Update server, frontend + add proxy handler
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user