文章详情

返回首页

CF搭建视频播放带密码登录

分享文章 作者: Ws01 创建时间: 2025-11-24 📝 字数: 18,925 字 👁️ 阅读: 20 次

原始 Markdown

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 randomLink = '';
    
    try {
        const videoList1 = await fetch('https://img.boke.us.to/config/9527qita/video-list.txt');
        const videoList2 = await fetch('https://img.boke.us.to/config/9527qita/video-list.txt');
        
        const links1 = (await videoList1.text()).split('\n').filter(line => line.trim() !== '');
        const links2 = (await videoList2.text()).split('\n').filter(line => line.trim() !== '');

        // 合并两个文件的内容
        links = [...links1, ...links2];

        // 检查文件是否为空
        if (links.length === 0) {
            return new Response('链接文件为空或未找到!', { 
                status: 500,
                headers: { 'Content-Type': 'text/html;charset=utf-8' }
            });
        }

        // 默认选择第一个链接
        randomLink = links[0];
    } catch (error) {
        // 如果获取视频列表失败,使用默认视频
        console.error('获取视频列表失败:', error);
        links = ['https://sample-videos.com/zip/10/mp4/SampleVideo_1280x720_1mb.mp4|测试视频'];
        randomLink = links[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 {
              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 {
              background-color: #333;
          }
  
          .sites {
              width: 640px;
              background: #F2F2F2;
              border: 1px solid rgba(0,0,0,.01);
              margin: 15px auto;
              padding: 0;
          }
  
          /* 居中对齐容器 */
          .video-container {
              display: flex;
              justify-content: center;
              align-items: center;
              margin: -0cm 0 0 0;
          }
          
          /* 标题下移 */
          h2 {
              text-align: center;
              margin-bottom: 1cm;
          }
          
          /* 播放列表样式 */
          .playlist {
              list-style-type: none;
              padding: 0;
              margin: 10px 0 0 0;
              width:638px;
              max-height: 162px;
              overflow-y: auto;
              text-align: left;
              border: 1px solid #ccc;
              background-color: #F2F2F2;
          }
          
          .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: 10px 0;">
      <!-- 新增:播放列表按钮 -->
      <button id="togglePlaylistBtn">播放列表</button>
      <button id="playPauseBtn">▶</button>
      <button id="prevBtn">&#10074;&#9664;</button>
      <button id="nextBtn">&#9654;&#10074;</button>
  </div>
  
  <div class="sites">
  <ul class="playlist" id="playlist" style="display: none;">
  ${links.map((link, index) => {
      const [url, title] = link.split('|');
      return `<li data-src="${url}">${index + 1}. ${title}</li>`;
  }).join('')}
  </ul>
  </div>
  
  <script>
  // 将视频链接列表转换为 JavaScript 数组
  const videoLinks = ${JSON.stringify(links)};
  
  // 选择视频元素
  const videoPlayer = document.getElementById('videoPlayer');
  
  // 新增按钮功能
  const playPauseBtn = document.getElementById('playPauseBtn');
  const prevBtn = document.getElementById('prevBtn');
  const nextBtn = document.getElementById('nextBtn');
  
  // 默认从第一个视频开始播放,并在页面加载时播放
  let currentVideoIndex = 0;
  
  // 页面加载时自动播放第一个视频
  document.addEventListener('DOMContentLoaded', () => {
      playVideo(currentVideoIndex);
      // 新增:为当前播放的列表项添加 playing 类
      updatePlaylistStyle(currentVideoIndex);
  });
  
  // 新增:更新播放列表样式的函数
  function updatePlaylistStyle(index) {
      const playlistItems = document.querySelectorAll('#playlist li');
      playlistItems.forEach((item, i) => {
          if (i === index) {
              item.classList.add('playing');
          } else {
              item.classList.remove('playing');
          }
      });
  }
  
  // 播放视频时更新样式
  function playVideo(index) {
      const [url] = videoLinks[index].split('|');
      videoPlayer.src = url;
      videoPlayer.play();
      // 更新播放列表样式
      updatePlaylistStyle(index);
  }
  
  // 播放/暂停按钮功能
  playPauseBtn.addEventListener('click', () => {
      if (videoPlayer.paused) {
          videoPlayer.play();
          playPauseBtn.textContent = '⏸';
      } else {
          videoPlayer.pause();
          playPauseBtn.textContent = '▶';
      }
  });
  
  // 上一首按钮功能
  prevBtn.addEventListener('click', () => {
      currentVideoIndex = (currentVideoIndex - 1 + videoLinks.length) % videoLinks.length;
      playVideo(currentVideoIndex);
  });
  
  // 下一首按钮功能
  nextBtn.addEventListener('click', () => {
      currentVideoIndex = (currentVideoIndex + 1) % videoLinks.length;
      playVideo(currentVideoIndex);
  });
  
  // 视频播放结束时,随机播放下一个视频
  videoPlayer.addEventListener('ended', () => {
      // 新增:随机选择未播放的视频
      const unplayedVideos = videoLinks.filter((_, index) => !playedIndexes.includes(index));
      if (unplayedVideos.length === 0) {
          // 如果所有视频都已播放过,重置记录
          playedIndexes = [];
          currentVideoIndex = Math.floor(Math.random() * videoLinks.length);
      } else {
          // 随机选择一个未播放的视频
          const randomIndex = Math.floor(Math.random() * unplayedVideos.length);
          currentVideoIndex = videoLinks.indexOf(unplayedVideos[randomIndex]);
      }
      playVideo(currentVideoIndex);
      playedIndexes.push(currentVideoIndex);
  });
  
  // 新增:用于记录已播放视频的索引
  let playedIndexes = [];
  
  // 新增:播放列表按钮功能
  const togglePlaylistBtn = document.getElementById('togglePlaylistBtn');
  const playlist = document.getElementById('playlist');
  
  togglePlaylistBtn.addEventListener('click', () => {
      if (playlist.style.display === 'none') {
          playlist.style.display = 'block';
          togglePlaylistBtn.textContent = '隐藏列表';
      } else {
          playlist.style.display = 'none';
          togglePlaylistBtn.textContent = '播放列表';
      }
  });
  
  // 点击播放列表中的链接后播放选择的视频
  document.getElementById('playlist').addEventListener('click', function(event) {
      if (event.target.tagName === 'LI') {
          const selectedUrl = event.target.getAttribute('data-src');
          videoPlayer.src = selectedUrl;
          videoPlayer.play();
          // 更新当前视频索引
          currentVideoIndex = videoLinks.findIndex(link => link.split('|')[0] === selectedUrl);
          // 更新播放列表样式
          updatePlaylistStyle(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>`;
    },
};

预览

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 randomLink = '';

try { const videoList1 = await fetch('https://img.boke.us.to/config/9527qita/video-list.txt'); const videoList2 = await fetch('https://img.boke.us.to/config/9527qita/video-list.txt');

const links1 = (await videoList1.text()).split('\n').filter(line => line.trim() !== ''); const links2 = (await videoList2.text()).split('\n').filter(line => line.trim() !== '');

// 合并两个文件的内容 links = [...links1, ...links2];

// 检查文件是否为空 if (links.length === 0) { return new Response('链接文件为空或未找到!', { status: 500, headers: { 'Content-Type': 'text/html;charset=utf-8' } }); }

// 默认选择第一个链接 randomLink = links[0]; } catch (error) { // 如果获取视频列表失败,使用默认视频 console.error('获取视频列表失败:', error); links = ['https://sample-videos.com/zip/10/mp4/SampleVideo1280x7201mb.mp4|测试视频']; randomLink = links[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 { 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 { background-color: #333; }

.sites { width: 640px; background: #F2F2F2; border: 1px solid rgba(0,0,0,.01); margin: 15px auto; padding: 0; }

/ 居中对齐容器 / .video-container { display: flex; justify-content: center; align-items: center; margin: -0cm 0 0 0; }

/ 标题下移 / h2 { text-align: center; margin-bottom: 1cm; }

/ 播放列表样式 / .playlist { list-style-type: none; padding: 0; margin: 10px 0 0 0; width:638px; max-height: 162px; overflow-y: auto; text-align: left; border: 1px solid #ccc; background-color: #F2F2F2; }

.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: 10px 0;"> <!-- 新增:播放列表按钮 --> <button id="togglePlaylistBtn">播放列表</button> <button id="playPauseBtn">▶</button> <button id="prevBtn">&#10074;&#9664;</button> <button id="nextBtn">&#9654;&#10074;</button> </div>

<div class="sites"> <ul class="playlist" id="playlist" style="display: none;"> ${links.map((link, index) => { const [url, title] = link.split('|'); return <li data-src="${url}">${index + 1}. ${title}</li>; }).join('')} </ul> </div>

<script> // 将视频链接列表转换为 JavaScript 数组 const videoLinks = ${JSON.stringify(links)};

// 选择视频元素 const videoPlayer = document.getElementById('videoPlayer');

// 新增按钮功能 const playPauseBtn = document.getElementById('playPauseBtn'); const prevBtn = document.getElementById('prevBtn'); const nextBtn = document.getElementById('nextBtn');

// 默认从第一个视频开始播放,并在页面加载时播放 let currentVideoIndex = 0;

// 页面加载时自动播放第一个视频 document.addEventListener('DOMContentLoaded', () => { playVideo(currentVideoIndex); // 新增:为当前播放的列表项添加 playing 类 updatePlaylistStyle(currentVideoIndex); });

// 新增:更新播放列表样式的函数 function updatePlaylistStyle(index) { const playlistItems = document.querySelectorAll('#playlist li'); playlistItems.forEach((item, i) => { if (i === index) { item.classList.add('playing'); } else { item.classList.remove('playing'); } }); }

// 播放视频时更新样式 function playVideo(index) { const [url] = videoLinks[index].split('|'); videoPlayer.src = url; videoPlayer.play(); // 更新播放列表样式 updatePlaylistStyle(index); }

// 播放/暂停按钮功能 playPauseBtn.addEventListener('click', () => { if (videoPlayer.paused) { videoPlayer.play(); playPauseBtn.textContent = '⏸'; } else { videoPlayer.pause(); playPauseBtn.textContent = '▶'; } });

// 上一首按钮功能 prevBtn.addEventListener('click', () => { currentVideoIndex = (currentVideoIndex - 1 + videoLinks.length) % videoLinks.length; playVideo(currentVideoIndex); });

// 下一首按钮功能 nextBtn.addEventListener('click', () => { currentVideoIndex = (currentVideoIndex + 1) % videoLinks.length; playVideo(currentVideoIndex); });

// 视频播放结束时,随机播放下一个视频 videoPlayer.addEventListener('ended', () => { // 新增:随机选择未播放的视频 const unplayedVideos = videoLinks.filter((_, index) => !playedIndexes.includes(index)); if (unplayedVideos.length === 0) { // 如果所有视频都已播放过,重置记录 playedIndexes = []; currentVideoIndex = Math.floor(Math.random() * videoLinks.length); } else { // 随机选择一个未播放的视频 const randomIndex = Math.floor(Math.random() * unplayedVideos.length); currentVideoIndex = videoLinks.indexOf(unplayedVideos[randomIndex]); } playVideo(currentVideoIndex); playedIndexes.push(currentVideoIndex); });

// 新增:用于记录已播放视频的索引 let playedIndexes = [];

// 新增:播放列表按钮功能 const togglePlaylistBtn = document.getElementById('togglePlaylistBtn'); const playlist = document.getElementById('playlist');

togglePlaylistBtn.addEventListener('click', () => { if (playlist.style.display === 'none') { playlist.style.display = 'block'; togglePlaylistBtn.textContent = '隐藏列表'; } else { playlist.style.display = 'none'; togglePlaylistBtn.textContent = '播放列表'; } });

// 点击播放列表中的链接后播放选择的视频 document.getElementById('playlist').addEventListener('click', function(event) { if (event.target.tagName === 'LI') { const selectedUrl = event.target.getAttribute('data-src'); videoPlayer.src = selectedUrl; videoPlayer.play(); // 更新当前视频索引 currentVideoIndex = videoLinks.findIndex(link => link.split('|')[0] === selectedUrl); // 更新播放列表样式 updatePlaylistStyle(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>; }, };