// ==UserScript== // @name NetChk_Triangle_IronLock v37 beta // @version 37.5.31.b3 // @namespace https://greasyfork.org/zh-CN/users/1593463-nander // @license CC BY-NC-SA 4.0 // @description 深度修复隐藏逻辑,确保点击隐藏后立即生效并持久化 // @author Gemini // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_openInTab // @grant GM_registerMenuCommand // @connect * // @run-at document-start // @downloadURL https://update.greasyfork.icu/scripts/575373/NetChk_Triangle_IronLock%20v37%20beta.user.js // @updateURL https://update.greasyfork.icu/scripts/575373/NetChk_Triangle_IronLock%20v37%20beta.meta.js // ==/UserScript== (function() { 'use strict'; const COLORS = { bg: '#1a1a1a', border: '#333333', textMain: '#ffffff', text80: '#cccccc', text60: '#999999', text40: '#666666', vscBlue: '#005a9e', nckCN: '#4ade80', nckGL: '#60a5fa', nckERR: '#f87171', nckWarn: '#fbbf24' }; const STYLES = ` #nck-main { position: fixed !important; z-index: 2147483647 !important; background: ${COLORS.bg} !important; border: 1px solid ${COLORS.border} !important; border-radius: 2px !important; height: 24px !important; display: flex !important; align-items: stretch !important; box-sizing: border-box !important; cursor: default !important; user-select: none !important; font-family: "Cascadia Code", Consolas, monospace !important; box-shadow: 0 2px 8px rgba(0,0,0,0.5) !important; transition: opacity 0.3s, background 0.3s; } #nck-panel-container { position: absolute !important; display: none !important; left: 50% !important; transform: translateX(-50%) !important; width: 210px !important; } #nck-panel-container::before { content: ''; position: absolute; left: 0; right: 0; height: 10px; } .dir-down { top: 24px !important; padding-top: 5px !important; } .dir-down::before { top: -10px; } .dir-up { bottom: 24px !important; padding-bottom: 5px !important; } .dir-up::before { bottom: -10px; } #nck-main:hover #nck-panel-container, #nck-main.keep-open #nck-panel-container { display: block !important; } #nck-panel { background: ${COLORS.bg} !important; border: 1px solid ${COLORS.border} !important; padding: 6px !important; box-shadow: 0 4px 15px rgba(0,0,0,0.7) !important; } .panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; border-bottom: 1px solid #333; padding-bottom: 3px; } .panel-ver { font-size: 8px; color: ${COLORS.text40}; font-weight: bold; } .ip-link-btn { cursor: pointer; color: ${COLORS.text60}; font-size: 8px; padding: 0 4px; border: 1px solid #444; background: #252526; } .ip-row { background: #222; padding: 4px 6px; margin-bottom: 3px; border: 1px solid #2d2d2d; } .ip-row-info { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2px; } .ip-label { font-size: 8px; color: ${COLORS.text40}; font-weight: bold; } .ip-label b { color: ${COLORS.text60}; margin-left: 5px; font-weight: normal; } .ip-ms { font-size: 9px; font-weight: 900; opacity: 0.9;} .ip-val { color: ${COLORS.text80}; font-size: 10px; font-family: "Cascadia Code", monospace; word-break: break-all; line-height: 1.2; display: block; border-top: 1px solid #2d2d2d; padding-top: 3px; margin-top: 2px; } .ms-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; margin: 5px 0; } .ms-node { font-size: 9px; text-align: center; color: ${COLORS.text40}; background: #252526; padding: 3px 0; border: 1px solid #333; } .ms-node.active { color: ${COLORS.text80}; border-color: #444; } .ms-node b { display: block; font-size: 7px; opacity: 0.6; margin-bottom: 1px; } .btn-group { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px; margin-top: 5px; } .t-btn { background: #2a2a2a; color: ${COLORS.text60}; font-size: 8px; padding: 4px 0; text-align: center; cursor: pointer; border: 1px solid #333; transition: 0.1s; } .t-btn:hover { background: #333; color: #fff; } .t-btn.active { background: ${COLORS.vscBlue} !important; color: #fff !important; border-color: #007acc !important; } #nck-trigger { display: flex; align-items: center; padding: 0 8px; flex-grow: 1; cursor: pointer; gap: 6px; } .info-code { color: #fff; font-size: 10px; font-weight: bold; } .info-ms { font-size: 10px; font-weight: 900;min-width: 30px; } .ms-cn { color: ${COLORS.nckCN}; } .ms-gl { color: ${COLORS.nckGL}; } .nck-led { width: 4px; height: 4px; border-radius: 1px; background: #333; transition: 0.3s; } .led-checking { background: ${COLORS.nckWarn} !important; box-shadow: 0 0 4px ${COLORS.nckWarn}; } .led-ok-cn { background: ${COLORS.nckCN} !important; box-shadow: 0 0 3px ${COLORS.nckCN}; } .led-ok-gl { background: ${COLORS.nckGL} !important; box-shadow: 0 0 3px ${COLORS.nckGL}; } .led-err { background: ${COLORS.nckERR} !important; } #nck-bay { width: 24px; border-left: 1px solid ${COLORS.border}; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: 0.2s; } #nck-bay:hover { background: #2a2a2a; } .bay-play { width: 0; height: 0; border-top: 4px solid transparent; border-bottom: 4px solid transparent; border-left: 6px solid #555; transition: 0.2s; } .ctrl-active .bay-play { border-left-color: ${COLORS.nckCN} !important; } @keyframes success-flash { 0% { background: #1a1a1a; } 50% { background: #1a4a2a; } 100% { background: #1a1a1a; } } .state-success { animation: success-flash 0.4s ease; } .state-success .bay-play { border-left-color: ${COLORS.nckCN} !important; transform: scale(1.2); } @keyframes error-shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } } .state-error { animation: error-shake 0.2s 2; border-color: ${COLORS.nckERR} !important; } .state-error .bay-play { border-left-color: ${COLORS.nckERR} !important; } .hidden { display: none !important; } `; let state = { isProcessing: false, nodes: { cn: { ip: '...', ms: '--', state: 'init' }, gl: { ip: '...', ms: '--', state: 'init' }, code: 'VSC' }, targets: [ { id: 'BD', url: 'https://www.baidu.com/favicon.ico' }, { id: 'GH', url: 'https://github.com/favicon.ico' }, { id: 'CF', url: 'https://1.1.1.1/cdn-cgi/trace' } ], conf: { visible: GM_getValue('nck_v378_vis', true), matrix: GM_getValue('nck_v378_mtx', true), longShow: GM_getValue('nck_v378_long', false), locked: GM_getValue('nck_v378_lock', false), bindCtrl: GM_getValue('nck_v378_ctrl', true), bayOn: GM_getValue('nck_v378_bay', true), pingShow: GM_getValue('nck_v378_ping', true), lang: GM_getValue('nck_v378_lang', 'zh') }, langLib: { zh: { mtx:'矩阵', bay:'弹仓', keep:'驻留', lock:'锁定', ctrl:'劫持', lang:'中文', hide:'隐藏', ping:'数值' }, en: { mtx:'MTX', bay:'BAY', keep:'KEEP', lock:'LOCK', ctrl:'CTRL', lang:'EN', hide:'HIDE', ping:'PING' } } }; function syncUI() { const box = document.getElementById('nck-main'); if (!box) return; // 深度修复:强制设置 display 属性,确保可见性受控 if (state.conf.visible) { box.style.setProperty('display', 'flex', 'important'); } else { box.style.setProperty('display', 'none', 'important'); } box.classList.toggle('keep-open', state.conf.longShow); const bay = document.getElementById('nck-bay'); if (bay) { bay.classList.toggle('hidden', !state.conf.bayOn); bay.classList.toggle('ctrl-active', state.conf.bindCtrl); } // 刷新内容 const msCN = state.nodes.cn.ms ; const msGL = state.nodes.gl.ms ; // 在 syncUI 函数内部找到 infoBox 渲染逻辑并替换: const infoBox = document.getElementById('nck-info-box'); if (infoBox) { // 确保即使在加载中,也有占位符或正确的数值显示 const displayCN = state.conf.pingShow ? (state.nodes.cn.ms || '--') : ''; const displayGL = state.conf.pingShow ? (state.nodes.gl.ms || '--') : ''; infoBox.innerHTML = ` ${state.nodes.code || 'VSC'} ${displayCN} ${displayGL}`; } // LED const ledCN = document.getElementById('led-cn'); const ledGL = document.getElementById('led-gl'); if (ledCN) ledCN.className = 'nck-led' + (state.nodes.cn.state === 'ok' ? ' led-ok-cn' : (state.nodes.cn.state === 'checking' ? ' led-checking' : '')); if (ledGL) ledGL.className = 'nck-led' + (state.nodes.gl.state === 'ok' ? ' led-ok-gl' : (state.nodes.gl.state === 'checking' ? ' led-checking' : '')); // 面板文本 const valCN = document.getElementById('ip-cn-val'); const valGL = document.getElementById('ip-gl-val'); if (valCN) valCN.innerText = state.nodes.cn.ip; if (valGL) valGL.innerText = state.nodes.gl.ip; // 2. 【新增/修复】刷新面板内部的延迟数值 (Label) const labelCN = document.getElementById('ip-cn-ms-label'); const labelGL = document.getElementById('ip-gl-ms-label'); if (labelCN) labelCN.innerText = msCN; // 更新面板 CN 行的延迟 if (labelGL) labelGL.innerText = msGL; // 更新面板 GLB 行的延迟 // 按钮 const L = state.langLib[state.conf.lang]; const btnConfigs = [ { id: 't-matrix', key: 'matrix', text: L.mtx }, { id: 't-bayOn', key: 'bayOn', text: L.bay }, { id: 't-longShow', key: 'longShow', text: L.keep }, { id: 't-locked', key: 'locked', text: L.lock }, { id: 't-bindCtrl', key: 'bindCtrl', text: L.ctrl }, { id: 't-pingShow', key: 'pingShow', text: L.ping }, { id: 't-lang', key: null, text: L.lang }, { id: 't-hide', key: null, text: L.hide } ]; btnConfigs.forEach(cfg => { const el = document.getElementById(cfg.id); if (el) { el.innerText = cfg.text; if (cfg.key) el.classList.toggle('active', state.conf[cfg.key]); } }); const matrixArea = document.getElementById('matrix-area'); if (matrixArea) matrixArea.classList.toggle('hidden', !state.conf.matrix); renderMatrix(); updatePanelPos(); } function centerBox() { const box = document.getElementById('nck-main'); if (box) { const x = (window.innerWidth - box.offsetWidth) / 2; const y = (window.innerHeight - box.offsetHeight) / 2; box.style.left = x + 'px'; box.style.top = y + 'px'; GM_setValue('nck_v378_pos', { x, y }); updatePanelPos(); } } function renderMatrix() { const grid = document.getElementById('grid-1'); if (grid) grid.innerHTML = state.targets.map(t => `
${t.id}${t.ms || '--'}
`).join(''); } function updatePanelPos() { const box = document.getElementById('nck-main'); const container = document.getElementById('nck-panel-container'); if (box && container) { const rect = box.getBoundingClientRect(); container.className = rect.top > window.innerHeight / 2 ? 'dir-up' : 'dir-down'; } } function checkNet() { const start = Date.now(); state.nodes.cn.state = 'checking'; state.nodes.gl.state = 'checking'; syncUI(); GM_xmlhttpRequest({ method: "GET", url: "https://myip.ipip.net", timeout: 2500, onload: (r) => { // IPIP 返回的是纯文本,形如 "IP: 1.2.3.4 来自于: 中国..." // 我们用正则直接提取出 IP 地址部分 const match = r.responseText.match(/((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}/); if (match) { state.nodes.cn.ip = match[0]; state.nodes.cn.ms = (Date.now() - start) + 'ms'; state.nodes.cn.state = 'ok'; } else { state.nodes.cn.state = 'err'; } syncUI(); }, onerror: () => { state.nodes.cn.state = 'err'; syncUI(); } }); GM_xmlhttpRequest({ method: "GET", url: "https://www.cloudflare.com/cdn-cgi/trace", timeout: 2500, onload: (r) => { const ip = r.responseText.match(/ip=(.+)/); const loc = r.responseText.match(/loc=(.+)/); if (ip) state.nodes.gl.ip = ip[1]; if (loc) state.nodes.code = loc[1]; state.nodes.gl.ms = (Date.now() - start) + 'ms'; state.nodes.gl.state = 'ok'; syncUI(); }, onerror: () => { state.nodes.gl.state = 'err'; syncUI(); } }); state.targets.forEach(t => { const s = Date.now(); GM_xmlhttpRequest({ method: "GET", url: t.url + "?t=" + s, timeout: 2000, onload: () => { t.ms = (Date.now() - s) + 'ms'; renderMatrix(); } }); }); } async function handleSend() { if (state.isProcessing) return; state.isProcessing = true; const main = document.getElementById('nck-main'); state.nodes.cn.state = 'checking'; state.nodes.gl.state = 'checking'; syncUI(); const isOk = await new Promise(r => { GM_xmlhttpRequest({ method: "GET", url: "https://www.google.com/generate_204", timeout: 1500, onload: () => r(true), onerror: () => r(false), ontimeout: () => r(false) }); }); if (isOk) { main.classList.add('state-success'); const selectors = ['button[aria-label*="发送"]', 'button[aria-label*="Send"]', '[data-testid="send-button"]', 'button.send-icon', 'button[type="submit"]', '#send-btn']; for (let s of selectors) { const btn = document.querySelector(s); if (btn && !btn.disabled) { btn.click(); break; } } setTimeout(() => main.classList.remove('state-success'), 500); } else { main.classList.add('state-error'); setTimeout(() => main.classList.remove('state-error'), 800); } state.isProcessing = false; checkNet(); } function inject() { if (document.getElementById('nck-main')) return; GM_addStyle(STYLES); const box = document.createElement('div'); box.id = 'nck-main'; const pos = GM_getValue('nck_v378_pos', { x: window.innerWidth - 240, y: 50 }); box.style.left = pos.x + 'px'; box.style.top = pos.y + 'px'; box.innerHTML = `
IRONLOCK v37.5.31.beta
CN IPIP--
...
GLB CF--
...
`; document.body.appendChild(box); const configKeys = ['matrix', 'bayOn', 'longShow', 'locked', 'bindCtrl', 'pingShow']; configKeys.forEach(key => { document.getElementById('t-' + key).onclick = (e) => { e.preventDefault(); e.stopPropagation(); state.conf[key] = !state.conf[key]; GM_setValue('nck_v378_' + key, state.conf[key]); syncUI(); }; }); document.getElementById('t-lang').onclick = (e) => { e.preventDefault(); e.stopPropagation(); state.conf.lang = state.conf.lang === 'zh' ? 'en' : 'zh'; GM_setValue('nck_v378_lang', state.conf.lang); syncUI(); }; // 最终隐藏修复 document.getElementById('t-hide').onclick = function(e) { e.preventDefault(); e.stopPropagation(); console.log('[NCK] 执行隐藏指令'); state.conf.visible = false; GM_setValue('nck_v378_vis', false); syncUI(); }; document.getElementById('ip-skk').onclick = () => GM_openInTab("https://ip.skk.moe/multi", { active: true }); document.getElementById('nck-trigger').onclick = (e) => { e.stopPropagation(); checkNet(); }; document.getElementById('nck-bay').onclick = (e) => { e.stopPropagation(); handleSend(); }; box.onmousedown = (e) => { if (e.target.closest('#nck-panel') || state.conf.locked || e.target.closest('#nck-bay')) return; let ox = e.clientX - box.offsetLeft, oy = e.clientY - box.offsetTop; const move = (ev) => { box.style.left = ev.clientX - ox + 'px'; box.style.top = ev.clientY - oy + 'px'; updatePanelPos(); }; const stop = () => { document.removeEventListener('mousemove', move); GM_setValue('nck_v378_pos', { x: box.offsetLeft, y: box.offsetTop }); }; document.addEventListener('mousemove', move); document.addEventListener('mouseup', stop); }; syncUI(); checkNet(); } window.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 'Enter' && state.conf.bindCtrl) { const activeEl = document.activeElement; if (activeEl && (activeEl.tagName === 'TEXTAREA' || activeEl.contentEditable === 'true' || activeEl.tagName === 'INPUT')) { e.preventDefault(); e.stopImmediatePropagation(); handleSend(); } } }, true); GM_registerMenuCommand("[NCK] 唤醒 / 显示界面", () => { state.conf.visible = true; GM_setValue('nck_v378_vis', true); syncUI(); }); GM_registerMenuCommand("[NCK] 重置位置居中", () => { state.conf.visible = true; GM_setValue('nck_v378_vis', true); centerBox(); syncUI(); }); if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', inject); else inject(); })();