Files
dy/凭证采集工具版本e.html
2026-07-23 17:56:25 +08:00

2881 lines
72 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>鎶栭煶鍑璇侀噰闆嗗伐鍏 路 鏈鍦扮敓鎴 storage_state</title>
<style>
:root {
--bg: #0f1020;
--panel: #1a1b2e;
--panel2: #23244044;
--border: #2c2e4a;
--text: #e6e6f0;
--muted: #9aa0c0;
--accent: #8b5cf6;
--accent2: #a855f7;
--ok: #34d399;
--warn: #fbbf24;
--err: #f87171;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: radial-gradient(1200px 600px at 70% -10%, #2a1c4a55, transparent), var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", sans-serif;
line-height: 1.6;
padding: 32px 16px 80px;
}
.wrap { max-width: 920px; margin: 0 auto; }
h1 { font-size: 24px; margin: 0 0 4px; }
.sub { color: var(--muted); margin: 0 0 24px; font-size: 14px; }
.card {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 14px;
padding: 20px 22px;
margin-bottom: 18px;
}
.step-h {
display: flex; align-items: center; gap: 10px;
font-weight: 600; font-size: 16px; margin-bottom: 10px;
}
.badge {
width: 26px; height: 26px; flex: none;
background: linear-gradient(135deg, var(--accent), var(--accent2));
border-radius: 50%; display: grid; place-items: center;
font-size: 14px; font-weight: 700; color: #fff;
}
p.tip { color: var(--muted); font-size: 13.5px; margin: 6px 0; }
code.k { background: #00000055; padding: 1px 6px; border-radius: 5px; color: #c4b5fd; font-size: 13px; }
textarea {
width: 100%; min-height: 92px; resize: vertical;
background: #0c0d1a; color: var(--text);
border: 1px solid var(--border); border-radius: 10px;
padding: 12px; font-family: ui-monospace, Consolas, monospace; font-size: 12.5px;
outline: none;
}
textarea:focus { border-color: var(--accent); }
.snippet {
position: relative; background: #0c0d1a; border: 1px solid var(--border);
border-radius: 10px; padding: 12px 12px; margin: 10px 0;
font-family: ui-monospace, Consolas, monospace; font-size: 12.5px;
white-space: pre-wrap; word-break: break-all; color: #a5b4fc;
}
button {
background: linear-gradient(135deg, var(--accent), var(--accent2));
color: #fff; border: none; border-radius: 10px;
padding: 10px 18px; font-size: 14px; font-weight: 600; cursor: pointer;
transition: opacity .15s;
}
button:hover { opacity: .9; }
button.ghost {
background: transparent; border: 1px solid var(--border); color: var(--muted);
padding: 6px 12px; font-size: 12.5px; font-weight: 500;
}
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 12px; }
.out { min-height: 160px; }
.checks { margin-top: 12px; display: grid; gap: 6px; }
.chk { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.ok .dot { background: var(--ok); } .ok { color: var(--ok); }
.warn .dot { background: var(--warn); } .warn { color: var(--warn); }
.err .dot { background: var(--err); } .err { color: var(--err); }
.hint-box {
background: #1e1b3a; border: 1px solid #3b2f6b; border-radius: 10px;
padding: 10px 14px; margin: 10px 0; font-size: 13px; color: #cbd5e1;
}
ol { margin: 6px 0 6px 4px; padding-left: 20px; }
ol li { margin: 4px 0; font-size: 13.5px; }
.pill { font-size: 11px; color: var(--muted); border: 1px solid var(--border); padding: 1px 8px; border-radius: 999px; }
.toast {
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
background: #111; border: 1px solid var(--accent); color: #fff;
padding: 10px 18px; border-radius: 10px; opacity: 0; transition: opacity .2s; pointer-events: none;
font-size: 13.5px;
}
.toast.show { opacity: 1; }
.toast.warn { border-color: #fbbf24; background: #2b231c; max-width: min(92vw, 520px); text-align: left; line-height: 1.5; }
.ws-tag { font-size: 11px; color: #6ee7b7; border: 1px solid #2f5b39; background: #1c2b1e; padding: 2px 8px; border-radius: 999px; margin-left: 6px; }
textarea.auto-filled { border-color: #34d399 !important; box-shadow: 0 0 0 2px rgba(52, 211, 153, 0.2); }
.ws-missing-hint {
background: #2b231c; border: 1px solid #b45309; border-radius: 10px;
padding: 12px 14px; margin-top: 12px; font-size: 13px; color: #fcd34d;
}
.ws-missing-hint ul { margin: 8px 0 0; padding-left: 18px; color: #fde68a; }
.ws-missing-hint li { margin: 4px 0; }
/* Tabs Navigation */
.tabs-nav {
display: flex;
gap: 8px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border);
padding-bottom: 8px;
flex-wrap: wrap;
}
.tab-btn {
background: transparent;
border: 1px solid transparent;
color: var(--muted);
padding: 10px 16px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.25s;
display: flex;
align-items: center;
gap: 8px;
border-radius: 10px;
outline: none;
}
.tab-btn:hover {
color: var(--text);
background: var(--panel2);
}
.tab-btn.active {
color: #fff;
background: var(--panel2);
border-color: var(--border);
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.15);
}
.tab-num {
width: 22px;
height: 22px;
border-radius: 50%;
background: var(--border);
display: grid;
place-items: center;
font-size: 12px;
font-weight: 700;
color: var(--muted);
transition: all 0.25s;
}
.tab-btn.active .tab-num {
background: linear-gradient(135deg, var(--accent), var(--accent2));
color: #fff;
}
/* Tab Panes */
.tab-pane {
display: none;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.tab-pane.active {
display: block;
animation: fadeIn 0.3s ease-out forwards;
}
</style>
</head>
<body>
<div class="wrap">
<h1>鎶栭煶鍑璇侀噰闆嗗伐鍏 <span class="pill">鍦拌繍琛 路 涓嶄笂浼犱换浣曟暟鎹</span></h1>
<p class="sub">
鍦ㄤ綘<strong>鍦扮數鑴</strong>鐨勬祻瑙堝櫒閲岀櫥褰曟姈闊崇綉椤电増锛屾寜涓嬮潰姝ラら噰闆嗗嚟璇侊紝鐢熸垚鍙鐩存帴瀵煎叆绯荤粺鐨 JSON銆
瑙e喅鏈嶅姟鍣锛圠inux/鏃犵晫闈锛夋壂鐮佺櫥褰曞脊涓嶅嚭浜岀淮鐮佺殑闂棰樸
</p>
<div class="tabs-nav">
<button id="tab-btn-1" class="tab-btn active" onclick="switchTab(1)">
<span class="tab-num">1</span>
<span class="tab-txt">1. 鐧诲綍缃戦〉鐗</span>
</button>
<button id="tab-btn-2" class="tab-btn" onclick="switchTab(2)">
<span class="tab-num">2</span>
<span class="tab-txt">2. 鐙绔嬫彃浠堕噰闆 (鎺ㄨ崘)</span>
</button>
<button id="tab-btn-3" class="tab-btn" onclick="switchTab(3)">
<span class="tab-num">3</span>
<span class="tab-txt">3. 鎵嬪姩澶嶅埗 Cookie (澶囩敤)</span>
</button>
<button id="tab-btn-4" class="tab-btn" onclick="switchTab(4)">
<span class="tab-num">4</span>
<span class="tab-txt">4. 閲囬泦涓庣敓鎴</span>
</button>
</div>
<!-- TAB PANE 1 -->
<div id="tab-pane-1" class="tab-pane active">
<!-- STEP 1 -->
<div class="card">
<div class="step-h"><span class="badge">1</span> 鐧诲綍鎶栭煶缃戦〉鐗</div>
<p class="tip">
鐢ㄦ湰鍦 Chrome / Edge 鎵撳紑 <code class="k">https://www.douyin.com</code><strong>鐮佺櫥褰</strong>
鐒跺悗<strong>鎵撳紑涓娆°佷俊銆嶉〉闈</strong>锛堣╁畨鍏 SDK 鍐欏叆绛惧悕鍑璇侊級銆備繚鎸佽ユ爣绛鹃〉鎵撳紑銆
</p>
</div>
<div class="row" style="margin-top:20px; justify-content: flex-end;">
<button onclick="switchTab(2)">涓嬩竴姝ワ細鐙绔嬫彃浠堕噰闆</button>
</div>
</div>
<!-- TAB PANE 2 -->
<div id="tab-pane-2" class="tab-pane">
<div class="card">
<div class="step-h"><span class="badge">2</span> 浣跨敤鐙绔嬫祻瑙堝櫒鎻掍欢锛堜竴閿鑾峰彇鎵鏈夊嚟璇侊紝鏃犱换浣曠涓夋柟渚濊禆锛</div>
<p class="tip">
鐢变簬瀹夊叏闄愬埗锛屾姈闊崇綉椤电増鐨 <code class="k">sessionid</code> HttpOnly 鐨勶紝鏅閫氳剼鏈鏃犳硶鐩存帴璇诲彇銆
鎴戜滑涓轰綘鎻愪緵涓鏋佺畝鐨**鐙绔嬫祻瑙堝櫒鎻掍欢**锛屽姞杞藉悗浼氬湪鎶栭煶缃戦〉鍙充笅瑙掔敓鎴愪竴閿閲囬泦鎸夐挳锛岃嚜鍔ㄦ彁鍙栧寘鍚 HttpOnly 鍦ㄥ唴鐨勬墍鏈夊嚟璇佸苟鎵撳寘澶嶅埗銆
</p>
<div class="hint-box" style="background:#1e1b3a; border-color:#3b2f6b; padding:16px;">
<strong style="color: var(--ok); display: block; margin-bottom: 6px;">💡 系统已自动在本地创建插件目录,无需手动下载!</strong>
<p class="tip" style="margin-top:4px; color: var(--text); font-weight: 500;">
该插件的所有文件已保存在项目根目录的 <code class="k">douyin-extension</code> 文件夹中。你无需点击下方按钮下载,可直接进行下一步。
</p>
<div style="border-top: 1px dashed var(--border); margin: 12px 0 0; padding-top: 12px;">
<strong>备用方案:下载插件文件到本地(非本地运行或远程使用时)</strong>
<p class="tip" style="margin-top:6px;">在本地电脑新建一个文件夹(例如命名为 <code class="k">douyin-plugin</code>),依次点击下方三个按钮下载文件,并全部保存到该文件夹中:</p>
<div class="row" style="margin-top:12px; gap:12px;">
<button onclick="downloadPluginFile('manifest.json')">1. 下载 manifest.json</button>
<button onclick="downloadPluginFile('background.js')">2. 下载 background.js</button>
<button onclick="downloadPluginFile('content.js')">3. 下载 content.js</button>
</div>
</div>
</div>
<ol style="margin-top: 16px;">
<li>鎵撳紑 Chrome 鎴 Edge 娴忚堝櫒锛屽湪鍦板潃鏍忚緭鍏 <code class="k">chrome://extensions/</code> (鎴 <code class="k">edge://extensions/</code>) 骞跺洖杞︺</li>
<li>鍦ㄦ墿灞曠▼搴忕$悊椤甸潰鐨勫彸涓婅掞紝寮 **銆屽紑鍙戣呮ā寮忋** 鍒囨崲寮鍏炽</li>
<li>鐐瑰嚮宸︿笂瑙掔殑 **銆屽姞杞藉凡瑙e帇鐨勬墿灞曠▼搴忋** (Load unpacked)锛岄夋嫨浣犲垰鍒氬垱寤哄苟瀛樺叆閭 3 涓鏂囦欢鐨 <code class="k">douyin-plugin</code> 鏂囦欢澶广</li>
<li>鍒锋柊浣<strong>宸茬櫥褰曟姈闊崇殑缃戦〉鏍囩鹃〉</strong>锛岄〉闈㈠彸涓嬭掍細娴鐜颁竴涓 <code class="k">馃搶 涓閲囬泦鍑</code> 鎸夐挳锛岀偣鍑诲畠銆</li>
<li>璇佸皢琚鍔ㄩ噰闆嗗苟澶嶅埗鍒板壀璐存澘锛岄殢鍚庣洿鎺ョ矘璐村埌涓嬫柟銆屾 4锛氶噰闆嗕笌鐢熸垚銆嶇殑杈撳叆妗嗗嵆鍙</li>
</ol>
<div class="hint-box" style="background:#1c2b1e; border-color:#2f5b39; margin-top:14px;">
<strong style="color:var(--ok);"> 瀹夊叏涓庣佸瘑淇濊瘉</strong>锛氳ユ彃浠跺畬鍏ㄨ繍琛屽湪浣犵殑鏈鍦版祻瑙堝櫒锛屾棤浠讳綍澶栭儴杩炴帴锛岀函鏈鍦版彁鍙栵紝鏃犻渶瀹夎涓夋柟娌圭尨鎻掍欢銆
</div>
</div>
<div class="row" style="margin-top:20px; justify-content: space-between;">
<button class="ghost" onclick="switchTab(1)">涓婁竴姝</button>
<button onclick="switchTab(4)">涓嬩竴姝ワ細閲囬泦涓庣敓鎴</button>
</div>
</div>
<!-- TAB PANE 3 -->
<div id="tab-pane-3" class="tab-pane">
<!-- STEP 2 -->
<div class="card">
<div class="step-h"><span class="badge">3</span> 澶囩敤鏂规堬細鎵嬪姩浠庣綉缁滆锋眰澶嶅埗 Cookie</div>
<p class="tip">
鑻ヤ笉鏂逛究瀹夎呮补鐚存彃浠讹紝鍙鎵嬪姩浠庡紑鍙戣呭伐鍏凤紙F12锛夌殑缃戠粶璇锋眰澶村嶅埗鍖呭惈 sessionid 鐨勫畬鏁 Cookie锛
</p>
<ol>
<li>鍦ㄦ姈闊抽〉闈㈡寜 <code class="k">F12</code> 鍒囧埌 <strong>Network锛堢綉缁滐級</strong> 闈㈡澘</li>
<li> Filter 杩囨护妗嗕腑杈撳叆 <code class="k">user_detail</code> <code class="k">douyin.com</code> 骞跺埛鏂伴〉闈</li>
<li>鍦ㄨ锋眰鍒楄〃閲岀偣鍑诲瑰簲鐨勮锋眰锛堝 <code class="k">user_detail/?aid=...</code></li>
<li>鎵惧埌 鍙充晶 <strong>Request Headers锛堣锋眰鏍囧ご锛</strong> 閲岀殑 <code class="k">Cookie:</code> 杩欎竴琛</li>
<li> <code class="k">Cookie:</code> 鍚庨潰<strong>鏁存</strong>澶嶅埗锛堟垨鑰呭彸閿璇ヨ锋眰 -> Copy -> Copy request headers锛夛紝绮樿创鍒颁笅闈</li>
</ol>
<div class="hint-box">
绮樿创鍐呭瑰簲绫讳技锛<code class="k">ttwid=1%7C...; sessionid=xxxx; sessionid_ss=xxxx; sid_guard=...; uid_tt=...; ...</code>
鈥斺 蹇呴』鍖呭惈 <strong>sessionid</strong>
</div>
<textarea id="cookieInput" placeholder="鍦ㄦょ矘璐村畬鏁 Cookie 璇锋眰澶寸殑鍊硷紝鎴栨暣娈 Request Headers锛堝伐鍏蜂細鑷鍔ㄤ粠涓鎻愬彇 Cookie锛"></textarea>
</div>
<div class="row" style="margin-top:20px; justify-content: space-between;">
<button class="ghost" onclick="switchTab(2)">涓婁竴姝</button>
<button onclick="switchTab(4)">涓嬩竴姝ワ細閲囬泦涓庣敓鎴</button>
</div>
</div>
<!-- TAB PANE 4 -->
<div id="tab-pane-4" class="tab-pane">
<!-- STEP 3 -->
<div class="card">
<div class="step-h"><span class="badge">4</span> 閲囬泦涓庣敓鎴</div>
<p class="tip">
<b>娌圭尨鑴氭湰閲囬泦鐨 `DYCRED1.` 瀵嗘枃</b>锛屾垨鑰<b>涔︾/鎺у埗鍙板煎嚭鐨 localStorage JSON</b> 绮樿创鍒颁笅鏂硅緭鍏ユ嗭細
</p>
<div class="hint-box" style="background:#1c2b1e;border-color:#2f5b39;">
<strong>鏂规 B锛氫功绛惧皬宸ュ叿锛堜綔涓烘墜鍔ㄦ柟妗堢殑 localStorage 杈呭姪閲囬泦锛夛細</strong>
鎶婁笅闈㈣繖涓鎸夐挳<strong>鎷栧埌娴忚堝櫒涔︾炬爮</strong>
鍦ㄦ姈闊崇佷俊椤电偣鍑讳袱娆★紝缁撴灉澶嶅埗鍒板壀璐存澘鍚庣矘璐村埌涓嬫柟鍗冲彲锛圵S 浼氳嚜鍔ㄥ~鍏ユ 鈽咃級銆
<div class="row" style="margin-top:10px;">
<a id="bookmarklet" class="pill" style="padding:8px 16px;color:#fff;background:linear-gradient(135deg,var(--accent),var(--accent2));text-decoration:none;cursor:grab;">馃搶 鎶栭煶鍑璇侀噰闆嗭紙鎷栨垜鍒颁功绛炬爮锛</a>
</div>
</div>
<details style="margin-top: 16px; border: 1px dashed var(--border); border-radius: 10px; padding: 12px 14px; background: rgba(0,0,0,0.15);">
<summary style="font-size: 13.5px; font-weight: 600; cursor: pointer; color: var(--muted); outline: none; user-select: none;">
馃挕 鏂规 C锛氫娇鐢ㄦ祻瑙堝櫒鎺у埗鍙伴噰闆嗭紙鐐瑰嚮灞曞紑 / 鏀惰捣锛
</summary>
<p class="tip" style="margin-top:10px;">
鍒囧埌 <strong>Console锛堟帶鍒跺彴锛</strong>锛岀矘璐翠笅闈㈣繖娈靛苟鍥炶溅锛堜細鑷鍔ㄥ嶅埗缁撴灉鍒板壀璐存澘锛夈
</p>
<div class="snippet" id="snippet" style="max-height: 150px; overflow-y: auto;"></div>
<div class="row">
<button class="ghost" onclick="copyText(document.getElementById('snippet').innerText,'宸插嶅埗閲囬泦鑴氭湰')">澶嶅埗閲囬泦鑴氭湰</button>
</div>
</details>
<p class="tip">鎶婇噰闆嗗埌鐨勫唴瀹癸紙`DYCRED1.` 瀵嗘枃鎴 JSON锛夌矘璐村埌涓嬮潰锛屽伐鍏蜂細鑷鍔ㄨ瘑鍒骞剁敓鎴愶細</p>
<textarea id="lsInput" placeholder='鍦ㄦょ矘璐撮噰闆嗗埌鐨勫唴瀹癸紙DYCRED1.xxx 瀵嗘枃锛屾垨 {"localStorage":{...}} JSON锛'></textarea>
<div id="wsParseHint" class="ws-missing-hint" style="display:none;">
<strong>鈿狅笍 鏈璇嗗埆鍒 WebSocket 杩炴帴</strong>
<ul>
<li>涔︾剧粨鏋滈噷娌℃湁 <code class="k">frontier_ws_url</code>锛岃峰湪鎶栭煶<strong>绉佷俊椤</strong>锛欶12 鈫 Network 鈫 杩囨护 <code class="k">WS</code> 鎵惧埌 <code class="k">frontier</code> / <code class="k">ws/v2</code> 鍙抽敭 Copy URL</li>
<li>灏嗗嶅埗鐨 <code class="k">wss://...</code> 绮樿创鍒<strong>妗嗘湯灏炬崲琛</strong>锛屾垨鐩存帴绮樿创鍒颁笅鏂广 鈽呫</li>
<li>鎴栧湪绉佷俊椤<strong>鍏堢偣涔︾</strong> 鍒锋柊绉佷俊椤 WS 杩炴帴鍚庡啀<strong>鐐逛竴娆′功绛</strong>閲嶆柊閲囬泦</li>
</ul>
</div>
</div>
<!-- STEP 3.5 -->
<div class="card">
<div class="step-h"><span class="badge" style="background:linear-gradient(135deg,#e08c2f,#e0492f);"></span> 绉佷俊 WebSocket 杩炴帴 <span class="ws-tag">鑴氭湰鍙鍔ㄦ姄鍙</span></div>
<div class="hint-box" style="background:#2b231c;border-color:#5b462f;">
涓嬫柟鍐呭圭敱<strong>姝ラ 4 绮樿创鍐呭规椂鑷鍔ㄨ瘑鍒</strong>
濡傛灉鏈璇嗗埆鍒帮紝鍙鎵嬪姩锛欶12 鈫 Network 鈫 WS 鈫 鎵惧埌 <code class="k">frontier</code> Copy URL 骞剁矘璐淬
</div>
<textarea id="wsInput" placeholder="绮樿创 wss://frontier-im.douyin.com/ws/v2?token=...&sdk_cert=...&ts_sign=... 瀹屾暣 URL" style="min-height:90px; margin-bottom:12px;"></textarea>
<p class="tip">
<strong>鎶栭煶鏁板瓧 UID锛</strong>锛堝缓璁鍐欙紝浠ヨ勯伩浜戠 IP 鏌ヨ庢帶锛
</p>
<input type="text" id="uidInput" placeholder="渚嬪傦細869032150442612锛堜竴閿閲囬泦浼氳嚜鍔ㄥ~鍏咃級" style="width:100%;height:38px;background:#0c0d1a;color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0 12px;outline:none;font-size:13.5px;transition:border-color .15s;" />
</div>
<!-- STEP 4 -->
<div id="step4Card" class="card">
<div class="step-h"><span class="badge">4</span> 鐢熸垚骞跺煎叆</div>
<div class="row">
<button onclick="generate()">鐢熸垚鍑 JSON</button>
<button class="ghost" onclick="copyText(document.getElementById('output').value,'宸插嶅埗鍑 JSON')">澶嶅埗缁撴灉</button>
</div>
<div class="checks" id="checks"></div>
<textarea id="output" class="out" placeholder="鐢熸垚鐨 storage_state JSON 浼氬嚭鐜板湪杩欓噷" style="margin-top:12px;"></textarea>
<div class="hint-box" style="margin-top:14px;">
<strong>瀵煎叆姝ラわ細</strong>鍥炲埌绯荤粺 鈫 璐﹀彿绠$悊 鈫 瀵瑰簲璐﹀彿鐐广岀紪杈戙嶁啋 鎶婁笂闈㈢殑 JSON 绮樿创杩 <strong>Cookie</strong> 淇濆瓨 鈫
鍐嶇偣銆屽惎鍔ㄦ墭绠°傜郴缁熶細鐩存帴 IM 鐩磋繛锛屼笉鍐嶉渶瑕佸湪鏈嶅姟鍣ㄤ笂鎵鐮併
</div>
</div>
<div class="row" style="margin-top:20px;">
<button class="ghost" onclick="switchTab(3)">涓婁竴姝</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script>
function switchTab(idx) {
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.tab-pane').forEach(pane => pane.classList.remove('active'));
document.getElementById('tab-btn-' + idx)?.classList.add('active');
document.getElementById('tab-pane-' + idx)?.classList.add('active');
}
const LS_KEYS = [
"security-sdk/s_sdk_crypt_sdk",
"security-sdk/s_sdk_sign_data_key/web_protect",
"tea_cache_tokens",
"web_runtime_security_uid"
];
// 鍦ㄦ姈闊抽〉闈㈠畨瑁 WebSocket 閽╁瓙锛屾姄鍙 IM /ws/v2 杩炴帴 URL
const WS_HOOK_CODE = `(function(){
function __dyIsImWs(u){
u=String(u||'');
return u&&/\\/ws\\/v2/i.test(u)&&/[?&]token=/.test(u)&&(/frontier/i.test(u)||/zijieapi\\.com/i.test(u));
}
function __dySaveWs(u){
if(!__dyIsImWs(u))return;
var a=[];try{a=JSON.parse(sessionStorage.getItem('__dy_captured_ws')||'[]');}catch(e){}
if(a.indexOf(u)<0)a.unshift(u);
sessionStorage.setItem('__dy_captured_ws',JSON.stringify(a.slice(0,5)));
}
if(window.__dyWsHookInstalled)return;
window.__dyWsHookInstalled=1;
var O=window.WebSocket;
if(!O)return;
try {
var origSend = O.prototype.send;
O.prototype.send = function() {
try{__dySaveWs(this.url);}catch(e){}
return origSend.apply(this, arguments);
};
} catch(e){}
try {
var desc = Object.getOwnPropertyDescriptor(O.prototype, 'readyState');
if (desc && desc.get) {
var origGet = desc.get;
Object.defineProperty(O.prototype, 'readyState', {
get: function() {
try{__dySaveWs(this.url);}catch(e){}
return origGet.apply(this, arguments);
},
configurable: true,
enumerable: true
});
}
} catch(e){}
function W(u,p){
try{__dySaveWs(String(u||''));}catch(e){}
return arguments.length>1?new O(u,p):new O(u);
}
W.prototype=O.prototype;
Object.keys(O).forEach(function(k){try{W[k]=O[k];}catch(e){}});
['CONNECTING','OPEN','CLOSING','CLOSED'].forEach(function(k){if(k in O)W[k]=O[k];});
window.WebSocket=W;
try{
new PerformanceObserver(function(list){
list.getEntries().forEach(function(e){__dySaveWs(e.name);});
}).observe({entryTypes:['resource']});
}catch(e){}
})();`;
// 鍥炴函 performance / sessionStorage 閲屽凡寤虹珛鐨 IM WS
const WS_COLLECT_CODE = `(function(){
function __dyIsImWs(u){
u=String(u||'');
return u&&/\\/ws\\/v2/i.test(u)&&/[?&]token=/.test(u)&&(/frontier/i.test(u)||/zijieapi\\.com/i.test(u));
}
function __dyCollectWsUrls(){
var found=[];
function add(u){
u=String(u||'');
if(!__dyIsImWs(u))return;
if(found.indexOf(u)<0)found.unshift(u);
}
try{(performance.getEntries()||[]).forEach(function(e){add(e.name);});}catch(e){}
try{
var stored=JSON.parse(sessionStorage.getItem('__dy_captured_ws')||'[]');
if(Array.isArray(stored))stored.forEach(add);
}catch(e){}
try{sessionStorage.setItem('__dy_captured_ws',JSON.stringify(found.slice(0,5)));}catch(e){}
return found;
}
window.__dyCollectWsUrls=__dyCollectWsUrls;
window.__dyIsImWs=__dyIsImWs;
return __dyCollectWsUrls();
})();`;
function showWsMissingHint(show) {
const el = document.getElementById('wsParseHint');
if (el) el.style.display = show ? 'block' : 'none';
}
function looksLikeBookmarkDump(raw) {
const text = (raw || '').trim();
if (text.length < 80) return false;
return text.includes('"localStorage"') || text.includes("'localStorage'") || (text.startsWith('{') && text.includes('cookie'));
}
function applyDumpToForm(d, raw, forceOverwrite) {
const ws = resolveWsFromDump(d, raw);
const wsEl = document.getElementById('wsInput');
const uidEl = document.getElementById('uidInput');
const cookieEl = document.getElementById('cookieInput');
const existingWs = (wsEl.value || '').trim();
if (d && d.cookie) {
if (forceOverwrite || !cookieEl.value.trim()) {
cookieEl.value = d.cookie;
}
}
if (d && d.my_uid) {
if (forceOverwrite || !uidEl.value.trim()) {
uidEl.value = d.my_uid;
}
}
if (ws) {
showWsMissingHint(false);
const uidFromWs = uidFromWsUrl(ws);
if (uidFromWs) {
if (forceOverwrite || !uidEl.value.trim()) {
uidEl.value = uidFromWs;
}
}
if (forceOverwrite || wsEl.value !== ws) {
const isChanged = wsEl.value !== ws;
wsEl.value = ws;
if (isChanged) {
wsEl.classList.add('auto-filled');
setTimeout(() => wsEl.classList.remove('auto-filled'), 1800);
toast('宸茶嚜鍔ㄨ瘑鍒 WebSocket 骞跺~鍏ユ');
}
}
return true;
}
if (existingWs && isImWsUrl(existingWs)) {
showWsMissingHint(false);
return true;
}
if (looksLikeBookmarkDump(raw)) {
showWsMissingHint(true);
toastWarn('鏈璇嗗埆鍒 WebSocket锛氳剼鏈缁撴灉涓嶅惈 WS 杩炴帴锛岃锋煡鐪嬫 4 涓嬫柟鎻愮ず');
} else {
showWsMissingHint(false);
}
return false;
}
function syncDumpFieldsFromLsInput() {
const raw = document.getElementById('lsInput').value;
applyDumpToForm(normalizeDump(raw), raw, true);
generate();
}
// 鎺у埗鍙伴噰闆嗚剼鏈锛氬叏閲 dump localStorage + 瀹夎 WS 鐩戝惉 + 寮圭獥杈呭姪澶嶅埗
const SNIPPET_CODE = `(function(){
${WS_HOOK_CODE}
${WS_COLLECT_CODE}
var o = { localStorage: Object.assign({}, localStorage), cookie: document.cookie, my_uid: '' };
try{
var wsArr=JSON.parse(sessionStorage.getItem('__dy_captured_ws')||'[]');
if(wsArr&&wsArr.length){ o.ws_urls=wsArr; o.frontier_ws_url=wsArr[0]; }
}catch(e){}
var wsTip = o.frontier_ws_url ? ('\\n宸叉姄鍙 WebSocket: ' + o.frontier_ws_url.slice(0,72) + '...') : '\\n鏈鎶撳埌 WS锛氳峰埛鏂扮佷俊椤靛悗閲嶆柊杩愯岋紱鎴栨妸 Network 閲屽嶅埗鐨 wss URL 杩藉姞绮樿创鍒伴噰闆嗗伐鍏锋 3';
var s = JSON.stringify(o);
try { copy(s); console.log("宸插嶅埗鍒板壀璐存澘" + wsTip); } catch(e){ console.log(s); }
var div = document.createElement('div');
div.style = "position:fixed;top:15%;left:50%;transform:translateX(-50%);z-index:999999;background:#1a1b2e;color:#e6e6f0;padding:20px;border:2px solid #8b5cf6;border-radius:14px;box-shadow:0 10px 30px rgba(0,0,0,0.8);width:90%;max-width:550px;font-family:sans-serif;text-align:left;line-height:1.5;";
div.innerHTML = "<h3 style='margin:0 0 8px;color:#a855f7;font-size:16px;'>馃搶 鎺у埗鍙板嚟璇侀噰闆嗘垚鍔</h3>" +
"<p style='margin:0 0 12px;font-size:13px;color:#9aa0c0;'>宸插畨瑁 WS 鐩戝惉骞跺皾璇曡嚜鍔ㄥ嶅埗銆" + wsTip.replace(/\\n/g,'<br/>') + "</p>" +
"<textarea id='dy_copy_area' style='width:100%;height:140px;background:#0c0d1a;color:#cbd5e1;border:1px solid #2c2e4a;border-radius:8px;padding:8px;font-family:monospace;font-size:12px;outline:none;resize:none;' readonly>" + s + "</textarea>" +
"<div style='margin-top:14px;display:flex;justify-content:flex-end;gap:10px;'>" +
"<button id='dy_btn_copy' style='background:#8b5cf6;color:#fff;border:none;border-radius:8px;padding:8px 16px;cursor:pointer;font-weight:600;font-size:13px;'>澶嶅埗鏂囨湰</button>" +
"<button id='dy_btn_close' style='background:transparent;color:#9aa0c0;border:1px solid #2c2e4a;border-radius:8px;padding:8px 16px;cursor:pointer;font-size:13px;'>鍏抽棴</button>" +
"</div>";
document.body.appendChild(div);
var txt = document.getElementById('dy_copy_area');
document.getElementById('dy_btn_copy').onclick = function(){
txt.select();
document.execCommand('copy');
this.innerText = '宸插嶅埗锛';
setTimeout(function(){ document.getElementById('dy_btn_copy').innerText = '澶嶅埗鏂囨湰'; }, 1000);
};
document.getElementById('dy_btn_close').onclick = function(){
div.remove();
};
})()`;
const SNIPPET = SNIPPET_CODE;
document.getElementById('snippet').innerText = SNIPPET;
// 涔︾惧皬宸ュ叿锛氬叏閲 dump localStorage + cookie + WS 鐩戝惉 + 寮傛 fetch UID + 寤惰繜杞 + 寮圭獥杈呭姪澶嶅埗
const BOOKMARKLET_CODE = `(function(){
${WS_HOOK_CODE}
${WS_COLLECT_CODE}
var o = { localStorage: Object.assign({}, localStorage), cookie: document.cookie, my_uid: '' };
try{
var wsArr=JSON.parse(sessionStorage.getItem('__dy_captured_ws')||'[]');
if(wsArr&&wsArr.length){ o.ws_urls=wsArr; o.frontier_ws_url=wsArr[0]; }
}catch(e){}
function refreshWs(){
try{
if(window.__dyCollectWsUrls)window.__dyCollectWsUrls();
var wsArr=JSON.parse(sessionStorage.getItem('__dy_captured_ws')||'[]');
if(wsArr&&wsArr.length){ o.ws_urls=wsArr; o.frontier_ws_url=wsArr[0]; }
else { delete o.ws_urls; o.frontier_ws_url=''; }
}catch(e){}
}
function done(){
refreshWs();
var s = JSON.stringify(o);
var tip = o.my_uid ? ('\\n(已自动提取到抖音数字 UID: ' + o.my_uid + ')') : '\\n(未获取到 UID,可在采集工具中手动输入)';
var wsTip = o.frontier_ws_url ? ('\\n(已抓取 WebSocket 私信连接)') : '\\n(未抓到 WSNetwork→WS→Copy URL,粘贴到采集工具步骤3末尾或步骤★)';
tip += wsTip;
try {
navigator.clipboard.writeText(s);
} catch(e){}
var div = document.createElement('div');
div.style = "position:fixed;top:15%;left:50%;transform:translateX(-50%);z-index:999999;background:#1a1b2e;color:#e6e6f0;padding:20px;border:2px solid #8b5cf6;border-radius:14px;box-shadow:0 10px 30px rgba(0,0,0,0.8);width:90%;max-width:550px;font-family:sans-serif;text-align:left;line-height:1.5;";
div.innerHTML = "<h3 style='margin:0 0 8px;color:#a855f7;font-size:16px;'>📌 控制台凭证采集成功</h3>" +
"<p style='margin:0 0 12px;font-size:13px;color:#9aa0c0;'>已尝试自动复制" + tip.replace(/\\n/g,'<br/>') + "。若粘贴失败,请点击下方按钮复制或手动复制框内文本:</p>" +
"<textarea id='dy_copy_area' style='width:100%;height:140px;background:#0c0d1a;color:#cbd5e1;border:1px solid #2c2e4a;border-radius:8px;padding:8px;font-family:monospace;font-size:12px;outline:none;resize:none;' readonly>" + s + "</textarea>" +
"<div style='margin-top:14px;display:flex;justify-content:flex-end;gap:10px;'>" +
"<button id='dy_btn_copy' style='background:#8b5cf6;color:#fff;border:none;border-radius:8px;padding:8px 16px;cursor:pointer;font-weight:600;font-size:13px;'>复制文本</button>" +
"<button id='dy_btn_close' style='background:transparent;color:#9aa0c0;border:1px solid #2c2e4a;border-radius:8px;padding:8px 16px;cursor:pointer;font-size:13px;'>关闭</button>" +
"</div>";
document.body.appendChild(div);
var txt = document.getElementById('dy_copy_area');
document.getElementById('dy_btn_copy').onclick = function(){
txt.select();
document.execCommand('copy');
this.innerText = '已复制!';
setTimeout(function(){ document.getElementById('dy_btn_copy').innerText = '复制文本'; }, 1000);
};
document.getElementById('dy_btn_close').onclick = function(){
div.remove();
};
}
var fetchedUid = false;
var elapsed = 0;
var maxWait = 3500;
var interval = 200;
function tryFinish() {
refreshWs();
if ((o.frontier_ws_url && fetchedUid) || elapsed >= maxWait) {
done();
} else {
elapsed += interval;
setTimeout(tryFinish, interval);
}
}
fetch('/aweme/v1/web/query/user/')
.then(function(r){ return r.json(); })
.then(function(data){
if(data && data.user_uid){ o.my_uid = String(data.user_uid); }
fetchedUid = true;
})
.catch(function(){
fetch('/aweme/v1/creator/user/info/')
.then(function(r){ return r.json(); })
.then(function(data){
if(data && data.creator_user_id){ o.my_uid = String(data.creator_user_id); }
fetchedUid = true;
})
.catch(function(){ fetchedUid = true; });
});
setTimeout(tryFinish, 0);
})();`;
const BOOKMARKLET = "javascript:" + encodeURIComponent(BOOKMARKLET_CODE.replace(/\s+/g, ' '));
document.getElementById('bookmarklet').setAttribute('href', BOOKMARKLET);
const onst MANIFEST_JSON = `{
"manifest_version": 3,
"name": "鎶栭煶鍑璇佸姪鎵",
"version": "1.0",
"description": "鐙绔嬭幏鍙栨姈闊冲厤鎵鐮佸嚟璇侊紙鍚 HttpOnly sessionid銆亀eb_protect銆乲eys 鍜 WebSocket 杩炴帴锛",
"permissions": [
"cookies"
],
"host_permissions": [
"https://*.douyin.com/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["https://*.douyin.com/*"],
"js": ["content.js"],
"run_at": "document_start"
}
]
}`;
const BACKGROUND_JS = [
'chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {',
' if (message.action === "get_cookies") {',
' chrome.cookies.getAll({ url: sender.tab.url }, (cookies) => {',
' if (chrome.runtime.lastError) {',
' sendResponse({ error: chrome.runtime.lastError.message });',
' } else {',
' const cookieStr = cookies.map(c => c.name + "=" + c.value).join("; ");',
' sendResponse({ cookie: cookieStr });',
' }',
' });',
' return true;',
' }',
'});'
].join('\\n');
const CONTENT_JS = [
'(function() {',
' \\'use strict\\';',
'',
' // 1. WebSocket Hook 閫昏緫锛堟敞鍏ュ埌 main world锛',
' const WS_HOOK_CODE = `(function(){',
' function __dyIsImWs(u){',
' u=String(u||"");',
' return u&&/\\\\\\\\/ws\\\\\\\\/v2/i.test(u)&&/[?&]token=/.test(u)&&(/frontier/i.test(u)||/zijieapi\\\\\\\\.com/i.test(u));',
' }',
' function __dySaveWs(u){',
' if(!__dyIsImWs(u))return;',
' var a=[];try{a=JSON.parse(sessionStorage.getItem("__dy_captured_ws")||"[]");}catch(e){}',
' if(a.indexOf(u)<0)a.unshift(u);',
' sessionStorage.setItem("__dy_captured_ws",JSON.stringify(a.slice(0,5)));',
' }',
' if(window.__dyWsHookInstalled)return;',
' window.__dyWsHookInstalled=1;',
' var O=window.WebSocket;',
' if(!O)return;',
' ',
' try {',
' var origSend = O.prototype.send;',
' O.prototype.send = function() {',
' try{__dySaveWs(this.url);}catch(e){}',
' return origSend.apply(this, arguments);',
' };',
' } catch(e){}',
' ',
' try {',
' var desc = Object.getOwnPropertyDescriptor(O.prototype, "readyState");',
' if (desc && desc.get) {',
' var origGet = desc.get;',
' Object.defineProperty(O.prototype, "readyState", {',
' get: function() {',
' try{__dySaveWs(this.url);}catch(e){}',
' return origGet.apply(this, arguments);',
' },',
' configurable: true,',
' enumerable: true',
' });',
' }',
' } catch(e){}',
'',
' function W(u,p){',
' try{__dySaveWs(String(u||""));}catch(e){}',
' return arguments.length>1?new O(u,p):new O(u);',
' }',
' W.prototype=O.prototype;',
' Object.keys(O).forEach(function(k){try{W[k]=O[k];}catch(e){}});',
' ["CONNECTING","OPEN","CLOSING","CLOSED"].forEach(function(k){if(k in O)W[k]=O[k];});',
' window.WebSocket=W;',
' try{',
' new PerformanceObserver(function(list){',
' list.getEntries().forEach(function(e){__dySaveWs(e.name);});',
' }).observe({entryTypes:["resource"]});',
' }catch(e){}',
' })();`;',
'',
' const script = document.createElement("script");',
' script.textContent = WS_HOOK_CODE;',
' (document.head || document.documentElement).appendChild(script);',
' script.remove();',
'',
' // 2. 椤甸潰鍔犺浇瀹屾垚鍚庢坊鍔犳偓娴鎸夐挳',
' if (document.readyState === "loading") {',
' window.addEventListener("load", initButton);',
' } else {',
' initButton();',
' }',
'',
' function initButton() {',
' if (document.getElementById("dy-credential-grabber-btn")) return;',
' var btn = document.createElement("div");',
' btn.id = "dy-credential-grabber-btn";',
' btn.innerHTML = "馃搶 涓閲囬泦鍑";',
' btn.style = "position:fixed;bottom:80px;right:24px;z-index:999999;background:linear-gradient(135deg,#8b5cf6,#a855f7);color:#fff;padding:12px 18px;border-radius:10px;font-weight:600;font-size:14px;cursor:pointer;box-shadow:0 4px 15px rgba(139,92,246,0.4);transition:all 0.2s;user-select:none;font-family:sans-serif;";',
' ',
' btn.addEventListener("mouseenter", function() {',
' btn.style.transform = "scale(1.05)";',
' btn.style.boxShadow = "0 6px 20px rgba(139,92,246,0.6)";',
' });',
' btn.addEventListener("mouseleave", function() {',
' btn.style.transform = "scale(1)";',
' btn.style.boxShadow = "0 4px 15px rgba(139,92,246,0.4)";',
' });',
'',
' btn.addEventListener("click", grabCredentials);',
' document.body.appendChild(btn);',
' }',
'',
' // 3. 閲囬泦涓婚昏緫',
' function grabCredentials() {',
' var btn = document.getElementById("dy-credential-grabber-btn");',
' if (btn) {',
' btn.innerHTML = "鈴 姝e湪閲囬泦...";',
' btn.style.background = "#4b5563";',
' }',
'',
' var ls = {};',
' for (var i = 0; i < localStorage.length; i++) {',
' var k = localStorage.key(i);',
' ls[k] = localStorage.getItem(k);',
' }',
'',
' var keys = "";',
' var web_protect = "";',
' var sec_uid = "";',
' var uid = "";',
'',
' for (var key in ls) {',
' var lk = key.toLowerCase();',
' if (lk.indexOf("crypt_sdk") >= 0) keys = ls[key];',
' if (lk.indexOf("web_protect") >= 0) web_protect = ls[key];',
' if (lk.indexOf("security_uid") >= 0 || lk.indexOf("runtime_security_uid") >= 0) sec_uid = ls[key];',
' if (lk.indexOf("tea_cache_tokens") >= 0) {',
' try {',
' var parsed = JSON.parse(ls[key]);',
' uid = String(parsed.user_unique_id || parsed.web_id || "");',
' } catch(e) {}',
' }',
' }',
' if (!sec_uid && uid) sec_uid = uid;',
'',
' var capturedWs = [];',
' try {',
' capturedWs = JSON.parse(sessionStorage.getItem("__dy_captured_ws") || "[]");',
' } catch(e) {}',
' var wsUrl = capturedWs[0] || "";',
'',
' var my_uid = uid;',
' var fetchPromises = [];',
'',
' if (!my_uid) {',
' fetchPromises.push(',
' fetch("/aweme/v1/web/query/user/")',
' .then(function(r) { return r.json(); })',
' .then(function(d) { if(d && d.user_uid) my_uid = String(d.user_uid); })',
' .catch(function() {})',
' );',
' fetchPromises.push(',
' fetch("/aweme/v1/creator/user/info/")',
' .then(function(r) { return r.json(); })',
' .then(function(d) { if(d && d.creator_user_id) my_uid = String(d.creator_user_id); })',
' .catch(function() {})',
' );',
' }',
'',
' Promise.all(fetchPromises).then(function() {',
' chrome.runtime.sendMessage({ action: "get_cookies" }, function(response) {',
' if (!response || response.error) {',
' showToast("鉂 鑾峰彇 Cookie 澶辫触: " + ((response && response.error) || "鏈鍝嶅簲"), "err");',
' resetBtn();',
' return;',
' }',
'',
' var cookieStr = response.cookie;',
'',
' var data = {',
' cookie: cookieStr,',
' web_protect: web_protect,',
' keys: keys,',
' ua: navigator.userAgent,',
' sec_uid: sec_uid,',
' nickname: "",',
' unique_id: my_uid || "",',
' frontier_ws_url: wsUrl,',
' ws_urls: capturedWs',
' };',
'',
' var payloadStr = JSON.stringify(data);',
' var base64Payload = btoa(unescape(encodeURIComponent(payloadStr)));',
' var finalResult = "DYCRED1." + base64Payload;',
'',
' try {',
' navigator.clipboard.writeText(finalResult).then(function() {',
' showToast("馃帀 鍑璇侀噰闆嗘垚鍔燂紒宸茶嚜鍔ㄥ嶅埗鍒板壀璐存澘銆", "ok");',
' }).catch(function() {',
' fallbackCopy(finalResult);',
' });',
' } catch(e) {',
' fallbackCopy(finalResult);',
' }',
' resetBtn();',
' });',
' });',
' }',
'',
' function fallbackCopy(text) {',
' var ta = document.createElement("textarea");',
' ta.value = text;',
' document.body.appendChild(ta);',
' ta.select();',
' document.execCommand("copy");',
' ta.remove();',
' showToast("馃帀 鍑璇侀噰闆嗘垚鍔燂紒宸叉墜鍔ㄥ嶅埗鍒板壀璐存澘銆", "ok");',
' }',
'',
' function resetBtn() {',
' var btn = document.getElementById("dy-credential-grabber-btn");',
' if (btn) {',
' btn.innerHTML = "馃搶 涓閲囬泦鍑";',
' btn.style.background = "linear-gradient(135deg,#8b5cf6,#a855f7)";',
' }',
' }',
'',
' function showToast(msg, type) {',
' var toast = document.createElement("div");',
' toast.style = "position:fixed;top:10%;left:50%;transform:translateX(-50%);z-index:9999999;padding:14px 24px;border-radius:12px;color:#fff;font-weight:600;font-size:14px;box-shadow:0 8px 30px rgba(0,0,0,0.5);font-family:sans-serif;line-height:1.4;";',
' if (type === "ok") {',
' toast.style.background = "#059669";',
' toast.style.border = "1px solid #34d399";',
' } else {',
' toast.style.background = "#dc2626";',
' toast.style.border = "1px solid #f87171";',
' }',
' toast.innerHTML = msg;',
' document.body.appendChild(toast);',
' setTimeout(function() {',
' toast.style.opacity = "0";',
' toast.style.transition = "opacity 0.4s";',
' setTimeout(function() { toast.remove(); }, 400);',
' }, 3000);',
' }',
'})();'
].join('\\n');
function downloadPluginFile(filename) {
let content = "";
if (filename === 'manifest.json') content = MANIFEST_JSON;
else if (filename === 'background.js') content = BACKGROUND_JS;
else if (filename === 'content.js') content = CONTENT_JS;
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
toast('宸蹭笅杞 ' + filename + '锛岃蜂繚瀛樺埌浣犵殑鎻掍欢鐩');
}me/v1/creator/user/info/')
.then(function(r) { return r.json(); })
.then(function(d) { if(d && d.creator_user_id) my_uid = String(d.creator_user_id); })
.catch(function() {})
);
}
Promise.all(fetchPromises).then(function() {
if (typeof GM_cookie === 'undefined' || !GM_cookie.list) {
showToast(' 娌圭尨鐜澧冩湭鎺堜簣 GM_cookie 鏉冮檺锛岃峰湪鑴氭湰涓 @grant GM_cookie', 'err');
resetBtn();
return;
}
GM_cookie.list({ url: location.href }, function(cookies, error) {
if (error) {
showToast(' 鑾峰彇 Cookie 澶辫触: ' + error, 'err');
resetBtn();
return;
}
var cookieStr = cookies.map(function(c) {
return c.name + '=' + c.value;
}).join('; ');
var data = {
cookie: cookieStr,
web_protect: web_protect,
keys: keys,
ua: navigator.userAgent,
sec_uid: sec_uid,
nickname: '',
unique_id: my_uid || '',
frontier_ws_url: wsUrl,
ws_urls: capturedWs
};
var payloadStr = JSON.stringify(data);
var base64Payload = btoa(unescape(encodeURIComponent(payloadStr)));
var finalResult = 'DYCRED1.' + base64Payload;
try {
GM_setClipboard(finalResult);
showToast('馃帀 璇侀噰闆嗘垚鍔燂紒宸茶嚜鍔ㄥ嶅埗鍒板壀璐存澘銆', 'ok');
} catch(e) {
var ta = document.createElement('textarea');
ta.value = finalResult;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
ta.remove();
showToast('馃帀 璇侀噰闆嗘垚鍔燂紒宸叉墜鍔ㄥ嶅埗鍒板壀璐存澘銆', 'ok');
}
resetBtn();
});
});
}
function resetBtn() {
var btn = document.getElementById('dy-credential-grabber-btn');
if (btn) {
btn.innerHTML = '馃搶 閲囬泦鍑';
btn.style.background = 'linear-gradient(135deg,#8b5cf6,#a855f7)';
}
}
function showToast(msg, type) {
var toast = document.createElement('div');
toast.style = 'position:fixed;top:10%;left:50%;transform:translateX(-50%);z-index:9999999;padding:14px 24px;border-radius:12px;color:#fff;font-weight:600;font-size:14px;box-shadow:0 8px 30px rgba(0,0,0,0.5);font-family:sans-serif;line-height:1.4;';
if (type === 'ok') {
toast.style.background = '#059669';
toast.style.border = '1px solid #34d399';
} else {
toast.style.background = '#dc2626';
toast.style.border = '1px solid #f87171';
}
toast.innerHTML = msg;
document.body.appendChild(toast);
setTimeout(function() {
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.4s';
setTimeout(function() { toast.remove(); }, 400);
}, 3000);
}
})();\`;
function toast(msg) {
const t = document.getElementById('toast');
t.classList.remove('warn');
t.innerText = msg; t.classList.add('show');
clearTimeout(t._t); t._t = setTimeout(() => t.classList.remove('show'), 1600);
}
function toastWarn(msg) {
const t = document.getElementById('toast');
t.innerText = msg;
t.classList.add('show', 'warn');
clearTimeout(t._t);
t._t = setTimeout(() => t.classList.remove('show', 'warn'), 5000);
}
function copyText(text, msg) {
if (!text) { toast('湁鍙澶嶅埗鐨勫唴瀹'); return; }
navigator.clipboard.writeText(text).then(() => toast(msg || '宸插嶅埗'))
.catch(() => {
const ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta);
ta.select(); document.execCommand('copy'); ta.remove(); toast(msg || '宸插嶅埗');
});
}
// 鎶婇噰闆嗗埌鐨勫師濮 JSON 瑙勬暣涓 {ls:{...}, cookie:"", my_uid:""}
// 鍏煎逛笁绉嶆牸寮忥細鍏ㄩ噺 dump {localStorage,cookie,my_uid} / 鏃х増鍥涢敭鎵佸钩瀵硅薄 / 鐩存帴鐨 localStorage 瀵硅薄 / DYCRED1.xxx 瀵嗘枃
function normalizeDump(raw) {
let cleanRaw = (raw || '').trim();
if (cleanRaw.startsWith('DYCRED1.')) {
try {
const b64 = cleanRaw.split('.', 2)[1];
const decoded = decodeURIComponent(escape(atob(b64)));
const data = JSON.parse(decoded);
const ls = {};
if (data.keys) ls["security-sdk/s_sdk_crypt_sdk"] = data.keys;
if (data.web_protect) ls["security-sdk/s_sdk_sign_data_key/web_protect"] = data.web_protect;
if (data.sec_uid) ls["web_runtime_security_uid"] = data.sec_uid;
if (data.unique_id) {
ls["tea_cache_tokens"] = JSON.stringify({
user_unique_id: data.unique_id,
web_id: data.unique_id
});
}
return {
ls: ls,
cookie: data.cookie || '',
my_uid: data.unique_id || data.my_uid || '',
frontier_ws_url: data.frontier_ws_url || (data.ws_urls && data.ws_urls[0]) || '',
ws_urls: Array.isArray(data.ws_urls) ? data.ws_urls : []
};
} catch (e) {
console.error("Failed to parse DYCRED1 format:", e);
}
}
const obj = parseLocalStorage(cleanRaw);
if (obj === null) return null;
if (obj.localStorage && typeof obj.localStorage === 'object') {
return {
ls: obj.localStorage,
cookie: obj.cookie || '',
my_uid: obj.my_uid || '',
frontier_ws_url: obj.frontier_ws_url || '',
ws_urls: Array.isArray(obj.ws_urls) ? obj.ws_urls : []
};
}
return {
ls: obj,
cookie: obj.cookie || '',
my_uid: obj.my_uid || '',
frontier_ws_url: obj.frontier_ws_url || '',
ws_urls: Array.isArray(obj.ws_urls) ? obj.ws_urls : []
};
}
// 浠 localStorage 閲屾櫤鑳芥彁鍙栨煇涓瀛楁碉細鍏堢簿纭鍚嶏紝鍐嶆ā绯婂寘鍚鍖归厤
function pickLs(ls, exactKey, containsList) {
if (ls[exactKey]) return ls[exactKey];
for (const k in ls) {
const lk = k.toLowerCase();
if (containsList.some(c => lk.includes(c)) && ls[k]) return ls[k];
}
return '';
}
// 浠庝换鎰 localStorage 鍊奸噷灏藉姏鎸栧嚭 web_id锛坲ser_unique_id锛
function extractWebId(ls) {
const tea = pickLs(ls, 'tea_cache_tokens', ['tea_cache_tokens']);
if (tea) {
try {
const p = JSON.parse(tea);
const id = p.user_unique_id || p.web_id || '';
if (id) return String(id);
} catch (e) {}
}
// 鍏滃簳锛氭壂鎻忔墍鏈夊硷紝姝e垯鎵 user_unique_id
for (const k in ls) {
const v = ls[k];
if (typeof v !== 'string') continue;
const m = v.match(/"user_unique_id"\s*:\s*"?(\d{6,})"?/);
if (m && m[1]) return m[1];
}
return '';
}
// 浠庣矘璐村唴瀹归噷鎶藉嚭 wss://frontier-im.douyin.com/ws/v2?... 杩欐潯 URL
// 鍏煎圭洿鎺ョ矘 URL锛屾垨绮樹簡 fetch("...", {...}) 杩欑 devtools 澶嶅埗缁撴灉
function isImWsUrl(u) {
u = String(u || '');
if (!u || !/\/ws\/v2/i.test(u) || !/[?&]token=/.test(u)) return false;
return /frontier/i.test(u) || /zijieapi\.com/i.test(u);
}
function extractWsUrl(raw) {
if (!raw) return '';
const text = String(raw).replace(/\\\//g, '/');
const re = /wss?:\/\/[^\s"'`,)\]}]+/gi;
let m;
while ((m = re.exec(text)) !== null) {
const url = m[0];
if (isImWsUrl(url)) return url;
}
return '';
}
function uidFromWsUrl(ws) {
if (!ws) return '';
const m = String(ws).match(/[?&]device_id=(\d{6,})/);
return m ? m[1] : '';
}
function resolveWsFromDump(d, raw) {
const candidates = [];
if (d) {
if (d.frontier_ws_url && String(d.frontier_ws_url).trim()) {
candidates.push(String(d.frontier_ws_url).trim());
}
if (Array.isArray(d.ws_urls)) {
d.ws_urls.forEach((u) => { if (u && String(u).trim()) candidates.push(String(u).trim()); });
}
}
if (raw) {
candidates.push(String(raw));
candidates.push(String(raw).replace(/\\\//g, '/'));
}
for (const item of candidates) {
const url = extractWsUrl(item) || (isImWsUrl(item) ? item : '');
if (url) return url;
}
return '';
}
// 浠 URL 鍙栨煇涓 query 鍙傛暟骞惰В鐮侊紙decodeURIComponent 涓嶄細鎶 + 鍙樼┖鏍硷紝base64 瀹夊叏锛
function qparam(url, key) {
const m = url.match(new RegExp('[?&]' + key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '=([^&\\s]+)'));
if (!m) return '';
try { return decodeURIComponent(m[1]); } catch (e) { return m[1]; }
}
// 瑙f瀽 web_protect JSON锛堝吋瀹 {"data":"{...}"} 鍙屽眰缁撴瀯锛
function parseWebProtect(raw) {
if (!raw) return null;
try {
let o = JSON.parse(String(raw));
if (typeof o === 'string') o = JSON.parse(o);
if (o && typeof o.data === 'string') {
try { o = JSON.parse(o.data); } catch (e) {}
} else if (o && typeof o.data === 'object' && o.data) {
o = o.data;
}
return (o && typeof o === 'object') ? o : null;
} catch (e) {
return null;
}
}
// 鐩戝惉鍚勪釜杈撳叆妗嗙殑鍙樺姩锛岀洿鎺ヨ嚜鍔ㄧ敓鎴愬苟鏍¢獙绗鍥涙
const cookieInputEl = document.getElementById('cookieInput');
cookieInputEl.addEventListener('input', () => generate(false));
cookieInputEl.addEventListener('change', () => generate(false));
cookieInputEl.addEventListener('paste', () => setTimeout(() => generate(true), 0));
const lsInputEl = document.getElementById('lsInput');
lsInputEl.addEventListener('input', () => {
const raw = lsInputEl.value;
applyDumpToForm(normalizeDump(raw), raw, false);
generate(false);
});
lsInputEl.addEventListener('change', () => {
const raw = lsInputEl.value;
applyDumpToForm(normalizeDump(raw), raw, false);
generate(false);
});
lsInputEl.addEventListener('paste', () => setTimeout(() => {
const raw = lsInputEl.value;
applyDumpToForm(normalizeDump(raw), raw, true);
generate(true);
}, 0));
const wsInputEl = document.getElementById('wsInput');
const handleWsInput = (isPaste) => {
const ws = extractWsUrl(wsInputEl.value);
if (ws) showWsMissingHint(false);
if (!ws) {
generate(isPaste);
return;
}
const uid = uidFromWsUrl(ws);
if (uid && !document.getElementById('uidInput').value.trim()) {
document.getElementById('uidInput').value = uid;
}
generate(isPaste);
};
wsInputEl.addEventListener('input', () => handleWsInput(false));
wsInputEl.addEventListener('change', () => handleWsInput(false));
wsInputEl.addEventListener('paste', () => setTimeout(() => handleWsInput(true), 0));
const uidInputEl = document.getElementById('uidInput');
uidInputEl.addEventListener('input', () => generate(false));
uidInputEl.addEventListener('change', () => generate(false));
function extractCookieFromRaw(raw) {
raw = (raw || "").trim();
// 1. 灏濊瘯鍖归厤 JSON 缁撴瀯锛歿"cookie": "..."} 鎴 'cookie': '...'
const m1 = raw.match(/['"]cookie['"]\s*:\s*['"]([^'"]+)['"]/i);
if (m1 && m1[1]) {
return m1[1];
}
// 2. 灏濊瘯鍖归厤 cURL / Header 琛岋細-H 'cookie: ...' 鎴 cookie: '...'
const m2 = raw.match(/cookie:\s*['"]?([^'\r\n"]+)['"]?/i);
if (m2 && m2[1]) {
return m2[1].trim();
}
// 3. 鍏滃簳鎻愬彇锛氬尮閰嶄互 cookie: 寮澶寸殑浠绘剰琛岋紝骞跺墧闄ゅ栧眰寮曞彿/杞涔夌
const m3 = raw.match(/cookie:\s*([^\r\n]+)/i);
if (m3 && m3[1]) {
let val = m3[1].trim();
val = val.replace(/^['"]|['"]$/g, ''); // 鍓ョ绘渶澶栧眰鐨勫崟寮曞彿鎴栧弻寮曞彿
return val;
}
return raw;
}
// 鎶 "a=b; c=d" 瑙f瀽涓 cookie 瀵硅薄鏁扮粍
function parseCookieHeader(raw) {
const out = [];
const farFuture = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 180; // 180 澶
raw.split(/;\s*/).forEach(pair => {
if (!pair) return;
const idx = pair.indexOf('=');
if (idx <= 0) return;
const name = pair.slice(0, idx).trim();
let value = pair.slice(idx + 1).trim();
// 杩囨护鎺夊洜涓虹矘璐翠簡 fetch 璇鍙ョ瓑瀵艰嚧瑙f瀽鍑虹殑闈炴硶鐨 Cookie 鍚
if (!name || /[\(\)\[\]\{\}'"\n \t\\]/.test(name)) return;
out.push({
name,
value,
domain: ".douyin.com",
path: "/",
expires: farFuture,
httpOnly: false,
secure: true,
sameSite: "None"
});
});
return out;
}
function parseLocalStorage(raw) {
raw = (raw || '').trim();
if (!raw) return {};
try { return JSON.parse(raw); } catch (e) {}
const ws = extractWsUrl(raw);
if (ws) {
const idx = raw.indexOf(ws);
if (idx > 0) {
const head = raw.slice(0, idx).trim();
try { return JSON.parse(head); } catch (e2) {}
const s = head.indexOf('{'), e = head.lastIndexOf('}');
if (s >= 0 && e > s) {
try { return JSON.parse(head.slice(s, e + 1)); } catch (e3) {}
}
}
}
const s = raw.indexOf('{'), e = raw.lastIndexOf('}');
if (s >= 0 && e > s) {
try { return JSON.parse(raw.slice(s, e + 1)); } catch (e2) {}
}
return extractWsUrl(raw) ? {} : null;
}
function generate(autoFocus) {
const cookieRaw = document.getElementById('cookieInput').value.trim();
const lsRaw = document.getElementById('lsInput').value.trim();
const myUidVal = document.getElementById('uidInput').value.trim();
const checks = [];
if (!cookieRaw) {
renderChecks([{ s:'err', t:'璇峰厛绮樿创瀹屾暣 Cookie锛堟 2锛' }]);
if (autoFocus) {
switchTab(2);
toastWarn('璇峰厛瀹屾垚姝ラ 2锛氫粠鎺у埗鍙板嶅埗骞剁矘璐村畬鏁 Cookie');
}
return;
}
// 鎻愬彇鐪熸g殑 Cookie 鍊煎苟鍘绘帀 Cookie: 鍓嶇紑
const cleanCookie = extractCookieFromRaw(cookieRaw).replace(/^cookie\s*:/i, '').trim();
const cookies = parseCookieHeader(cleanCookie);
const names = new Set(cookies.map(c => c.name.toLowerCase()));
const dump = normalizeDump(lsRaw);
if (dump === null) {
renderChecks([{ s:'err', t:'姝ラ 3 鐨 JSON 瑙f瀽澶辫触锛岃烽噸鏂板嶅埗閲囬泦缁撴灉' }]);
return;
}
const ls = dump.ls || {};
// 鑷鍔ㄥ弽濉 UID / WS
applyDumpToForm(dump, lsRaw, false);
// 鏅鸿兘鎻愬彇鍥涢」鍏抽敭鍑璇侊紙绮剧‘閿 + 妯$硦鍖归厤鍏滃簳锛
const valKeys = pickLs(ls, 'security-sdk/s_sdk_crypt_sdk', ['crypt_sdk']);
const valProtect = pickLs(ls, 'security-sdk/s_sdk_sign_data_key/web_protect', ['web_protect']);
const webId = extractWebId(ls);
const deviceId = pickLs(ls, 'web_runtime_security_uid', ['runtime_security_uid', 'security_uid']) || webId;
// 鐢ㄥ悗绔鏈熸湜鐨勨勮寖閿鍚嶁濋噸寤 localStorage 鏉$洰锛屽肩敤鏅鸿兘鎻愬彇鍒扮殑缁撴灉
const localStorageEntries = [];
if (valKeys) localStorageEntries.push({ name: 'security-sdk/s_sdk_crypt_sdk', value: String(valKeys) });
if (valProtect) localStorageEntries.push({ name: 'security-sdk/s_sdk_sign_data_key/web_protect', value: String(valProtect) });
// 鍚庣 tea_cache_tokens 瑙f瀽 web_id锛涜嫢鍘熷肩己澶变絾鎸栧埌浜 web_id锛屽垯鍚堟垚涓 structure
const teaRaw = pickLs(ls, 'tea_cache_tokens', ['tea_cache_tokens']);
if (teaRaw) {
localStorageEntries.push({ name: 'tea_cache_tokens', value: String(teaRaw) });
} else if (webId) {
localStorageEntries.push({ name: 'tea_cache_tokens', value: JSON.stringify({ user_unique_id: webId, web_id: webId }) });
}
if (deviceId) localStorageEntries.push({ name: 'web_runtime_security_uid', value: String(deviceId) });
const storageState = {
cookies,
origins: [
{ origin: "https://www.douyin.com", localStorage: localStorageEntries }
],
user_agent: navigator.userAgent
};
const finalUid = document.getElementById('uidInput').value.trim() || dump.my_uid;
if (finalUid) {
storageState.my_uid = parseInt(finalUid, 10);
}
// 鏂规 A锛氳В鏋 frontier WS URL锛堟 鎵嬪~鎴栦功绛捐嚜鍔ㄩ噰闆嗭級
let wsRaw = (document.getElementById('wsInput').value || '').trim();
if (!wsRaw && dump.frontier_ws_url) wsRaw = dump.frontier_ws_url;
if (!wsRaw && dump.ws_urls && dump.ws_urls[0]) wsRaw = dump.ws_urls[0];
let hasWs = false, wsSdkCert = '', wsTsSign = '';
if (wsRaw) {
const wsUrl = extractWsUrl(wsRaw);
const isFrontier = wsUrl && /[?&]token=/.test(wsUrl) &&
(wsUrl.indexOf('frontier-im.douyin.com') !== -1 || (wsUrl.indexOf('frontier') !== -1 && wsUrl.indexOf('zijieapi.com') !== -1));
if (isFrontier) {
hasWs = true;
storageState.frontier_ws_url = wsUrl;
wsSdkCert = qparam(wsUrl, 'sdk_cert');
wsTsSign = qparam(wsUrl, 'ts_sign');
if (wsSdkCert) storageState.sdk_cert = wsSdkCert;
if (wsTsSign) storageState.ts_sign = wsTsSign;
}
}
document.getElementById('output').value = JSON.stringify(storageState, null, 2);
// 鏍¢獙
const hasSession = names.has('sessionid') || names.has('sessionid_ss');
const hasUid = !!finalUid || names.has('uid_tt') || names.has('uid_tt_ss');
const hasProtect = !!valProtect;
const hasKeys = !!valKeys;
const hasWebId = !!webId;
const hasDevice = !!deviceId;
const wp = parseWebProtect(valProtect);
const hasWpTicket = !!(wp && wp.ticket);
const hasWpTs = !!(wp && wp.ts_sign);
const hasWpCert = !!(wp && (wp.client_cert || wp.sdk_cert));
checks.push(chk(hasSession, 'sessionid锛堢櫥褰曟侊紝蹇呴渶锛', '缂 sessionid锛佸繀椤讳粠銆屾 2銆峃etwork 璇锋眰澶撮噷鐨 Cookie 澶嶅埗锛堝惈 sessionid=...锛夛紝document.cookie 璇讳笉鍒板畠'));
checks.push(chk(hasUid, '鎶栭煶鏁板瓧 UID', '鏈鎻愬彇鍒版暟瀛 UID锛堜功绛句細鑷鍔ㄦ姄鍙栵級锛涘彲鎵嬪姩濉鍐欙紝缂哄け鏃跺悗鍙颁細鑱旂綉鏌ヨ'));
checks.push(chk(hasProtect, 'web_protect锛堢惧悕鍑璇侊紝蹇呴渶锛', '缂 web_protect锛佽峰湪鎶栭煶銆岀佷俊椤点嶅仠鐣欏嚑绉掕╁畨鍏 SDK 鍐欏叆鍚庯紝閲嶆柊鐢ㄤ功绛/鑴氭湰閲囬泦'));
if (hasProtect) {
checks.push(chk(hasWpTicket && hasWpTs && hasWpCert, 'web_protect 鍐呭惈 ticket + ts_sign + client_cert锛堝彂閫佸繀闇',
'web_protect 涓嶅畬鏁达紒璇风‘淇濆湪銆岀佷俊椤点嶅仠鐣 5~10 绉掑悗閲嶆柊閲囬泦锛涚己 client_cert/ts_sign 浼氬艰嚧鍙戦 7911'));
}
checks.push(chk(hasKeys, 'keys / crypt_sdk锛堢惧悕瀵嗛挜锛屽繀闇', '缂 crypt_sdk锛佽烽噸鏂伴噰闆 localStorage锛堢‘璁ゅ湪宸茬櫥褰曠殑鎶栭煶鏍囩鹃〉鎵ц岋級'));
checks.push(chk(hasWebId, 'web_id', '缂 web_id锛歭ocalStorage 閲屾病鎵惧埌 tea_cache_tokens锛涘埛鏂版姈闊抽〉闈㈠悗閲嶉噰闆'));
checks.push(chk(hasDevice, 'device_id', '缂 device_id锛氭病鎵惧埌 web_runtime_security_uid锛涘埛鏂版姈闊抽〉闈㈠悗閲嶉噰闆嗭紙宸插皾璇曠敤 web_id 鍏滃簳锛'));
if (hasWs) {
checks.push({ s: wsSdkCert ? 'ok' : 'warn', t: wsSdkCert ? '宸插寘鍚 frontier WebSocket锛堜功绛/鑴氭湰鍙鍔ㄦ姄鍙栵紝鐢ㄤ簬瀹炴椂鏀舵秷鎭' : '宸插寘鍚 frontier WebSocket锛屼絾鏈瑙f瀽鍒 sdk_cert锛岃风‘璁 URL 瀹屾暣' });
} else {
checks.push({ s: 'warn', t: '鏈鎶撳埌 frontier WebSocket锛氳风敤涔︾炬墦寮绉佷俊椤靛悗鍐嶉噰闆嗭紝鎴栨墜鍔ㄧ矘璐 WS URL锛堟 鈽咃級' });
}
renderChecks(checks);
const okCore = hasSession && hasProtect && hasKeys && hasWpTicket && hasWpTs && hasWpCert;
if (okCore) {
if (autoFocus) {
// 妫鏌ュ苟鑷鍔ㄥ垏鍥 Tab 4
const tab4Btn = document.getElementById('tab-btn-4');
if (tab4Btn && !tab4Btn.classList.contains('active')) {
switchTab(4);
}
// 鑷鍔ㄥ嶅埗
const outputText = JSON.stringify(storageState, null, 2);
navigator.clipboard.writeText(outputText).then(() => {
toast('鍑璇佺敓鎴愭垚鍔燂紝宸茶嚜鍔ㄥ嶅埗鍒板壀璐存澘锛');
}).catch(() => {
const ta = document.createElement('textarea');
ta.value = outputText;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
ta.remove();
toast('鍑璇佺敓鎴愭垚鍔燂紝宸茶嚜鍔ㄥ嶅埗鍒板壀璐存澘锛');
});
// 鑷鍔ㄦ粴鍔ㄥ埌姝ラ 4 Card
setTimeout(() => {
document.getElementById('step4Card')?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}, 300);
} else {
toast(okCore ? (hasWebId && hasDevice ? '鐢熸垚鎴愬姛锛屽嚟璇侀綈鍏锛屽彲澶嶅埗瀵煎叆' : '鏍稿績鍑璇侀綈鍏ㄥ彲鐢锛泈eb_id/device_id 寤鸿琛ュ叏') : '鍏抽敭鍑璇佺己澶憋紝璇风湅绾㈣壊鎻愮ず');
}
} else {
if (autoFocus) {
document.getElementById('step4Card')?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
toastWarn('鍏抽敭鍑璇佺己澶憋紝璇风湅绾㈣壊鎻愮ず杩涜岃ˉ閲');
} else {
toast('鍏抽敭鍑璇佺己澶憋紝璇风湅绾㈣壊鎻愮ず');
}
}
}
function chk(ok, okText, failText) {
if (ok) return { s: 'ok', t: '宸插寘鍚 ' + okText };
const critical = /蹇呴渶/.test(okText);
return { s: critical ? 'err' : 'warn', t: failText };
}
function renderChecks(list) {
document.getElementById('checks').innerHTML = list.map(c =>
`<div class="chk ${c.s}"><span class="dot"></span>${c.t}</div>`
).join('');
}
</script>
</body>
</html>