Update server, frontend + add proxy handler

This commit is contained in:
yuqianhe
2026-06-10 05:12:15 +00:00
parent 413d6c463b
commit d9908fcb37
6 changed files with 421 additions and 5 deletions

View File

@@ -3,9 +3,11 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<title>api-server - 运维监控面板</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="/style.css?v=2">
</head>
<body>
<div class="container">
@@ -134,6 +136,6 @@
</footer>
</div>
<script src="/app.js"></script>
<script src="/app.js?v=2"></script>
</body>
</html>

View File

@@ -26,6 +26,42 @@ let totalPages = 1;
let currentViewkey = null;
let extractedVideoURL = null;
// ── 播放模式('proxy' | 'direct')───────────────────────────
let playMode = localStorage.getItem('playMode') || 'proxy';
function initPlayMode() {
const toggle = document.getElementById('modeToggle');
if (!toggle) return;
if (playMode === 'direct') toggle.classList.add('direct');
else toggle.classList.remove('direct');
}
function togglePlayMode() {
playMode = (playMode === 'proxy') ? 'direct' : 'proxy';
localStorage.setItem('playMode', playMode);
const toggle = document.getElementById('modeToggle');
if (playMode === 'direct') {
toggle.classList.add('direct');
} else {
toggle.classList.remove('direct');
}
// 如果当前正在播放视频,重新加载
if (extractedVideoURL && !document.getElementById('videoPlayer').classList.contains('hidden')) {
startVideoPlayer(extractedVideoURL);
}
}
// 根据模式构建视频加载 URL
function getVideoLoadURL(rawURL) {
if (playMode === 'direct') return rawURL;
return '/api/proxy/video?url=' + encodeURIComponent(rawURL);
}
// 根据模式返回 referrerpolicy 值
function getVideoReferrerPolicy() {
return (playMode === 'direct') ? 'no-referrer' : 'no-referrer';
}
function navigate(hash) {
window.location.hash = hash;
}
@@ -250,6 +286,12 @@ function startVideoPlayer(src) {
const source = document.getElementById('videoSource');
const errorOverlay = document.getElementById('playerError');
// 双模式加载:直连(剥离 Referer或后端代理
const loadURL = getVideoLoadURL(src);
// 设置 Referrer Policy直连模式关键阻止浏览器发送 Referer
video.setAttribute('referrerpolicy', getVideoReferrerPolicy());
// 先注册事件,再加载
video.onloadedmetadata = function() {
document.getElementById('playerStatus').className = 'player-status success';
@@ -285,7 +327,7 @@ function startVideoPlayer(src) {
};
// 切换显示:隐藏占位,显示播放器
source.src = src;
source.src = loadURL;
video.load();
playerBox.classList.add('hidden');
video.classList.remove('hidden');
@@ -390,6 +432,7 @@ function formatDuration(seconds) {
// ── 事件 ────────────────────────────────────────────────────
window.addEventListener('hashchange', handleRoute);
window.addEventListener('load', () => {
initPlayMode();
handleRoute();
refreshNavStats();
setInterval(refreshNavStats, 10000);

View File

@@ -3,8 +3,11 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Sol148 Video - 视频浏览</title>
<link rel="stylesheet" href="/videoapp/style.css">
<link rel="stylesheet" href="/videoapp/style.css?v=2">
</head>
<body>
<!-- 顶部导航 -->
@@ -98,6 +101,14 @@
</div>
</div>
<div class="player-status hidden" id="playerStatus"></div>
<div class="player-mode" id="playerMode">
<span class="mode-label">加载模式</span>
<div class="mode-toggle" id="modeToggle" onclick="togglePlayMode()" title="切换视频加载方式">
<span class="mode-option active" data-mode="proxy">🛡️ 代理</span>
<span class="mode-option" data-mode="direct">🔗 直连</span>
<span class="mode-slider"></span>
</div>
</div>
</div>
<div class="video-detail">
<h2 id="videoTitle">--</h2>
@@ -130,6 +141,6 @@
<span>Data via sol148-extractor API</span>
</footer>
<script src="/videoapp/app.js"></script>
<script src="/videoapp/app.js?v=2"></script>
</body>
</html>

View File

@@ -147,6 +147,32 @@ body {
.player-status.success { border-left:3px solid var(--success); color:var(--success); }
.player-status.error { border-left:3px solid var(--accent); color:var(--accent); }
/* ── 播放模式切换 ──────────────────────────────────────── */
.player-mode {
display:flex; align-items:center; gap:10px; margin-top:8px;
padding:8px 12px; background:var(--card); border-radius:8px; font-size:0.8rem;
}
.player-mode .mode-label { color:var(--text2); white-space:nowrap; }
.mode-toggle {
position:relative; display:flex; align-items:center; gap:0;
background:var(--bg); border-radius:20px; padding:3px;
cursor:pointer; user-select:none;
border:1px solid var(--border);
}
.mode-option {
position:relative; z-index:1; padding:5px 14px; border-radius:17px;
color:var(--text2); transition:color .2s; white-space:nowrap;
}
.mode-option.active { color:var(--text); }
.mode-slider {
position:absolute; top:3px; left:3px; width:calc(50% - 3px); height:calc(100% - 6px);
background:var(--accent2); border-radius:17px;
transition:transform .2s ease; z-index:0;
}
.mode-toggle.direct .mode-slider { transform:translateX(100%); }
.mode-toggle.direct .mode-option[data-mode="direct"] { color:var(--text); }
.mode-toggle.direct .mode-option[data-mode="proxy"] { color:var(--text2); }
.video-detail h2 { font-size:1.3rem; margin-bottom:12px; }
.video-meta { display:flex; flex-wrap:wrap; gap:16px; margin-bottom:16px; font-size:0.85rem; color:var(--text2); }
.video-actions { display:flex; gap:8px; margin-bottom:12px; flex-wrap:wrap; }