效果预览
本来是做着玩的,写篇文章记录一下
主要配置文件
也是静态网站
结构
video.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>金将军!忠诚!</title>
<!-- 添加网站图标 favicon -->
<link rel="icon" type="image/jpeg" href="https://pic.wtr.cc/i/2024/11/19/673ca4cca2756.jpeg">
<link rel="shortcut icon" type="image/jpeg" href="https://pic.wtr.cc/i/2024/11/19/673ca4cca2756.jpeg">
<!-- Plyr CSS -->
<link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" />
<style>
/* 在:root中更新主题色变量 */
:root {
--primary-color: #ffffff;
/* 改为白色,不再使用YouTube红色 */
--youtube-red: #cc0000;
/* 更深的YouTube红色 */
--youtube-red-hover: #990000;
/* 更深的悬停红色 */
--text-color: #ffffff;
--border-color: #303030;
--hover-color: #2c2c2c;
/* 改为实色而不是半透明 */
--shadow-color: rgba(0, 0, 0, 0.3);
--background-color: #0f0f0f;
/* YouTube模式背景色 */
--surface-color: #212121;
/* YouTube卡片背景色 */
--secondary-text: #aaaaaa;
--progress-color: #ffffff;
/* 进度条使用白色 */
}
/* 修改body背景 */
body {
margin: 0;
padding: 0;
min-height: 100vh;
background: var(--background-color);
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.main-container {
width: 95vw;
max-width: 1600px;
height: 98vh;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
}
.video-container {
width: 100%;
height: 100%;
background: var(--background-color) !important;
border: none;
border-radius: 0;
/* YouTube风格扁平化 */
box-shadow: none;
position: relative;
/* 确保定位正确 */
display: flex;
flex-direction: column;
padding: 15px;
gap: 8px;
box-sizing: border-box;
overflow: hidden;
}
.video-container::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
background-image:
linear-gradient(rgba(255, 255, 255, 0.15) 1.5px, transparent 1.5px),
linear-gradient(90deg, rgba(255, 255, 255, 0.15) 1.5px, transparent 1.5px);
background-size: 40px 40px;
/* 添加以下属性来调整网格位置 */
background-position: center center;
z-index: 0;
}
.video-container>* {
position: relative;
z-index: 1;
}
/* 修改网站图标和标题样式 */
h1 {
font-family: "YouTube Sans", "Roboto", sans-serif;
font-size: 1.4em !important;
color: var(--text-color);
padding: 8px 0;
margin: 0;
text-align: center;
font-weight: 600;
text-shadow: none;
letter-spacing: 0.5px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
/* 修改图标大小和间距 */
.site-icon {
width: 55px !important;
height: 55px !important;
margin-right: 25px !important;
/* ��除 border-radius */
vertical-align: middle;
animation: shake 2s ease-in-out infinite;
}
@keyframes shake {
0%,
100% {
transform: rotate(0deg);
}
25% {
transform: rotate(-10deg);
}
75% {
transform: rotate(10deg);
}
}
/* 移动备适配 */
@media screen and (max-width: 768px) {
h1 {
font-size: 1em !important;
}
.site-icon {
width: 16px !important;
height: 16px !important;
margin-right: 8px !important;
/* 不需要 border-radius */
}
}
/* 修改字幕样式的实现方式 */
.plyr__captions {
font-size: var(--subtitle-size, 20px) !important;
font-weight: var(--subtitle-weight, 500) !important;
bottom: var(--subtitle-bottom, 60px) !important;
}
.plyr__caption {
background: var(--subtitle-bg-color, rgba(0, 0, 0, 0.7)) !important;
padding: 5px 10px !important;
border-radius: 4px !important;
text-shadow: none !important;
max-width: 90% !important;
margin: 0 auto !important;
}
/* 移除原来的字幕设置面板样式 */
.subtitle-settings {
display: none;
}
/* 新增字幕控制面板样式 */
.subtitle-controls-panel {
width: 95%;
margin: 5px auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
padding: 15px;
background: var(--surface-color) !important;
border-radius: 2px;
padding: 16px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
border: none !important;
}
.subtitle-control {
margin: 0;
padding: 8px;
background: transparent !important;
border: none;
border-radius: 8px;
}
.subtitle-control label {
display: block;
margin-bottom: 8px;
color: var(--text-color);
font-weight: 500;
}
.control-group {
display: flex;
align-items: center;
gap: 10px;
background: var(--background-color) !important;
padding: 8px;
border-radius: 6px;
border: none !important;
}
.subtitle-control input[type="range"] {
flex: 1;
height: 4px;
background: rgba(255, 255, 255, 0.1) !important;
border-radius: 2px;
appearance: none;
-webkit-appearance: none;
}
.subtitle-control input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
background: var(--primary-color) !important;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 2px 4px rgba(33, 150, 243, 0.3);
}
.subtitle-control span {
min-width: 45px;
text-align: right;
color: var(--secondary-text);
font-size: 0.9em;
}
/* 滚动条美化 */
.video-list::-webkit-scrollbar {
height: 6px;
}
.video-list::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.video-list::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
.video-list::-webkit-scrollbar-thumb:hover {
background: #999;
}
/* 确保播放器控件样式统一 */
.plyr__controls {
display: flex !important;
flex-wrap: nowrap !important;
align-items: center !important;
gap: 8px !important;
padding: 15px !important;
min-height: 80px !important;
width: 100% !important;
background: rgba(0, 0, 0, 0) !important;
/* 完全透明 */
}
/* 移除之可能存在的渐变和模糊效果 */
.plyr__controls {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
background-image: none !important;
}
/* 调整控制按钮样式以确保在透明背景上可见 */
.plyr__control {
background: rgba(255, 255, 255, 0.1) !important;
border-radius: 10px !important;
transition: all 0.15s ease-out !important;
}
.plyr__control:hover {
background: rgba(255, 255, 255, 0.1) !important;
}
/* 调整进度条样式以确保在透明背景上可见 */
.plyr__progress input[type='range'] {
height: 6px !important;
background: rgba(255, 255, 255, 0.3) !important;
/* 增加进度条背景不透明度 */
}
/* 调整音量控制样式 */
.plyr__volume input[type='range'] {
height: 6px !important;
background: rgba(255, 255, 255, 0.3) !important;
}
/* 式布局调整 */
@media (max-width: 768px) {
.subtitle-controls-panel {
grid-template-columns: 1fr;
}
.video-container {
padding: 10px;
}
}
/* 确保播放器容器是相对定位 */
.player-wrapper {
flex: 1;
width: 95%;
margin: 0 auto;
/* 移除上边距 */
display: flex;
justify-content: center;
align-items: center;
background: #000;
border-radius: 8px;
overflow: hidden;
position: relative;
min-height: 80vh;
aspect-ratio: 16/9;
}
/* 确保视频填充容器 */
.plyr {
width: 100% !important;
height: 100% !important;
max-height: calc(100vh - 200px) !important;
--plyr-control-spacing: 15px !important;
--plyr-control-icon-size: 32px !important;
--plyr-progress-loading-size: 50px !important;
}
/* 移除原有的视频列表样式 */
.video-list {
display: none;
}
/* 下拉菜单容器 */
.video-select-container {
width: 95%;
margin: 5px auto 0 auto;
/* 移除下边距 */
position: relative;
background: transparent !important;
border-radius: 8px;
padding: 0;
min-height: auto;
display: flex;
align-items: center;
}
/* 修改下拉菜单样式,确保按钮本身的大小合适 */
.video-select {
width: 100%;
padding: 12px 40px 12px 15px !important;
font-size: 16px;
color: var(--text-color);
border: 1px solid var(--text-color) !important;
border-radius: 8px;
cursor: pointer;
height: 48px;
/* 添加固定高度 */
line-height: 24px;
/* 确保文字垂直居中 */
}
/* 修改下拉箭头样式 */
.video-select-container::after {
content: "";
position: absolute;
right: 25px;
top: 50%;
width: 8px;
height: 8px;
border-right: 2px solid var(--text-color);
border-bottom: 2px solid var(--text-color);
transform: translateY(-50%) rotate(45deg);
pointer-events: none;
z-index: 2;
transition: transform 0.3s ease;
}
/* 下拉菜单展开时箭头旋转 */
.video-select:focus::after {
transform: translateY(-50%) rotate(-135deg);
}
/* 调整下拉菜单样式 */
.video-select {
width: 100%;
padding: 12px 40px 12px 15px !important;
font-size: 16px;
color: var(--text-color);
border: 1px solid var(--text-color) !important;
border-radius: 8px;
cursor: pointer;
/* 添加以下属性来防止抖动 */
height: 48px;
/* 固定高度 */
line-height: 24px;
/* 确保文字垂直居中 */
appearance: none !important;
-webkit-appearance: none !important;
-moz-appearance: none !important;
background-color: #000000 !important;
background: #000000 !important;
transition: border-color 0.2s ease !important;
/* 只添边框颜色过渡效果 */
/* 保��头图标 */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23ffffff' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
background-size: 20px !important;
background-blend-mode: normal !important;
}
/* 下拉菜单基础样式 */
select.video-select {
width: 100%;
padding: 12px 15px;
font-size: 16px;
color: var(--text-color);
background-color: var(--surface-color);
border: 1px solid var(--border-color);
border-radius: 8px;
cursor: pointer;
display: block;
position: relative;
/* 完全禁用默认样式和箭头 */
appearance: none !important;
-moz-appearance: none !important;
-webkit-appearance: none !important;
/* 移除所有背景相关属性 */
background-image: none !important;
background: var(--surface-color) !important;
}
/* 禁用IE的默认箭头 */
select.video-select::-ms-expand {
display: none !important;
}
/* 选项样式 */
select.video-select option {
padding: 12px;
height: 48px;
/* 固定选项高度 */
line-height: 24px;
/* 确保文字垂直居中 */
background-color: var(--background-color);
color: var(--text-color);
}
/* 悬停状态 */
select.video-select:hover {
background-color: var(--hover-color) !important;
border-color: var(--primary-color);
}
/* 禁用所有可能的背景图 */
select.video-select,
select.video-select:hover,
select.video-select:focus,
select.video-select:active {
background-image: none !important;
}
/* 悬停状态 */
.video-select:hover {
background: var(--hover-color) !important;
border-color: var(--primary-color);
}
/* 选项样式 */
.video-select option {
background: var(--background-color);
color: var(--text-color);
padding: 12px;
}
/* 修改下拉菜单容器样式 */
.video-select-container {
width: 95%;
margin: 5px auto;
position: relative;
background: transparent !important;
border-radius: 8px;
padding: 10px;
}
/* 改放器容器式保齐 */
.player-wrapper {
width: 95%;
/* 确保与视频列表宽度一致 */
margin: 2px auto;
/* 将上边距从 5px 改为 2px */
/* 居中对齐 */
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background: #000;
border-radius: 8px;
overflow: hidden;
position: relative;
}
/* 修改幕控面板保持一致 */
.subtitle-controls-panel {
width: 95%;
/* 与其他元素保持一致 */
margin: 5px auto;
/* 居中对齐 */
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
padding: 15px;
background: transparent !important;
border-radius: 8px;
border: none !important;
box-shadow: none !important;
}
/* 美化主容器 */
.main-container {
width: 95vw;
max-width: 1600px;
height: 98vh;
margin: 0 auto;
}
/* 美化视频容器 */
.video-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* 美化标题 */
h1 {
color: var(--text-color);
font-size: 1.8em;
font-weight: 600;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
letter-spacing: 0.5px;
}
/* 美化下拉菜单 */
.video-select {
background: var(--surface-color) !important;
color: var(--text-color) !important;
border: 1px solid var(--border-color) !important;
border-radius: 12px;
padding: 14px 20px;
font-size: 16px;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.video-select:hover {
background: #e0e0e0 !important;
border-color: #2196F3;
outline: none;
}
/* 美化播放器容器 */
.player-wrapper {
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
/* 美化播放器控制栏 */
.plyr__controls {
background: linear-gradient(to top, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.5)) !important;
padding: 20px !important;
backdrop-filter: blur(8px);
}
.plyr__control {
background: rgba(255, 255, 255, 0.1) !important;
border-radius: 10px !important;
transition: all 0.15s ease-out !important;
}
.plyr__control:hover {
background: rgba(255, 255, 255, 0.1) !important;
}
/* 美化进度条 */
.plyr__progress input[type='range'] {
height: 6px !important;
background: rgba(255, 255, 255, 0.2) !important;
}
.plyr__progress__buffer {
background: rgba(255, 255, 255, 0.3) !important;
}
.plyr--full-ui input[type='range'] {
color: var(--text-color) !important;
}
/* 美化音量控制 */
.plyr__volume input[type='range'] {
height: 6px !important;
}
/* 美化字幕控制面板 */
.subtitle-controls-panel {
background: var(--surface-color);
border-radius: 16px;
padding: 20px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
border: 1px solid var(--border-color);
}
.subtitle-control {
background: white;
padding: 15px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.subtitle-control label {
color: var(--text-color);
font-weight: 600;
font-size: 0.95em;
margin-bottom: 12px;
}
.control-group {
background: var(--background-color);
padding: 12px;
border-radius: 10px;
border: 1px solid var(--border-color);
}
/* 美化滑块 */
input[type="range"] {
height: 6px !important;
background: #e0e0e0;
border-radius: 3px;
}
input[type="range"]::-webkit-slider-thumb {
width: 18px !important;
height: 18px !important;
background: var(--primary-color) !important;
border: 2px solid white;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
transition: all 0.2s ease;
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.1);
}
/* 添加平滑过渡果 */
.plyr__control,
.video-select,
.subtitle-control,
input[type="range"] {
transition: all 0.2s ease-in-out;
}
/* 美具提示 */
.plyr__tooltip {
background: rgba(0, 0, 0, 0.9) !important;
border-radius: 8px !important;
font-size: 14px !important;
padding: 8px 12px !important;
backdrop-filter: blur(4px);
}
/* 添加响应式悬停效果 */
.plyr__control:hover,
.video-select:hover,
.subtitle-control:hover {
transform: translateY(-2px);
}
/* 美化字幕样式 */
.plyr__captions {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.4) !important;
}
.plyr__caption {
background: rgba(0, 0, 0, 0.8) !important;
backdrop-filter: blur(4px);
border-radius: 8px !important;
padding: 8px 16px !important;
}
/* 添加网站图标 */
.site-icon {
width: 32px;
height: 32px;
margin-right: 10px;
border-radius: 50%;
vertical-align: middle;
}
/* 修改容器样式 */
.main-container {
width: 95vw;
max-width: 1600px;
height: 98vh;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
/* 修改视频容样式 */
.video-container {
width: 100%;
height: 100%;
background-color: #e0e0e0 !important;
/* 更深的背景色 */
background-image:
linear-gradient(#8f939b 1.5px, transparent 1.5px),
linear-gradient(90deg, #8f939b 1.5px, transparent 1.5px) !important;
background-size: 40px 40px;
border-radius: 12px;
border: 1px solid #8f939b;
/* 边框颜色与网格线一致 */
display: flex;
flex-direction: column;
padding: 15px;
gap: 8px;
box-sizing: border-box;
overflow: hidden;
box-shadow: none;
backdrop-filter: none !important;
}
/* 调整标题样式 */
h1 {
margin: 5px 0;
flex-shrink: 0;
}
/* 调整下拉菜单容器样式 */
.video-select-container {
margin: 5px auto;
flex-shrink: 0;
}
/* 调播放器容器样式 */
.player-wrapper {
flex: 1;
min-height: 0;
margin: 0 auto;
/* 移除上边距 */
}
/* 调整字幕控面板样 */
.subtitle-controls-panel {
width: 95%;
margin: 5px auto;
padding: 10px;
flex-shrink: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
/* 调整幕控制项样式 */
.subtitle-control {
margin: 0;
padding: 8px;
}
.control-group {
padding: 8px;
}
/* 确保所有内容都在容器内 */
.video-container>* {
max-height: 100%;
}
/* 移除大播放按钮的动画效果 */
.plyr__control--overlaid {
transition: none !important;
/* 移除所有过渡效果 */
transform: none !important;
/* 移除变形效果 */
animation: none !important;
/* 移除所有动画 */
}
.plyr__control--overlaid:hover {
transform: none !important;
/* 移除悬停时的变形效果 */
background: rgba(255, 255, 255, 0.8) !important;
/* 简单的背景色变化 */
}
/* 调整大播放按钮的位置和样式 */
.plyr__control--overlaid {
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
/* 使用 transform 来居中 */
background: rgba(255, 255, 255, 0.7) !important;
border: 0 !important;
border-radius: 50% !important;
padding: 25px !important;
margin: 0 !important;
z-index: 2 !important;
opacity: 0;
/* 默认隐藏 */
pointer-events: none;
/* 禁用鼠标事件 */
visibility: hidden;
/* 完全隐藏 */
}
/* 视频暂停时显示按钮 */
.plyr--paused .plyr__control--overlaid {
opacity: 1;
pointer-events: auto;
visibility: visible;
}
/* 移除所有动画效果 */
.plyr__control--overlaid,
.plyr--paused .plyr__control--overlaid,
.plyr__control--overlaid:hover {
transition: opacity 0.1s linear !important;
/* 只保留透明度的过渡 */
transform: translate(-50%, -50%) !important;
/* 保持固定位置 */
animation: none !important;
}
/* 简化悬停效果 */
.plyr__control--overlaid:hover {
background: rgba(255, 255, 255, 0.8) !important;
}
/* 确保按钮图标居中且大小固定 */
.plyr__control--overlaid svg {
width: 30px !important;
height: 30px !important;
margin: 0 !important;
padding: 0 !important;
display: block !important;
}
/* 调整播放器容器样式确保按钮定位正确 */
.player-wrapper {
position: relative !important;
}
.plyr {
position: relative !important;
}
/* 调整进度条和音量控制滑块样式 */
.plyr__progress input[type='range'],
.plyr__volume input[type='range'] {
height: 6px !important;
/* 减小滑块高度 */
background: rgba(255, 255, 255, 0.2) !important;
position: relative !important;
}
/* 调整滑块圆点样式 */
.plyr__progress input[type='range']::-webkit-slider-thumb,
.plyr__volume input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none !important;
width: 16px !important;
height: 16px !important;
background: #fff !important;
border-radius: 50% !important;
cursor: pointer !important;
position: relative !important;
top: 50% !important;
transform: translateY(-50%) !important;
/* 垂直居中 */
margin-top: 0 !important;
/* 移除默认边 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) !important;
}
/* Firefox 滑块样式 */
.plyr__progress input[type='range']::-moz-range-thumb,
.plyr__volume input[type='range']::-moz-range-thumb {
width: 16px !important;
height: 16px !important;
background: #fff !important;
border-radius: 50% !important;
cursor: pointer !important;
border: none !important;
position: relative !important;
transform: translateY(0) !important;
/* Firefox 不需要 Y 轴偏移 */
margin-top: 0 !important;
}
/* 滑块轨道样式 */
.plyr__progress input[type='range']::-webkit-slider-runnable-track,
.plyr__volume input[type='range']::-webkit-slider-runnable-track {
height: 6px !important;
background: rgba(255, 255, 255, 0.2) !important;
border-radius: 3px !important;
}
/* Firefox 轨道样 */
.plyr__progress input[type='range']::-moz-range-track,
.plyr__volume input[type='range']::-moz-range-track {
height: 6px !important;
background: rgba(255, 255, 255, 0.2) !important;
border-radius: 3px !important;
}
/* 调整音量控区域样式 */
.plyr__volume {
max-width: 150px !important;
/* 加最大宽度 */
min-width: 120px !important;
/* 增加最小宽度 */
margin: 0 10px !important;
}
/* 调整量滑块样式 */
.plyr__volume input[type='range'] {
width: 100% !important;
min-width: 100px !important;
/* 增加块最小宽度 */
height: 6px !important;
margin: 0 !important;
background: rgba(255, 255, 255, 0.3) !important;
}
/* 确保音量控制在控栏中的位置正确 */
.plyr__controls {
gap: 12px !important;
/* 增加控件之间的间距 */
}
/* 调整音量图标和滑块的间距 */
.plyr__volume button {
margin-right: 8px !important;
}
/* 调整设置按钮大小和样式 */
.plyr__menu__container {
font-size: 16px !important;
/* 减小字体大小 */
padding: 8px !important;
/* 减小内边距 */
}
.plyr__menu__container .plyr__control {
padding: 8px 12px !important;
/* 小内边距 */
font-size: 14px !important;
/* 减小字体大小 */
}
/* 调整设置按钮图标大小 */
.plyr__controls button[data-plyr="settings"] svg {
width: 18px !important;
/* 小图标大小 */
height: 18px !important;
}
/* 确保所有控制按钮图标大小一致 */
.plyr__controls .plyr__control svg {
width: 18px !important;
height: 18px !important;
}
/* 调整菜单项的样式 */
.plyr__menu__container .plyr__menu__value {
font-size: 14px !important;
padding: 6px !important;
}
/* 调设置菜单容器样式 */
.plyr__menu__container {
font-size: 14px !important;
padding: 8px !important;
min-width: 240px !important;
/* 增加菜单宽度 */
text-align: center !important;
}
/* 调菜布局 */
.plyr__menu__container .plyr__control {
display: flex !important;
align-items: center !important;
justify-content: center !important;
padding: 10px 16px !important;
/* 增加内距 */
width: 100% !important;
box-sizing: border-box !important;
position: relative !important;
}
/* 调整菜单项文本布局 */
.plyr__menu__container .plyr__control span {
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
text-align: center !important;
}
/* 移除子菜单指示角 */
.plyr__menu__container [role="menuitem"][aria-haspopup="true"]>span:after {
display: none !important;
}
/* 调整子菜单容器 */
.plyr__menu__container .plyr__menu__submenu {
min-width: 200px !important;
/* 增加子菜单宽度 */
padding: 8px !important;
background: rgba(28, 28, 28, 0.9) !important;
}
/* 调整子菜单项样式 */
.plyr__menu__container .plyr__menu__submenu .plyr__control {
padding: 10px 16px !important;
/* 保持一致的内边距 */
}
/* 调整菜单值的样式 */
.plyr__menu__container .plyr__menu__value {
margin-left: 12px !important;
/* 增加左边距 */
opacity: 0.8 !important;
}
/* 添加移动设备响应式样 */
@media screen and (max-width: 768px) {
/* 调整主容器 */
.main-container {
width: 100vw;
height: 100vh;
padding: 0;
}
/* 调整视容器 */
.video-container {
border-radius: 0;
/* 移除圆角 */
padding: 10px 5px;
}
/* 调整标题 */
h1 {
font-size: 1.2em;
margin: 5px 0;
}
.site-icon {
width: 24px;
height: 24px;
margin-right: 5px;
}
/* 调整下拉菜单 */
.video-select {
padding: 8px 12px;
font-size: 14px;
}
/* 调整播放器容器 */
.player-wrapper {
width: 100%;
min-height: 50vh;
}
/* 调整字控制面板 */
.subtitle-controls-panel {
grid-template-columns: 1fr;
/* 改为单列布局 */
gap: 8px;
padding: 8px;
width: 100%;
}
.subtitle-control {
padding: 8px;
}
.subtitle-control label {
font-size: 0.9em;
}
/* 调整播放器控制栏 */
.plyr__controls {
padding: 8px !important;
min-height: 40px !important;
}
/* 调整控制按钮大小 */
.plyr__control {
padding: 8px !important;
}
/* 调整时间显示 */
.plyr__time {
font-size: 12px !important;
min-width: 45px !important;
}
/* 调整音量控制 */
.plyr__volume {
max-width: 80px !important;
min-width: 60px !important;
}
/* 调整进度条 */
.plyr__progress input[type='range'] {
height: 4px !important;
}
/* 调整字幕大小 */
.plyr__captions {
font-size: 16px !important;
}
/* 优触摸操 */
.plyr__control,
.video-select,
input[type="range"] {
touch-action: manipulation;
}
/* ��整设置菜单 */
.plyr__menu__container {
font-size: 12px !important;
}
.plyr__menu__container .plyr__control {
padding: 6px 20px 6px 10px !important;
}
/* 确保控制栏在小屏幕上不会太拥挤 */
.plyr__controls {
gap: 4px !important;
}
/* 优化全屏模式 */
.plyr--fullscreen-enabled [data-plyr="fullscreen"] {
order: 10;
}
/* 调整工具提示 */
.plyr__tooltip {
font-size: 12px !important;
padding: 4px 8px !important;
}
/* 优化横屏模式 */
@media screen and (orientation: landscape) {
.player-wrapper {
min-height: 80vh;
}
.subtitle-controls-panel {
grid-template-columns: repeat(3, 1fr);
/* 横屏时恢复三列布局 */
}
}
}
/* 调整控制栏布局,确全屏按钮始终显示 */
.plyr__controls {
display: flex !important;
flex-wrap: nowrap !important;
align-items: center !important;
gap: 8px !important;
padding: 15px !important;
min-height: 80px !important;
width: 100% !important;
}
/* 设置全屏按钮样式 */
.plyr__controls [data-plyr="fullscreen"] {
flex: 0 0 auto !important;
/* 防止压缩 */
display: flex !important;
/* 始终显示 */
order: 999 !important;
/* 确保在最右侧 */
margin-left: auto !important;
/* 推到最右边 */
padding: 8px !important;
min-width: 36px !important;
/* 保最宽度 */
}
/* 移设备配时也保持全屏按钮显示 */
@media screen and (max-width: 768px) {
.plyr__controls [data-plyr="fullscreen"] {
display: flex !important;
min-width: 32px !important;
}
/* 在空间足时,可以隐藏其他次要控件,但全屏按钮 */
.plyr__controls [data-plyr="settings"],
.plyr__controls [data-plyr="pip"] {
display: none !important;
}
}
/* 超窄屏适配 */
@media screen and (max-width: 480px) {
.plyr__controls [data-plyr="fullscreen"] {
min-width: 28px !important;
padding: 6px !important;
}
/* 在极屏幕可以隐藏更多控件,仍保持全屏按钮 */
.plyr__time--duration {
display: none !important;
}
}
/* 修改控制组和相关元素背色 */
.control-group {
background: var(--background-color) !important;
border: 1px solid var(--border-color) !important;
color: var(--text-color) !important;
}
.subtitle-control label {
color: var(--text-color) !important;
}
.subtitle-control span {
color: var(--secondary-text) !important;
}
/* 修改下拉菜单样式 */
.video-select {
width: 100%;
padding: 12px 40px 12px 15px !important;
font-size: 16px;
color: var(--text-color);
border: 1px solid var(--text-color) !important;
border-radius: 8px;
cursor: pointer;
/* 移除所有默认样式 */
appearance: none !important;
-webkit-appearance: none !important;
-moz-appearance: none !important;
/* 强制使用纯黑背景 */
background-color: #000000 !important;
background: #000000 !important;
/* 保持箭头图标 */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23ffffff' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
background-size: 20px !important;
background-blend-mode: normal !important;
}
/* 悬停和焦点状态也保持白色边框 */
.video-select:hover,
.video-select:focus {
border: 1px solid var(--text-color) !important;
background-color: #000000 !important;
background: #000000 !important;
}
/* 删除之前的重复定义 */
.video-select,
.video-select:hover,
.video-select:focus,
.video-select:active {
background-color: #000000 !important;
background: #000000 !important;
}
/* 删除可能影响背景的其他样式 */
.video-select-container::after {
display: none !important;
}
/* 修改播放器背景 */
.player-wrapper {
background: var(--background-color) !important;
}
/* 确保所有文本色正确 */
.plyr__menu__container,
.plyr__menu__container .plyr__control,
.plyr__menu__container .plyr__menu__value {
color: var(--text-color) !important;
}
/* 添加加载遮罩样式 */
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--background-color);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
opacity: 1;
transition: opacity 0.3s ease;
}
.loading-overlay.hidden {
opacity: 0;
pointer-events: none;
}
.loading-spinner {
width: 50px;
height: 50px;
border: 5px solid var(--border-color);
border-top: 5px solid var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 修改视频容器样式 - 移除前的白色背景 */
.video-container {
background: var(--surface-color) !important;
border: 1px solid var(--border-color);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
/* 修字幕控制面板中的白背景 */
.subtitle-control {
background: var(--surface-color) !important;
border: 1px solid var(--border-color);
}
/* 修改下拉菜单的hover状态 */
.video-select:hover {
background-color: #000000 !important;
border-color: var(--primary-color);
}
/* 修改播放器菜单容器样式 */
.plyr__menu__container {
background: var(--surface-color) !important;
color: var(--text-color) !important;
}
.plyr__menu__container .plyr__control {
background: var(--surface-color) !important;
color: var(--text-color) !important;
}
.plyr__menu__container .plyr__control:hover {
background: #000000 !important;
}
/* 修改播放器设置菜单样式 */
.plyr__menu__container .plyr__menu__submenu {
background: var(--surface-color) !important;
border: 1px solid var(--border-color);
}
/* 修改时间显示文字颜色 */
.plyr__time {
color: var(--text-color) !important;
}
/* 修改进度条缓冲区颜色 */
.plyr--full-ui input[type=range]::-webkit-slider-runnable-track {
background: var(--surface-color) !important;
}
.plyr--full-ui input[type=range]::-webkit-slider-thumb {
background: var(--primary-color) !important;
}
/* 修改音量控制滑块 */
.plyr__volume input[type=range]::-webkit-slider-runnable-track {
background: var(--surface-color) !important;
}
.plyr__volume input[type=range]::-webkit-slider-thumb {
background: var(--primary-color) !important;
}
/* 修改具提示样式 */
.plyr__tooltip {
background: var(--surface-color) !important;
color: var(--text-color) !important;
border: 1px solid var(--border-color);
}
/* 修改字幕样式 */
.plyr__captions .plyr__caption {
color: var(--text-color) !important;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8) !important;
}
/* 修改下拉菜单箭头色 */
.video-select {
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ecf0f1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e") !important;
}
/* 修改滑块样式统一 */
input[type="range"] {
background: var(--surface-color) !important;
}
input[type="range"]::-webkit-slider-thumb {
background: var(--primary-color) !important;
border: 2px solid var(--text-color) !important;
}
/* 修改播放器控件颜色 */
.plyr__control svg {
fill: var(--text-color) !important;
}
/* 修改播放器大按钮样式 */
.plyr__control--overlaid {
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
background: rgba(33, 33, 33, 0.8) !important;
border-radius: 50% !important;
padding: 20px !important;
margin: 0 !important;
transition: background-color 0.2s ease !important;
width: 64px !important;
height: 64px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
.plyr__control--overlaid:hover {
background: rgba(255, 255, 255, 0.9) !important;
}
/* 修改播放按钮图标大小 */
.plyr__control--overlaid svg {
width: 32px !important;
height: 32px !important;
transition: fill 0.2s ease !important;
margin: 0 !important;
padding: 0 !important;
}
/* 悬停时改变图标颜色 */
.plyr__control--overlaid:hover svg {
fill: var(--background-color) !important;
}
/* 确保所有SVG图标颜色正确 */
svg {
fill: var(--text-color) !important;
}
/* 修改加载动画颜色 */
.loading-spinner {
border-color: var(--surface-color);
border-top-color: var(--primary-color);
}
/* 修改下拉菜单样式 */
.video-select {
width: 100%;
padding: 12px 40px 12px 15px !important;
font-size: 16px;
color: var(--text-color);
border: 1px solid var(--text-color) !important;
border-radius: 8px;
cursor: pointer;
/* 移除所有默认式 */
appearance: none !important;
-webkit-appearance: none !important;
-moz-appearance: none !important;
/* 强制使用纯黑背景 */
background-color: #000000 !important;
background: #000000 !important;
/* 保持箭头图标 */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23ffffff' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
background-size: 20px !important;
background-blend-mode: normal !important;
transition: all 0.3s ease !important;
}
/* 展开时的样式 */
.video-select:focus {
border-color: var(--primary-color);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23ecf0f1' d='M7 14l5-5 5 5z'/%3E%3C/svg%3E") !important;
}
/* 移除所有可能冲突的样式 */
.video-select-container::after {
display: none !important;
}
.video-select {
background: var(--surface-color) !important;
}
/* 确保背景图片显示 */
.video-select {
background-color: #000000 !important;
background-blend-mode: normal !important;
}
/* 修改所有播放制按钮的悬停效果 */
.plyr__control:hover {
background: var(--youtube-red) !important;
color: var(--text-color) !important;
}
/* 修改进度条和音量滑块的颜色 */
.plyr--full-ui input[type=range] {
color: var(--youtube-red) !important;
/* 使用YouTube红色 */
}
/* 修改进度条已播放部的颜色 */
.plyr--full-ui input[type=range]::-webkit-slider-runnable-track {
background: var(--surface-color) !important;
}
.plyr--full-ui input[type=range]::-webkit-slider-thumb {
background: var(--text-color) !important;
}
/* 保进度条已播放部分为红色 */
.plyr__progress input[type='range'] {
color: var(--youtube-red) !important;
background: linear-gradient(to right, var(--youtube-red) var(--value, 0%), rgba(255, 255, 255, 0.25) var(--value, 0%)) !important;
}
/* Firefox特定样式 */
.plyr__progress input[type='range']::-moz-range-progress {
background: var(--youtube-red) !important;
}
/* 修改音量控制为色 */
.plyr__volume input[type='range'] {
color: var(--youtube-red) !important;
}
/* 修改缓冲条颜色 */
.plyr__progress__buffer {
background-color: rgba(255, 255, 255, 0.25) !important;
}
/* 确保进度条背景色正确 */
.plyr--full-ui input[type=range]::-webkit-slider-runnable-track {
background-color: rgba(255, 255, 255, 0.25) !important;
}
/* 修改进度条悬停效果 */
.plyr__progress input[type='range']:hover {
color: var(--youtube-red-hover) !important;
}
/* 修改音量控制条样式 */
.plyr__volume input[type='range'] {
color: var(--youtube-red) !important;
}
/* 修改音量控制条已调节部分的颜色 */
.plyr__volume input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, var(--youtube-red) var(--value, 0%), rgba(255, 255, 255, 0.25) var(--value, 0%)) !important;
}
/* Firefox特定样 */
.plyr__volume input[type='range']::-moz-range-progress {
background: var(--youtube-red) !important;
}
.plyr__volume input[type='range']::-moz-range-track {
background: rgba(255, 255, 255, 0.25) !important;
}
/* 确保音量控制滑块为白色 */
.plyr__volume input[type='range']::-webkit-slider-thumb {
background: var(--text-color) !important;
border: none !important;
}
.plyr__volume input[type='range']::-moz-range-thumb {
background: var(--text-color) !important;
border: none !important;
}
/* 修改音量控制条背景色 */
.plyr__volume input[type='range'] {
background: rgba(255, 255, 255, 0.25) !important;
}
/* 修改字幕控制面板滑块样式 */
.subtitle-control input[type="range"] {
-webkit-appearance: none !important;
-moz-appearance: none !important;
appearance: none !important;
/* 添加标准属性以确保兼容性 */
width: 100% !important;
height: 6px !important;
background: rgba(255, 255, 255, 0.25) !important;
border-radius: 3px !important;
outline: none !important;
}
/* 修改滑块已调节部分的颜色 */
.subtitle-control input[type="range"]::-webkit-slider-runnable-track {
width: 100% !important;
height: 6px !important;
background: linear-gradient(to right, var(--youtube-red) var(--value, 0%), rgba(255, 255, 255, 0.25) var(--value, 0%)) !important;
border-radius: 3px !important;
}
/* 修改滑块圆点样 */
.subtitle-control input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none !important;
width: 16px !important;
height: 16px !important;
background: var(--text-color) !important;
border-radius: 50% !important;
cursor: pointer !important;
margin-top: -5px !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) !important;
}
/* Firefox特定样式 */
.subtitle-control input[type="range"]::-moz-range-track {
width: 100% !important;
height: 6px !important;
background: rgba(255, 255, 255, 0.25) !important;
border-radius: 3px !important;
}
.subtitle-control input[type="range"]::-moz-range-progress {
background: var(--youtube-red) !important;
height: 6px !important;
border-radius: 3px !important;
}
.subtitle-control input[type="range"]::-moz-range-thumb {
width: 16px !important;
height: 16px !important;
background: var(--text-color) !important;
border: none !important;
border-radius: 50% !important;
cursor: pointer !important;
}
/* 进度条悬停效果 */
.plyr__progress {
--plyr-progress-loading-background: rgba(255, 255, 255, 0.25) !important;
--plyr-progress-loading-size: 25px !important;
transition: height 0.2s ease !important;
}
/* 进度条容器悬停效果 */
.plyr__progress__container:hover .plyr__progress {
height: 10px !important;
/* 悬停时增加高度 */
}
/* 进度条滑块悬停效果 */
.plyr__progress input[type='range']:hover::-webkit-slider-thumb {
background: var(--youtube-red) !important;
transform: scale(1.2) !important;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) !important;
}
.plyr__progress input[type='range']:hover::-moz-range-thumb {
background: var(--youtube-red) !important;
transform: scale(1.2) !important;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) !important;
}
/* 进度条预览效果 */
.plyr__progress__buffer {
background: rgba(255, 255, 255, 0.25) !important;
transition: all 0.2s ease !important;
}
/* 进度条览悬停效果 */
.plyr__progress:hover .plyr__progress__buffer {
background: rgba(255, 255, 255, 0.35) !important;
}
/* 进度条已播放部分的悬停效果 */
.plyr__progress input[type='range']:hover {
background: linear-gradient(to right,
var(--youtube-red-hover) var(--value, 0%),
rgba(255, 255, 255, 0.35) var(--value, 0%)) !important;
}
/* 时间提示工具提示样式 */
.plyr__tooltip {
background: rgba(28, 28, 28, 0.9) !important;
color: var(--text-color) !important;
font-size: 14px !important;
padding: 6px 10px !important;
border-radius: 4px !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important;
transition: opacity 0.2s ease, transform 0.2s ease !important;
}
/* 时间提示工具提示悬停效果 */
.plyr__progress:hover .plyr__tooltip {
transform: translate(-50%, -10px) !important;
opacity: 1 !important;
}
/* 确保进度条块始终可见 */
.plyr__progress input[type='range']::-webkit-slider-thumb {
opacity: 0;
transition: opacity 0.2s ease, transform 0.2s ease, background-color 0.2s ease !important;
}
.plyr__progress:hover input[type='range']::-webkit-slider-thumb {
opacity: 1;
}
/* Firefox 版本 */
.plyr__progress input[type='range']::-moz-range-thumb {
opacity: 0;
transition: opacity 0.2s ease, transform 0.2s ease, background-color 0.2s ease !important;
}
.plyr__progress:hover input[type='range']::-moz-range-thumb {
opacity: 1;
}
/* 进度条加载动画 */
.plyr__progress__buffer {
background-size: var(--plyr-progress-loading-size) var(--plyr-progress-loading-size) !important;
animation: plyr-progress 1s linear infinite !important;
}
@keyframes plyr-progress {
to {
background-position: var(--plyr-progress-loading-size) 0;
}
}
/* 在:root中添加浅色主题变量 */
:root[data-theme="light"] {
--primary-color: #000000;
--youtube-red: #cc0000;
--youtube-red-hover: #990000;
--text-color: #000000;
--border-color: #e0e0e0;
--hover-color: #f5f5f5;
--shadow-color: rgba(0, 0, 0, 0.1);
--background-color: #ffffff;
--surface-color: #f8f8f8;
--secondary-text: #666666;
--progress-color: #000000;
}
/* 主题切换按钮样式 */
.theme-toggle {
position: fixed;
top: 20px;
right: 70px;
/* 调整右边距,让按钮往左移 */
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--surface-color);
border: 2px solid var(--border-color);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
transition: all 0.3s ease;
}
.theme-toggle:hover {
transform: scale(1.1);
background: var(--hover-color);
}
.theme-toggle svg {
width: 24px;
height: 24px;
fill: var(--text-color) !important;
transition: all 0.3s ease;
}
/* 移动设备适配 */
@media screen and (max-width: 768px) {
.theme-toggle {
top: 10px;
right: 50px;
/* 调整移动端右边距 */
width: 32px;
height: 32px;
}
.theme-toggle svg {
width: 18px;
height: 18px;
}
}
/* 完善浅色主题变量 */
:root[data-theme="light"] {
--primary-color: #000000;
--youtube-red: #cc0000;
--youtube-red-hover: #990000;
--text-color: #000000;
--border-color: #e0e0e0;
--hover-color: #f5f5f5;
--shadow-color: rgba(0, 0, 0, 0.1);
--background-color: #ffffff;
--surface-color: #f8f8f8;
--secondary-text: #666666;
--progress-color: #000000;
}
/* 确保播放器在浅色主题下的样式 */
:root[data-theme="light"] .video-container {
background-color: #ffffff !important;
background-image: linear-gradient(#e0e0e0 1.5px, transparent 1.5px),
linear-gradient(90deg, #e0e0e0 1.5px, transparent 1.5px) !important;
border-color: #e0e0e0;
}
:root[data-theme="light"] .plyr {
--plyr-color-main: var(--youtube-red);
--plyr-video-background: #ffffff;
}
:root[data-theme="light"] .plyr__controls {
background: rgba(255, 255, 255, 0.9) !important;
}
:root[data-theme="light"] .plyr__control {
color: #000000;
}
:root[data-theme="light"] .plyr__control svg {
fill: #000000 !important;
}
:root[data-theme="light"] .plyr__menu__container {
background: #ffffff;
color: #000000;
}
:root[data-theme="light"] .plyr__time {
color: #000000;
}
:root[data-theme="light"] .video-select {
background-color: #ffffff !important;
color: #000000;
border-color: #e0e0e0 !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000000' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") !important;
}
:root[data-theme="light"] .subtitle-control {
background: #ffffff;
}
:root[data-theme="light"] .subtitle-control label {
color: #000000;
}
:root[data-theme="light"] .control-group {
background: #f8f8f8;
border-color: #e0e0e0;
}
:root[data-theme="light"] input[type="range"] {
background: rgba(0, 0, 0, 0.1) !important;
}
:root[data-theme="light"] input[type="range"]::-webkit-slider-thumb {
background: var(--youtube-red) !important;
}
/* 修改下拉菜单样式 - 更新浅色主题下的样式 */
:root[data-theme="light"] .video-select {
background-color: #ffffff !important;
color: #000000;
border-color: #e0e0e0 !important;
/* 移除所有默认样式 */
appearance: none !important;
-webkit-appearance: none !important;
-moz-appearance: none !important;
/* 强制使用纯白背景 */
background: #ffffff !important;
/* 自定义箭头图标 - 使用黑色箭头 */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000000' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
background-size: 20px !important;
background-blend-mode: normal !important;
}
/* 展开时的样式 - 浅色主题 */
:root[data-theme="light"] .video-select:focus {
border-color: var(--youtube-red);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000000' d='M7 14l5-5 5 5z'/%3E%3C/svg%3E") !important;
}
/* 确保移除默认箭头 - 针对不同浏览器 */
:root[data-theme="light"] .video-select::-ms-expand {
display: none !important;
}
/* 悬停状态 - 浅色主题 */
:root[data-theme="light"] .video-select:hover {
background-color: #f5f5f5 !important;
border-color: var(--youtube-red) !important;
}
/* 选项样式 - 浅色主题 */
:root[data-theme="light"] .video-select option {
background: #ffffff;
color: #000000;
padding: 12px;
}
/* 在 :root[data-theme="light"] 下添加以下样式 */
:root[data-theme="light"] {
/* 保持有的浅主题变量... */
/* 修改字幕样式 */
--plyr-captions-background: rgba(255, 255, 255, 0.9) !important;
--plyr-captions-text-color: #000000 !important;
}
/* 浅色主题下的字幕样式 */
:root[data-theme="light"] .plyr__captions {
color: #000000 !important;
text-shadow: none !important;
}
:root[data-theme="light"] .plyr__caption {
background: rgba(255, 255, 255, 0.9) !important;
color: #000000 !important;
border: 1px solid rgba(0, 0, 0, 0.1) !important;
}
/* 浅色主题下的提示文字样式 */
:root[data-theme="light"] .plyr__tooltip {
background: rgba(255, 255, 255, 0.95) !important;
color: #000000 !important;
border: 1px solid rgba(0, 0, 0, 0.1) !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
}
/* 色主题下的菜单样式 */
:root[data-theme="light"] .plyr__menu__container {
background: #ffffff !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
}
:root[data-theme="light"] .plyr__menu__container .plyr__control {
color: #000000 !important;
}
:root[data-theme="light"] .plyr__menu__container .plyr__control--forward::after,
:root[data-theme="light"] .plyr__menu__container .plyr__control--back::before {
border-left-color: #000000 !important;
}
:root[data-theme="light"] .plyr__menu__container .plyr__control[role=menuitemradio]::before {
background: #000000 !important;
}
/* 浅色主题下的控制按钮提示 */
:root[data-theme="light"] .plyr__control:hover .plyr__tooltip {
background: #ffffff !important;
color: #000000 !important;
}
/* 浅色主题下的进度条预览提示 */
:root[data-theme="light"] .plyr__progress .plyr__tooltip {
background: #ffffff !important;
color: #000000 !important;
}
/* 浅色主题下的音量控制提示 */
:root[data-theme="light"] .plyr__volume .plyr__tooltip {
background: #ffffff !important;
color: #000000 !important;
}
/* 浅色主题下的时间显示 */
:root[data-theme="light"] .plyr__time {
color: #000000 !important;
}
/* 浅色主题下的加载动画 */
:root[data-theme="light"] .loading-spinner {
border-color: rgba(0, 0, 0, 0.1) !important;
border-top-color: var(--youtube-red) !important;
}
/* 浅色主题下的控制面板背景 */
:root[data-theme="light"] .plyr__controls {
background: linear-gradient(to top, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.8)) !important;
backdrop-filter: blur(10px) !important;
}
/* 浅色主题下的大播放按钮 */
:root[data-theme="light"] .plyr__control--overlaid {
background: rgba(255, 255, 255, 0.8) !important;
}
:root[data-theme="light"] .plyr__control--overlaid:hover {
background: var(--youtube-red) !important;
}
:root[data-theme="light"] .plyr__control--overlaid:hover svg {
fill: #ffffff !important;
}
/* 修改浅色主题下的网格样式 */
:root[data-theme="light"] .video-container {
background-color: #ffffff !important;
border: 1px solid #e0e0e0 !important;
}
:root[data-theme="light"] .video-container::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
background-image:
linear-gradient(rgba(0, 0, 0, 0.1) 1.5px, transparent 1.5px),
linear-gradient(90deg, rgba(0, 0, 0, 0.1) 1.5px, transparent 1.5px) !important;
background-size: 40px 40px;
/* 添加以下属性来调整网格位置 */
background-position: center center;
z-index: 0;
}
/* 确保深色主题下的网格样式不受影响 */
.video-container::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
background-image:
linear-gradient(rgba(255, 255, 255, 0.15) 1.5px, transparent 1.5px),
linear-gradient(90deg, rgba(255, 255, 255, 0.15) 1.5px, transparent 1.5px);
background-size: 40px 40px;
/* 添加以下属性来调整网格位置 */
background-position: center center;
z-index: 0;
}
/* 添加新按钮样式 */
.custom-controls {
display: flex;
align-items: center;
gap: 8px;
margin-left: 8px;
}
.custom-control {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 4px;
background: transparent;
border: none;
cursor: pointer;
color: var(--text-color);
transition: all 0.2s ease;
}
.custom-control:hover {
background: var(--youtube-red);
}
.custom-control svg {
width: 20px;
height: 20px;
fill: var(--text-color) !important;
}
.custom-control.active {
background: var(--youtube-red);
}
/* 浅色主题适配 */
:root[data-theme="light"] .custom-control svg {
fill: #000000 !important;
}
:root[data-theme="light"] .custom-control:hover svg,
:root[data-theme="light"] .custom-control.active svg {
fill: #ffffff !important;
}
/* 工具提示样式 */
.custom-control {
position: relative;
}
.custom-control::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%) translateY(-8px);
background: rgba(28, 28, 28, 0.9);
color: var(--text-color);
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: all 0.2s ease;
}
.custom-control:hover::after {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(-4px);
}
:root[data-theme="light"] .custom-control::after {
background: rgba(255, 255, 255, 0.9);
color: #000000;
border: 1px solid rgba(0, 0, 0, 0.1);
}
/* 自动续播按钮基础样式 */
#autoplayButton {
position: relative;
overflow: hidden;
}
#autoplayButton svg {
transform: scale(0.85);
transition: all 0.3s ease;
}
/* 图标各部分样式 */
#autoplayButton .icon-main {
fill: var(--text-color);
}
#autoplayButton .icon-repeat {
fill: var(--text-color);
opacity: 0.7;
transform-origin: center;
transition: all 0.3s ease;
}
/* 激活状态样式 */
#autoplayButton.active {
background: var(--youtube-red) !important;
}
#autoplayButton.active .icon-main,
#autoplayButton.active .icon-repeat {
fill: #ffffff !important;
opacity: 1;
}
/* 悬停效果 */
#autoplayButton:hover {
background: var(--youtube-red-hover) !important;
}
#autoplayButton:hover .icon-main,
#autoplayButton:hover .icon-repeat {
fill: #ffffff !important;
opacity: 1;
}
/* 动画效果 */
@keyframes rotate-repeat {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#autoplayButton.active .icon-repeat {
animation: rotate-repeat 4s linear infinite;
}
/* 浅色主题适配 */
:root[data-theme="light"] #autoplayButton .icon-main,
:root[data-theme="light"] #autoplayButton .icon-repeat {
fill: #000000;
}
:root[data-theme="light"] #autoplayButton.active .icon-main,
:root[data-theme="light"] #autoplayButton.active .icon-repeat,
:root[data-theme="light"] #autoplayButton:hover .icon-main,
:root[data-theme="light"] #autoplayButton:hover .icon-repeat {
fill: #ffffff !important;
}
/* 找到 .custom-control 的样式定义,修改为: */
.custom-control {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
/* 增加宽度 */
height: 40px;
/* 增加高度 */
border-radius: 6px;
/* 稍微增加圆角 */
background: transparent;
border: none;
cursor: pointer;
color: var(--text-color);
transition: all 0.2s ease;
margin: 0 2px;
/* 添加左右间距 */
}
/* 修改图标大小 */
.custom-control svg {
width: 24px;
/* 增加图标大小 */
height: 24px;
/* 增加图标大小 */
fill: var(--text-color) !important;
}
/* 修改自动续播按钮的图标大小 */
#autoplayButton svg {
transform: scale(1);
/* 移除缩小效果 */
transition: all 0.3s ease;
}
/* 调整工具提示的位置 */
.custom-control::after {
bottom: 120%;
/* 稍微提高提示位置 */
font-size: 14px;
/* 增加提示文字大小 */
padding: 6px 12px;
/* 增加提框内边距 */
}
/* 调整按钮组的位置和间距 */
.custom-controls {
display: flex;
align-items: center;
gap: 12px;
/* 增加按钮之间的间距 */
margin-left: 12px;
/* 增加左侧间距 */
padding: 0 4px;
/* 添加两侧内边距 */
}
/* 移动设备适配 */
@media screen and (max-width: 768px) {
.custom-control {
width: 36px;
/* ��动端稍微小一点 */
height: 36px;
}
.custom-control svg {
width: 22px;
height: 22px;
}
.custom-controls {
gap: 8px;
margin-left: 8px;
}
}
</style>
</head>
<body>
<button class="theme-toggle" id="themeToggle" aria-label="切换主题">
<svg class="sun-icon" viewBox="0 0 24 24">
<path
d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z" />
</svg>
</button>
<div class="main-container">
<!-- 左侧视频区域 -->
<div class="video-container">
<h1>
<img src="logo.png" alt="网站图标" class="site-icon">
金将军!忠诚!
</h1>
<div class="video-select-container">
<select class="video-select" id="videoSelect">
<!-- 选项会通过 JavaScript 动态添加 -->
</select>
</div>
<div class="player-wrapper">
<!-- 添加载遮罩 -->
<div class="loading-overlay">
<div class="loading-spinner"></div>
</div>
<video id="player" playsinline controls>
<source src="" type="video/mp4" />
<track kind="captions" label="文" src="" srclang="zh" default />
</video>
</div>
<!-- 新增字幕控面板 -->
<div class="subtitle-controls-panel">
<div class="subtitle-control">
<label>字幕大小</label>
<div class="control-group">
<input type="range" id="fontSize" min="16" max="80" value="32" step="2">
<span id="fontSizeValue">32px</span>
</div>
</div>
<div class="subtitle-control">
<label>背景透明度</label>
<div class="control-group">
<input type="range" id="bgOpacity" min="0" max="100" value="70" step="5">
<span id="bgOpacityValue">70%</span>
</div>
</div>
<div class="subtitle-control">
<label>字幕位置</label>
<div class="control-group">
<input type="range" id="subtitlePosition" min="20" max="200" value="60" step="5">
<span id="positionValue">60px</span>
</div>
</div>
</div>
</div>
</div>
<!-- Plyr JS -->
<script src="https://cdn.plyr.io/3.7.8/plyr.polyfilled.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
let player;
let currentVideoName = '';
// 定义播放控制函数
function playPrevVideo() {
const videoSelect = document.getElementById('videoSelect');
const currentIndex = videoSelect.selectedIndex;
const prevIndex = currentIndex === 0 ? videoSelect.options.length - 1 : currentIndex - 1;
videoSelect.selectedIndex = prevIndex;
loadVideo(videoSelect.value);
}
function playNextVideo() {
const videoSelect = document.getElementById('videoSelect');
const currentIndex = videoSelect.selectedIndex;
const nextIndex = (currentIndex + 1) % videoSelect.options.length;
videoSelect.selectedIndex = nextIndex;
loadVideo(videoSelect.value);
}
// 获取视频列表
console.log('开始获取视频列表...');
fetch('/api/videos')
.then(response => response.json())
.then(videos => {
console.log('获取到的视频列表:', videos);
const videoSelect = document.getElementById('videoSelect');
if (videos && videos.length > 0) {
// 对视频列表进行排序,确保APT.mp4在第位
videos.sort((a, b) => {
if (a.name === 'APT.mp4') return -1;
if (b.name === 'APT.mp4') return 1;
return a.name.localeCompare(b.name);
});
videos.forEach((video, index) => {
const option = document.createElement('option');
option.value = video.name;
option.textContent = video.name.replace(/\.mp4$/, "");
videoSelect.appendChild(option);
});
// 始化第一个视频
initializeFirstVideo(videos[0].name);
}
})
.catch(error => {
console.error('获取视频列表失败:', error);
// 移除报错提示,因为视频仍可以
console.log('继续初化默认视频');
initializeFirstVideo('APT.mp4'); // 使用默认视频
});
// 修改视频选择事件处理
document.getElementById('videoSelect').addEventListener('change', function (e) {
// 防止事件冒泡和默认行为
e.preventDefault();
e.stopPropagation();
const selectedVideo = e.target.value;
if (selectedVideo && selectedVideo !== currentVideoName) {
loadVideo(selectedVideo);
}
});
// 初始化第一个视频的函数
function initializeFirstVideo(videoName) {
const videoElement = document.getElementById('player');
const source = videoElement.querySelector('source');
const track = videoElement.querySelector('track');
const loadingOverlay = document.querySelector('.loading-overlay');
// 使用 decodeURIComponent 和 encodeURI 来正确处理中文文件名
const videoPath = `/video/${decodeURIComponent(encodeURI(videoName))}`;
source.src = videoPath;
// 检查字幕文件是否存在
const subtitleFileName = videoName.replace(/\.mp4$/, "");
const subtitlePath = `/video/${decodeURIComponent(encodeURI(subtitleFileName))}.mp4.vtt`;
// 先检查视频是否存在
fetch(videoPath, { method: 'HEAD' })
.then(response => {
if (response.ok) {
// 视频存在,继续处理
fetch(subtitlePath)
.then(response => {
if (response.ok) {
track.src = subtitlePath;
} else {
track.remove();
}
})
.catch(error => {
console.log('Error checking subtitle file:', error);
track.remove();
})
.finally(() => {
// 根据设备类型初始化不同的播放器
if (isMobileDevice()) {
// 移动设备使用原生播放器
initializeMobilePlayer(videoElement);
// 添加加载完成事件监听
videoElement.addEventListener('loadeddata', function onLoadedData() {
loadingOverlay.classList.add('hidden');
videoElement.play().catch(error => {
console.log('Auto-play prevented:', error);
});
videoElement.removeEventListener('loadeddata', onLoadedData);
});
// 强制加载视频
videoElement.load();
} else {
// PC端使用Plyr播放器
initializePlyrPlayer(videoElement);
}
});
} else {
throw new Error('Video not found');
}
})
.catch(error => {
console.error('Error loading video:', error);
loadingOverlay.classList.add('hidden');
alert('视频加载失败,请稍后重试');
});
currentVideoName = videoName;
}
// 移动设备播放器初始化
function initializeMobilePlayer(videoElement) {
// 移除现有的Plyr相关类和属性
videoElement.className = 'mobile-player';
// 移除可能存在的Plyr实例
if (player) {
player.destroy();
player = null;
}
// 设置移动端所需的属性
videoElement.setAttribute('playsinline', '');
videoElement.setAttribute('webkit-playsinline', '');
videoElement.setAttribute('x5-playsinline', '');
videoElement.setAttribute('x5-video-player-type', 'h5');
videoElement.setAttribute('x5-video-player-fullscreen', 'true');
videoElement.setAttribute('x5-video-orientation', 'landscape');
videoElement.setAttribute('controls', ''); // 启用原生控件
// 添加移动端播放器样式
const style = document.createElement('style');
style.textContent = `
.mobile-player {
width: 100%;
height: 100%;
background: #000;
object-fit: contain;
}
.mobile-player:fullscreen {
width: 100vw;
height: 100vh;
}
.mobile-player::cue {
font-size: 20px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
}
`;
document.head.appendChild(style);
// 监听加载完成事件
videoElement.addEventListener('loadeddata', () => {
loadingOverlay.classList.add('hidden');
});
// 错误处理
videoElement.addEventListener('error', () => {
console.error('Video error:', videoElement.error);
loadingOverlay.classList.add('hidden');
alert('视频加载失败,请稍后重试');
});
// 添加全屏事件监听
videoElement.addEventListener('fullscreenchange', handleFullscreen);
videoElement.addEventListener('webkitfullscreenchange', handleFullscreen);
videoElement.addEventListener('mozfullscreenchange', handleFullscreen);
videoElement.addEventListener('MSFullscreenChange', handleFullscreen);
let isVideoFullscreen = false;
function handleFullscreen() {
const isFullscreen = document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement;
if (isFullscreen && isFullscreen === videoElement) {
isVideoFullscreen = true;
lockScreenOrientation('landscape');
} else if (isVideoFullscreen) {
isVideoFullscreen = false;
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
}
}
}
// 添加页面可见性变化监听
document.addEventListener('visibilitychange', function () {
if (!document.hidden && !isVideoFullscreen) {
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
}
}
});
// 添加屏幕方向变化监听
window.addEventListener('orientationchange', function () {
if (!isVideoFullscreen) {
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
}
}
});
}
// PC端Plyr播放器初始化
function initializePlyrPlayer(videoElement) {
// 确保移除移动端相关的类和控件
const mobileControls = document.querySelector('.mobile-controls');
if (mobileControls) {
mobileControls.remove();
}
videoElement.className = '';
// 初始化Plyr播放器
player = new Plyr('#player', {
captions: { active: true, language: 'zh', update: true },
controls: [
'play-large',
'play',
'progress',
'current-time',
'duration',
'mute',
'volume',
'captions',
'settings',
'pip',
'fullscreen'
],
settings: ['captions', 'quality', 'speed'],
tooltips: { controls: true },
ratio: '16:9',
fullscreen: {
enabled: true,
fallback: true,
iosNative: true
}
});
// 添加自定义控件
player.on('ready', () => {
const controlsContainer = document.querySelector('.plyr__controls');
const volumeControl = controlsContainer.querySelector('.plyr__volume');
// 添加自定义控件
const customControls = `
<div class="custom-controls">
<button class="custom-control" id="autoplayButton" data-tooltip="自动续播">
<svg viewBox="0 0 24 24">
<path class="icon-main" d="M7 7v10l7-5-7-5z"/>
<path class="icon-repeat" d="M17 17H7v-2H5v2c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-2h-2v2zM17 5H7v2H5V5c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2v2h-2V5z"/>
</svg>
</button>
<button class="custom-control" id="prevVideoButton" data-tooltip="上一个视频">
<svg viewBox="0 0 24 24">
<path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/>
</svg>
</button>
<button class="custom-control" id="nextVideoButton" data-tooltip="下一个视频">
<svg viewBox="0 0 24 24">
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/>
</svg>
</button>
</div>
`;
volumeControl.insertAdjacentHTML('afterend', customControls);
// 绑定自定义控件事件
document.getElementById('autoplayButton').addEventListener('click', () => {
const isEnabled = document.getElementById('autoplayButton').classList.toggle('active');
localStorage.setItem('autoplay', isEnabled);
});
document.getElementById('prevVideoButton').addEventListener('click', playPrevVideo);
document.getElementById('nextVideoButton').addEventListener('click', playNextVideo);
// 获取自动续播状态
const autoplayEnabled = localStorage.getItem('autoplay') === 'true';
if (autoplayEnabled) {
document.getElementById('autoplayButton').classList.add('active');
}
});
// 视频结束时的处理
player.on('ended', () => {
const autoplayEnabled = localStorage.getItem('autoplay') === 'true';
if (autoplayEnabled) {
playNextVideo();
}
});
// 隐藏加载遮罩
document.querySelector('.loading-overlay').classList.add('hidden');
}
// 修改加载视频函数
function loadVideo(videoName) {
if (!videoName || currentVideoName === videoName) return;
const videoSelect = document.getElementById('videoSelect');
videoSelect.disabled = true;
const loadingOverlay = document.querySelector('.loading-overlay');
loadingOverlay.classList.remove('hidden');
const videoElement = document.getElementById('player');
if (isMobileDevice()) {
// 移动设备加载视频
const videoPath = `/video/${decodeURIComponent(encodeURI(videoName))}`;
// 先检查视频是否存在
fetch(videoPath, { method: 'HEAD' })
.then(response => {
if (response.ok) {
// 视频存在,开始加载
videoElement.src = videoPath;
// 检查字幕文件
const subtitleFileName = videoName.replace(/\.mp4$/, "");
const subtitlePath = `/video/${decodeURIComponent(encodeURI(subtitleFileName))}.mp4.vtt`;
const track = videoElement.querySelector('track');
if (track) {
fetch(subtitlePath)
.then(response => {
if (response.ok) {
track.src = subtitlePath;
} else {
track.remove();
}
})
.catch(() => track.remove());
}
// 监听视频加载完成事件
const onLoadedData = function () {
loadingOverlay.classList.add('hidden');
videoSelect.disabled = false;
videoElement.play().catch(error => {
console.log('Auto-play prevented:', error);
});
};
videoElement.addEventListener('loadeddata', onLoadedData, { once: true });
// 添加错误处理
const onError = function () {
console.error('Video loading error:', videoElement.error);
loadingOverlay.classList.add('hidden');
videoSelect.disabled = false;
alert('视频加载失败,请稍后重试');
};
videoElement.addEventListener('error', onError, { once: true });
videoElement.load(); // 开始加载视频
} else {
throw new Error('Video not found');
}
})
.catch(error => {
console.error('Error loading video:', error);
loadingOverlay.classList.add('hidden');
videoSelect.disabled = false;
alert('视频加载失败,请稍后重试');
});
} else {
// PC端代码保持不变
if (player) {
const newSource = {
type: 'video',
sources: [{
src: `/video/${decodeURIComponent(encodeURI(videoName))}`,
type: 'video/mp4'
}]
};
// 检查字幕文件是否存在
const subtitleFileName = videoName.replace(/\.mp4$/, "");
const subtitlePath = `/video/${decodeURIComponent(encodeURI(subtitleFileName))}.mp4.vtt`;
fetch(subtitlePath)
.then(response => {
if (response.ok) {
newSource.tracks = [{
kind: 'captions',
label: '中文',
srclang: 'zh',
src: subtitlePath,
default: true
}];
}
})
.catch(error => {
console.log('Error checking subtitle file:', error);
})
.finally(() => {
player.source = newSource;
player.once('loadeddata', () => {
loadingOverlay.classList.add('hidden');
videoSelect.disabled = false;
player.play().catch(error => {
console.log('Auto-play prevented:', error);
});
});
});
}
}
currentVideoName = videoName;
}
// 字幕设置关代码
const fontSize = document.getElementById('fontSize');
const fontSizeValue = document.getElementById('fontSizeValue');
fontSize.addEventListener('input', function () {
const size = this.value;
fontSizeValue.textContent = `${size}px`;
document.documentElement.style.setProperty('--subtitle-size', `${size}px`);
const weight = size > 40 ? 400 : 500;
document.documentElement.style.setProperty('--subtitle-weight', weight);
});
const bgOpacity = document.getElementById('bgOpacity');
const bgOpacityValue = document.getElementById('bgOpacityValue');
bgOpacity.addEventListener('input', function () {
const opacity = this.value / 100;
bgOpacityValue.textContent = `${this.value}%`;
document.documentElement.style.setProperty(
'--subtitle-bg-color',
`rgba(0, 0, 0, ${opacity})`
);
});
const subtitlePosition = document.getElementById('subtitlePosition');
const positionValue = document.getElementById('positionValue');
subtitlePosition.addEventListener('input', function () {
const position = this.value;
positionValue.textContent = `${position}px`;
document.documentElement.style.setProperty('--subtitle-bottom', `${position}px`);
});
// 键盘快捷键
document.addEventListener('keydown', function (event) {
if (!player) return;
if (event.code === 'Space') {
player.togglePlay();
event.preventDefault();
}
else if (event.code === 'ArrowUp') {
player.increaseVolume(0.1);
event.preventDefault();
}
else if (event.code === 'ArrowDown') {
player.decreaseVolume(0.1);
event.preventDefault();
}
});
// 初始化字幕样式
document.documentElement.style.setProperty('--subtitle-size', '32px');
document.documentElement.style.setProperty('--subtitle-bg-color', 'rgba(0, 0, 0, 0.7)');
document.documentElement.style.setProperty('--subtitle-bottom', '60px');
// 修改字幕设置面板样式
const style = document.createElement('style');
style.textContent = `
.plyr__subtitle-settings {
position: absolute;
bottom: 60px;
right: 10px;
background: rgba(0, 0, 0, 0.9);
padding: 15px;
border-radius: 4px;
z-index: 1000;
color: white;
min-width: 200px;
}
.subtitle-control {
margin-bottom: 10px;
}
.subtitle-control label {
display: block;
margin-bottom: 5px;
}
.subtitle-control input[type="range"] {
width: 100%;
}
.subtitle-control span {
float: right;
font-size: 12px;
}
/* 增大字幕样式 */
.plyr__captions {
font-size: var(--subtitle-size, 32px) !important;
font-weight: var(--subtitle-weight, 500) !important;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8) !important;
}
.plyr__caption {
background: var(--subtitle-bg-color, rgba(0, 0, 0, 0.7)) !important;
padding: 8px 12px !important;
border-radius: 4px !important;
max-width: 90% !important;
margin: 0 auto !important;
line-height: 1.4 !important;
}
`;
document.head.appendChild(style);
});
// 将之前在 CSS 中的 JavaScript 代码移到这里
function updateRangeBackground(rangeElement) {
const value = (rangeElement.value - rangeElement.min) / (rangeElement.max - rangeElement.min) * 100;
rangeElement.style.setProperty('--value', `${value}%`);
}
// 为所有滑块添加事件监听
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.subtitle-control input[type="range"]').forEach(range => {
// 初始化滑块颜色
updateRangeBackground(range);
// 监听滑块变化
range.addEventListener('input', function () {
updateRangeBackground(this);
});
});
});
// 在 DOMContentLoaded 事件监听器中添加以下代码
document.addEventListener('DOMContentLoaded', function () {
// 主题切换能
const themeToggle = document.getElementById('themeToggle');
const root = document.documentElement;
const moonIcon = `<svg class="moon-icon" viewBox="0 0 24 24"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-3.03 0-5.5-2.47-5.5-5.5 0-1.82.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/></svg>`;
const sunIcon = `<svg class="sun-icon" viewBox="0 0 24 24"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z" />
</svg>`;
// 检查本地存储中的主题设置
const savedTheme = localStorage.getItem('theme') || 'dark';
root.setAttribute('data-theme', savedTheme);
themeToggle.innerHTML = savedTheme === 'dark' ? sunIcon : moonIcon;
// 题切换事件处理
themeToggle.addEventListener('click', () => {
const currentTheme = root.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', newTheme);
themeToggle.innerHTML = newTheme === 'dark' ? sunIcon : moonIcon;
// 保存主题设置到本地存储
localStorage.setItem('theme', newTheme);
});
});
// 处理屏幕方向变化
function handleOrientationChange() {
if (isMobileDevice()) {
const isLandscape = isLandscapeMode();
if (isLandscape && !player.fullscreen.active) {
player.fullscreen.enter();
} else if (!isLandscape && player.fullscreen.active) {
player.fullscreen.exit();
}
}
}
// 检查是否是移动设备
function isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// 检查是否是横屏模式
function isLandscapeMode() {
// 优先使用屏幕向API
if (window.screen && window.screen.orientation) {
return window.screen.orientation.type.includes('landscape');
}
// 回退到window.orientation
else if (window.orientation !== undefined) {
return Math.abs(window.orientation) === 90;
}
// 最后使用视窗尺寸比例
return window.innerWidth > window.innerHeight;
}
// 在组件卸载时清理事件监听
window.addEventListener('unload', () => {
if ('orientation' in window) {
window.removeEventListener('orientationchange', handleOrientationChange);
} else if ('screen' in window && 'orientation' in window.screen) {
screen.orientation.removeEventListener('change', handleOrientationChange);
}
});
// 添加全屏变化监听,处理用户手动退出全屏的情况
document.addEventListener('fullscreenchange', handleFullscreenChange);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
document.addEventListener('mozfullscreenchange', handleFullscreenChange);
document.addEventListener('MSFullscreenChange', handleFullscreenChange);
function handleFullscreenChange() {
if (isMobileDevice() && isLandscapeMode()) {
const videoContainer = document.querySelector('.video-container');
if (!document.fullscreenElement && videoContainer) {
lockScreenOrientation('landscape');
videoContainer.requestFullscreen().catch(error => {
console.log('Fullscreen re-entry failed:', error);
});
}
}
}
// 添加屏幕方向锁定支持
function lockScreenOrientation(orientation) {
try {
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock(orientation).catch(error => {
console.log('Screen orientation lock failed:', error);
// 锁定失败时尝试解锁
screen.orientation.unlock();
});
} else if (screen.lockOrientation) {
screen.lockOrientation(orientation);
} else if (screen.webkitLockOrientation) {
screen.webkitLockOrientation(orientation);
} else if (screen.mozLockOrientation) {
screen.mozLockOrientation(orientation);
} else if (screen.msLockOrientation) {
screen.msLockOrientation(orientation);
}
} catch (error) {
console.log('Screen orientation lock error:', error);
// 发生错误时尝试解锁
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
}
}
}
// 在 script 标签内添加 checkOrientation 函数定义
function checkOrientation() {
if (isMobileDevice()) {
const isLandscape = isLandscapeMode();
if (isLandscape && !player.fullscreen.active) {
player.fullscreen.enter().catch(error => {
console.log('Fullscreen enter failed:', error);
});
}
}
}
function loadVideo(videoName) {
// ...现有代码
let retryCount = 0;
const maxRetries = 3;
function tryLoadVideo() {
fetch(`/video/${decodeURIComponent(encodeURI(videoName))}`, {
method: 'HEAD'
}).then(response => {
if (response.ok) {
// 视频存在,继续加载
player.source = newSource;
} else {
throw new Error('Video not found');
}
}).catch(error => {
console.error('Error loading video:', error);
if (retryCount < maxRetries) {
retryCount++;
setTimeout(tryLoadVideo, 1000 * retryCount);
} else {
loadingOverlay.classList.add('hidden');
videoSelect.disabled = false;
alert('视频加载失败,请稍后重试');
}
});
}
tryLoadVideo();
}
</script>
</body>
</html>
视频文件和字幕位于/video
,命名示例
视频:APT.mp4
字幕:APT.mp4.vtt
nginx.conf
# 在 server 块之前添加日志格式定义
log_format video_access '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$http_range" $request_time';
server {
listen 80 ;
listen [::]:80 ;
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;
server_name video.1143520.xyz fastly-test.1143520.xyz;
index video.html index.php index.html index.htm default.php default.htm default.html;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
access_log /www/sites/video.1143520.xyz/log/access.log main;
error_log /www/sites/video.1143520.xyz/log/error.log;
location ^~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}
root /www/sites/video.1143520.xyz/index;
error_page 404 /404.html;
if ($scheme = http) {
return 301 https://$host$request_uri;
}
ssl_certificate /www/sites/video.1143520.xyz/ssl/fullchain.pem;
ssl_certificate_key /www/sites/video.1143520.xyz/ssl/privkey.pem;
ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header X-Forwarded-Proto https;
add_header Strict-Transport-Security "max-age=31536000";
location = / {
try_files /video.html =404;
}
location = /video.html {
return 301 /;
}
location ~* \.html$ {
return 403;
}
location ~* \.srt$ {
add_header Content-Type "application/x-subrip";
add_header Access-Control-Allow-Origin "*";
}
location /video/ {
valid_referers none blocked server_names *.1143520.xyz;
if ($invalid_referer) {
return 301 /;
}
alias /www/sites/video.1143520.xyz/index/video/;
add_header Access-Control-Allow-Origin "*";
types {
application/x-subrip srt;
video/mp4 mp4;
}
add_header Cache-Control "public, max-age=3600";
add_header X-Content-Type-Options "nosniff";
add_header Accept-Ranges bytes;
slice 1m;
proxy_cache_key $uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_cache_valid 200 206 1h;
access_log /www/sites/video.1143520.xyz/log/video_access.log video_access;
}
location /api/videos {
default_type application/json;
content_by_lua_block {
local cjson = require "cjson"
local io = io
local videos = {}
-- 添加调试日志
ngx.log(ngx.ERR, "开始扫描视频目录")
-- 使用更安全的方式列出文件
local video_dir = "/www/sites/video.1143520.xyz/index/video"
local cmd = string.format("find %s -maxdepth 1 -type f -name '*.mp4'", video_dir)
-- 执行命令并捕获输出
local handle = io.popen(cmd)
if not handle then
ngx.log(ngx.ERR, "无法执行命令")
ngx.status = 500
ngx.say(cjson.encode({error = "Internal server error"}))
return
end
local result = handle:read("*a")
handle:close()
-- 记录扫描结果
ngx.log(ngx.ERR, "扫描结果: " .. (result or "空"))
-- 解析文件列表
for filename in string.gmatch(result, "[^\n]+") do
-- 提取文件名
local name = string.match(filename, "([^/]+)$")
if name and string.match(name, "%.mp4$") then
table.insert(videos, {name = name})
ngx.log(ngx.ERR, "找到视频文件: " .. name)
end
end
if #videos == 0 then
ngx.log(ngx.ERR, "没有找到任何视频文件")
end
-- 设置响应头
ngx.header["Content-Type"] = "application/json"
ngx.header["Access-Control-Allow-Origin"] = "*"
ngx.header["Access-Control-Allow-Methods"] = "GET"
-- 返回结果
local response = cjson.encode(videos)
ngx.log(ngx.ERR, "返回数据: " .. response)
ngx.say(response)
}
}
}