性能优化 & QR 修复:消除卡顿,二维码提取重构

【速度优化】
- 页面加载:wait_until 从 domcontentloaded 改为 commit(更快)
- 等待时间大幅缩减:主页加载 2-4s→1-2s,点击后 3-5s→1-2s
  QR切换等待 3s→1.5s,弹窗检测等待 2s→1s,轮询间隔 800ms→500ms
- 代理测试超时从 10s 降为 5s,get_proxy_from_api 支持可配置超时

【二维码修复 — 3 级策略】
- 策略 1:提取真实 QR <img> 的 src(data URI 直接解码 / CDN URL 下载)
- 策略 2:截取 QR 元素本身(仅二维码区域,非整个弹窗)
- 策略 3:截图弹窗/全屏兜底
→ 解决二维码显示异常(之前是整个登录弹窗截图,包含大量无关 UI)

【前端瘦身 — 消除外部 CDN 阻塞】
- 移除 highlight.js(~100KB)& font-awesome(~90KB)
- 全部图标改用 Unicode/Emoji,轻量 CSS spinner 替代 fa-spinner
- 轮询频率优化:status 2s→3s,check_login 2s→2.5s
- 首页仅 37KB,零外部依赖,即时渲染

Co-Authored-By: Claude <noreply@anthropic.com>
@
This commit is contained in:
travel
2026-06-25 07:51:00 +08:00
parent f9fb8478d6
commit 853dacf528
2 changed files with 184 additions and 100 deletions
+41 -33
View File
@@ -4,9 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>抖音 Cookie 扫码提取器</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<!-- 移除外部 CDN 依赖,使用内联 Unicode 图标 + 轻量 spinner -->
<style>
:root {
--bg: #0f172a;
@@ -121,6 +119,19 @@
.dot.ready { background: var(--success); }
.dot.error { background: var(--error); animation: none; }
/* 轻量 spinner 替代 fa-spinner */
.spinner {
display: inline-block;
width: 14px; height: 14px;
border: 2px solid rgba(255,255,255,0.2);
border-top-color: currentColor;
border-radius: 50%;
animation: spin 0.6s linear infinite;
vertical-align: middle;
margin-right: 4px;
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pulse {
0%, 100% { opacity: 0.4; transform: scale(0.8); }
50% { opacity: 1; transform: scale(1.2); }
@@ -671,10 +682,10 @@
<div class="left-panel">
<div class="btn-group">
<button class="btn btn-primary" id="startBtn" onclick="startQR()">
<i class="fas fa-qrcode"></i> 获取二维码
📱 获取二维码
</button>
<button class="btn btn-danger" id="resetBtn" onclick="resetSession()" style="flex:0.5;">
<i class="fas fa-undo"></i>
🔄
</button>
</div>
@@ -686,8 +697,7 @@
</div>
<div id="statusBadge" class="status-badge"></div>
<div style="margin-top:10px;font-size:0.8rem;color:var(--text-secondary);">
<i class="fas fa-download"></i>
<a href="/qrcode.png" target="_blank" style="color:var(--accent);">下载二维码</a>
<a href="/qrcode.png" target="_blank" style="color:var(--accent);">下载二维码</a>
</div>
</div>
@@ -695,7 +705,7 @@
<div id="resultContainer" class="hidden">
<div class="code-box">
<button class="copy-btn" onclick="copyCookies()">
<i class="fas fa-copy"></i> 复制
📋 复制
</button>
<pre><code id="cookieCode" class="language-json"></code></pre>
</div>
@@ -706,20 +716,19 @@
<div class="right-panel">
<div class="input-group">
<label>
<i class="fas fa-globe"></i> 代理 API
🌐 代理 API
<span style="font-weight:400;color:var(--text-secondary);font-size:0.7rem;">(选填)</span>
</label>
<input type="text" id="proxyApi" placeholder="https://api.example.com/proxy" autocomplete="off">
<div class="proxy-status" id="proxyStatus">
<i class="fas fa-circle" style="font-size:0.5rem;color:var(--text-secondary);"></i>
默认:服务器 IP
● 默认:服务器 IP
</div>
</div>
<button class="btn btn-success" id="testProxyBtn" onclick="testProxy()" style="font-size:0.85rem;padding:8px 12px;">
<i class="fas fa-plug"></i> 测试代理
🔌 测试代理
</button>
<div style="font-size:0.7rem;color:var(--text-secondary);text-align:center;padding:4px;">
<i class="fas fa-info-circle"></i> 留空则使用服务器默认 IP
留空则使用服务器默认 IP
</div>
</div>
</div>
@@ -831,7 +840,7 @@
// ========== 开始状态轮询 ==========
function startStatusPolling() {
if (statusPollingInterval) clearInterval(statusPollingInterval);
statusPollingInterval = setInterval(pollStatus, 2000);
statusPollingInterval = setInterval(pollStatus, 3000);
pollStatus(); // 立即执行一次
}
@@ -849,7 +858,7 @@
qrContainer.classList.add('hidden');
resultContainer.classList.add('hidden');
startBtn.disabled = false;
startBtn.innerHTML = '<i class="fas fa-qrcode"></i> 获取二维码';
startBtn.innerHTML = '📱 获取二维码';
updateStatus('idle', '已重置,可以重新开始');
} catch (e) {
showToast('重置失败,请重启服务', true);
@@ -859,10 +868,10 @@
// ========== 代理输入监听 ==========
proxyInput.addEventListener('input', function() {
if (this.value.trim()) {
proxyStatus.innerHTML = `<i class="fas fa-circle" style="font-size:0.5rem;color:var(--accent);"></i> 已配置代理`;
proxyStatus.innerHTML = `● <span style="color:var(--accent);">已配置代理</span>`;
proxyStatus.className = 'proxy-status active';
} else {
proxyStatus.innerHTML = `<i class="fas fa-circle" style="font-size:0.5rem;color:var(--text-secondary);"></i> 默认:服务器 IP`;
proxyStatus.innerHTML = ` 默认:服务器 IP`;
proxyStatus.className = 'proxy-status';
}
});
@@ -877,7 +886,7 @@
const btn = document.getElementById('testProxyBtn');
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 测试中...';
btn.innerHTML = '<span class="spinner"></span> 测试中...';
try {
const response = await fetch('/api/test_proxy', {
@@ -889,18 +898,18 @@
if (data.status === 'success') {
showToast(`✅ 代理测试成功!IP: ${data.ip || '获取成功'}`);
proxyStatus.innerHTML = `<i class="fas fa-circle" style="font-size:0.5rem;color:var(--success);"></i> ✅ 代理可用`;
proxyStatus.innerHTML = `✅ 代理可用`;
proxyStatus.className = 'proxy-status active';
} else {
showToast(`❌ 代理测试失败: ${data.message}`, true);
proxyStatus.innerHTML = `<i class="fas fa-circle" style="font-size:0.5rem;color:var(--error);"></i> ❌ 代理不可用`;
proxyStatus.innerHTML = `❌ 代理不可用`;
proxyStatus.className = 'proxy-status';
}
} catch (e) {
showToast('❌ 网络错误,请检查服务是否运行', true);
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-plug"></i> 测试代理';
btn.innerHTML = '🔌 测试代理';
}
}
@@ -946,7 +955,7 @@
} catch (e) {}
startBtn.disabled = true;
startBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 加载中...';
startBtn.innerHTML = '<span class="spinner"></span> 加载中...';
qrContainer.classList.add('hidden');
resultContainer.classList.add('hidden');
scanLine.style.display = 'block';
@@ -967,7 +976,7 @@
qrContainer.classList.remove('hidden');
isQrReady = true;
updateStatus('ready', '✅ 二维码已生成,请用抖音扫码');
startBtn.innerHTML = '<i class="fas fa-qrcode"></i> 获取二维码';
startBtn.innerHTML = '📱 获取二维码';
startBtn.disabled = false;
// 开始轮询登录状态
@@ -977,7 +986,7 @@
saveStats();
if (proxyApi) {
proxyStatus.innerHTML = `<i class="fas fa-circle" style="font-size:0.5rem;color:var(--success);"></i> ✅ 代理已启用`;
proxyStatus.innerHTML = `✅ 代理已启用`;
proxyStatus.className = 'proxy-status active';
}
@@ -985,7 +994,7 @@
} else {
updateStatus('error', '❌ ' + (data.message || '获取二维码失败'));
startBtn.disabled = false;
startBtn.innerHTML = '<i class="fas fa-qrcode"></i> 获取二维码';
startBtn.innerHTML = '📱 获取二维码';
showToast(data.message || '获取二维码失败', true);
scanLine.style.display = 'none';
}
@@ -993,7 +1002,7 @@
console.error('启动错误:', e);
updateStatus('error', '❌ 连接服务器失败');
startBtn.disabled = false;
startBtn.innerHTML = '<i class="fas fa-qrcode"></i> 获取二维码';
startBtn.innerHTML = '📱 获取二维码';
showToast('⚠️ 无法连接到服务器,请确保服务已启动', true);
scanLine.style.display = 'none';
}
@@ -1002,7 +1011,7 @@
// ========== 轮询登录状态 ==========
function startPolling() {
if (pollingInterval) clearInterval(pollingInterval);
pollingInterval = setInterval(checkLogin, 2000);
pollingInterval = setInterval(checkLogin, 2500);
}
async function checkLogin() {
@@ -1018,7 +1027,7 @@
displayCookies(data.cookies);
showToast(`🎉 Cookie 提取成功!耗时 ${elapsed}s`);
startBtn.disabled = false;
startBtn.innerHTML = '<i class="fas fa-qrcode"></i> 获取二维码';
startBtn.innerHTML = '📱 获取二维码';
scanLine.style.display = 'none';
isQrReady = false;
@@ -1032,7 +1041,7 @@
updateStatus('error', '❌ ' + data.message);
showToast(data.message, true);
startBtn.disabled = false;
startBtn.innerHTML = '<i class="fas fa-qrcode"></i> 获取二维码';
startBtn.innerHTML = '📱 获取二维码';
scanLine.style.display = 'none';
isQrReady = false;
} else if (data.status === 'scanning') {
@@ -1048,7 +1057,7 @@
const jsonStr = JSON.stringify(cookies, null, 2);
cookieCode.textContent = jsonStr;
resultContainer.classList.remove('hidden');
hljs.highlightElement(cookieCode);
// JSON 自带缩进,无需外部高亮库
}
// ========== 复制 Cookie ==========
@@ -1057,11 +1066,11 @@
const btn = document.querySelector('.copy-btn');
navigator.clipboard.writeText(text).then(() => {
btn.classList.add('copied');
btn.innerHTML = '<i class="fas fa-check"></i> 已复制';
btn.innerHTML = ' 已复制';
showToast('📋 已复制到剪贴板');
setTimeout(() => {
btn.classList.remove('copied');
btn.innerHTML = '<i class="fas fa-copy"></i> 复制';
btn.innerHTML = '📋 复制';
}, 2000);
}).catch(() => showToast('复制失败', true));
}
@@ -1077,6 +1086,5 @@
updateStatus('idle', '就绪,点击"获取二维码"开始');
startStatusPolling();
</script>
<script>hljs.highlightAll();</script>
</body>
</html>