// ==UserScript== // @name 世强+立创+芯城+汽车之家(Sekorm/LCSC/iKey/Autohome) 浏览增强 // @namespace https://www.sekorm.com/ // @version 3.1.0 // @description ①世强硬创平台(sekorm.com):自动关闭登录拦截弹窗,免登录浏览产品参数与资料预览;②立创商城(szlcsc.com):游客搜索次数达上限被强制跳转到 passport.jlc.com 登录页时,自动重置游客会话(含 HttpOnly Cookie、各域本地存储)、获取新游客身份并跳回搜索结果,失败时提供手动重试;③云汉芯城(ickey.cn):自动拦截"新人福利"等广告弹窗,游客搜索触发的登录弹窗自动关闭并重置游客会话刷新页面恢复搜索;④汽车之家(autohome.com.cn):自动关闭页面弹出的播放器小窗口。 // @author yangu // @match *://www.sekorm.com/* // @match *://en.sekorm.com/* // @match *://passport.jlc.com/login* // @match *://so.szlcsc.com/* // @match *://www.szlcsc.com/* // @match *://search.ickey.cn/* // @match *://www.ickey.cn/* // @match *://autohome.com.cn/* // @match *://*.autohome.com.cn/* // @run-at document-start // @noframes // @license MIT // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_registerMenuCommand // @grant GM_cookie // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect szlcsc.com // @connect so.szlcsc.com // @connect www.szlcsc.com // @connect jlc.com // @connect passport.jlc.com // @connect ickey.cn // @connect search.ickey.cn // @connect www.ickey.cn // @connect passport.ickey.cn // ==/UserScript== /* * ========== 世强部分原理(已在 pnPs / doc / product 三类页面实测验证)========== * 1. 未登录时站点向 body 直接追加两个元素作为登录墙: * - .modal-mask 全屏黑色遮罩(z-index 9999999) * - .modal-boundingBox.login_new_wrapper 登录弹窗(z-index 2147483647,内含 #modal_login 表单) * 2. 同时 body 被设置 overflow:hidden 锁定滚动,并带 hideCloseBtn 类隐藏右上角 X 关闭按钮。 * 3. 页面内容(产品参数表、资料正文、PDF 前 2 页预览图)其实早已在 DOM 中。 * 4. 脚本三层防线(v3.0.0 起): * a) CSS 预隐藏(document-start 注入,参考"知乎不显示登录框"思路): * 登录弹窗/遮罩/滚动锁定从头到尾不生效,弹窗不再闪现; * 遮罩与滚动用 :has(.login_new_wrapper) 跟随登录弹窗存在与否,不误伤站点其他弹窗; * b) 模拟点击 .modal-closeBtn,走站点自身关闭逻辑:移除弹窗+遮罩并恢复滚动(兜底); * c) 用户点击登录相关元素后 60 秒内不自动干预,保证正常登录。 * * ========== 立创部分原理(实测验证)========== * 1. 游客在 so.szlcsc.com/global.html 搜索若干次(实测约 3 次)后, * 服务端直接返回 302 强制跳转到 passport.jlc.com/login?redirectUrl=原搜索URL, * 且已清空全部 JS 可见 Cookie(tws2_*、_lcsc_fid、noLoginCustomerFlag 等)后依旧被拦, * 说明限制关联的是 HttpOnly Cookie 或服务端 IP 记录。 * 2. 302 是服务端行为,客户端脚本无法阻止跳转;因此恢复逻辑放在登录页执行: * 检测 redirectUrl 指向 szlcsc.com 时,用 GM_cookie(支持 HttpOnly)重置游客会话, * 然后跳回 redirectUrl 恢复搜索。 * 3. 跳回前做多件事提高恢复成功率: * a) 剥离 redirectUrl 中的 lcsc_vid(访客ID)/spm 等跟踪参数,避免被重新关联旧身份; * b) 清空登录页域(passport.jlc.com)的 localStorage/sessionStorage(含设备指纹键, * 游客购物车/搜索历史存在 szlcsc.com 域,不受影响); * c) 先用 GM_xmlhttpRequest 访问一次商城首页,让服务端 Set-Cookie 分配全新游客身份, * 模拟"新游客先逛首页再搜索"的正常流程,而非清空身份后直奔搜索页; * d) 设置跨域清理标记,跳回后由商城域(so/www.szlcsc.com)的脚本清理各自域的 * localStorage/sessionStorage 埋点指纹数据(经无痕窗口对照实验确认: * 全新身份可正常搜索,说明限制基于身份识别而非 IP)。 * 4. 若跳回后立刻再次弹回登录页(60 秒内),判定恢复失败(可能是 IP 级限制), * 进入 30 分钟冷却期,期间仅提供手动重试按钮,避免死循环。 * 5. 用户一旦开始操作登录页(输入/点击),自动恢复立即让位,不影响正常登录。 */ (function () { 'use strict'; var host = location.hostname || ''; if (/(^|\.)sekorm\.com$/.test(host)) { initSekorm(); } else if (host === 'passport.jlc.com') { initLcscRecovery(); } else if (/(^|\.)szlcsc\.com$/.test(host)) { initLcscStorageClean(); } else if (/(^|\.)ickey\.cn$/.test(host)) { initIkeyAdBlock(); initIkeyLoginClose(); } else if (/(^|\.)autohome\.com\.cn$/.test(host)) { initAutohomeVideoBlock(); } // 说明:立创的搜索次数限制是服务端 302 跳转,被拦时 so.szlcsc.com / www.szlcsc.com // 页面根本不会加载,因此恢复主逻辑统一在 passport.jlc.com 登录页执行; // 但这两个域的 localStorage/sessionStorage 里有埋点指纹数据(如 JlcTrackData), // 页面 JS 会读取并上报、让服务端重新认出旧身份,所以脚本也匹配商城域, // 在登录页发起恢复时设置标记(GM_setValue 跨域共享),商城页加载后据此清理本域存储。 /** * 通用工具:document-start 注入模式下尽早插入 CSS。 * 此时 head 可能尚未解析,挂到 documentElement 上同样生效。 */ function addStyleEarly(css) { try { var s = document.createElement('style'); s.textContent = css; (document.head || document.documentElement).appendChild(s); return s; } catch (e) { return null; } } /** * 通用工具:document-start 模式下 body 尚不存在, * 轮询 + DOMContentLoaded 双保险等待 body 就绪后再执行(只执行一次)。 */ function onBodyReady(fn) { var done = false; function run() { if (done || !document.body) return; done = true; fn(); } if (document.body) { run(); return; } var t = setInterval(run, 20); document.addEventListener('DOMContentLoaded', function () { clearInterval(t); run(); }); } /* ==================================================================== * * 第一部分:世强硬创平台 * * ==================================================================== */ function initSekorm() { var STORAGE_KEY = 'sk_nologin_enabled'; var enabled = GM_getValue(STORAGE_KEY, true); // ---- 入口 0:CSS 预隐藏(document-start 即注入,弹窗从头到尾不闪现)---- // - .modal-boundingBox.login_new_wrapper 是登录弹窗专属类组合,不会误伤站点其他弹窗; // - 遮罩与滚动锁定用 :has() 跟随登录弹窗存在与否生效,站点其他弹窗的遮罩不受影响 // (display:none 的弹窗仍存在于 DOM,:has() 依旧匹配,登录墙期间页面保持可滚动)。 // 隐藏后仍保留下方点击关闭逻辑作兜底:万一 CSS 被内联样式顶掉,observer 照常工作。 var cssEl = null; function applyPrehideCss() { if (cssEl || !enabled) return; cssEl = addStyleEarly( '.modal-boundingBox.login_new_wrapper { display: none !important; }' + 'body:has(.modal-boundingBox.login_new_wrapper) .modal-mask { display: none !important; }' + 'html:has(.modal-boundingBox.login_new_wrapper), body:has(.modal-boundingBox.login_new_wrapper) {' + ' overflow: auto !important; margin-right: 0 !important;' + '}' ); } applyPrehideCss(); // ---- 防抖与安全阀:避免与站点脚本形成"关闭→再弹出"死循环 ---- var lastCloseAt = 0; var closeCount = 0; var MIN_INTERVAL = 1000; // 两次自动关闭的最小间隔(ms) var MAX_CLOSE = 30; // 单个页面最多自动关闭次数 // ---- 用户主动登录意图检测 ---- // 点击"登录/注册"、或在弹窗内操作(输手机号/获取验证码)后 60 秒内不自动关闭, // 保证想登录的用户可以正常登录。 var loginIntentAt = 0; var INTENT_KEEP = 60000; // 登录弹窗特征:.modal-boundingBox 内包含登录表单 function findLoginModal() { var boxes = document.querySelectorAll('.modal-boundingBox'); for (var i = 0; i < boxes.length; i++) { if (boxes[i].querySelector('#modal_login, #js_portal_login_modal, .login-common-wrap')) { return boxes[i]; } } return null; } function closeLoginModal() { if (!enabled) return; var now = Date.now(); if (now - lastCloseAt < MIN_INTERVAL) return; if (closeCount >= MAX_CLOSE) return; if (now - loginIntentAt < INTENT_KEEP) return; // 用户正在尝试登录,别捣乱 var modal = findLoginModal(); if (!modal) return; lastCloseAt = now; closeCount++; var btn = modal.querySelector('.modal-closeBtn'); if (btn) { btn.click(); // 站点自身逻辑:移除弹窗+遮罩,恢复 body 滚动 } else { // 兜底:极少数情况弹窗内没有关闭按钮,手动清理 modal.remove(); var mask = document.querySelector('.modal-mask'); if (mask) mask.remove(); document.body.style.overflow = ''; } } // 弹窗内部内容(表单、二维码等)异步渲染,多试几次确保点到关闭按钮 function scheduleClose() { setTimeout(closeLoginModal, 100); setTimeout(closeLoginModal, 500); setTimeout(closeLoginModal, 1500); } // ---- 入口 1:监听弹窗出现(body 就绪后启动 observer)---- // 点击"下载/预览/收藏"等操作、或跳转新页面时会再次弹出登录墙 var observer = new MutationObserver(function (mutations) { if (!enabled) return; for (var i = 0; i < mutations.length; i++) { var nodes = mutations[i].addedNodes; for (var j = 0; j < nodes.length; j++) { var n = nodes[j]; if (!n || n.nodeType !== 1) continue; // 登录墙是 body 的直接子元素;同时也覆盖其它可能的容器 if ((n.classList && (n.classList.contains('modal-boundingBox') || n.classList.contains('modal-mask'))) || (n.querySelector && n.querySelector('.modal-boundingBox'))) { scheduleClose(); return; } } } }); onBodyReady(function () { // 入口 1a:页面加载时弹窗可能已出现 scheduleClose(); // 入口 1b:监听后续弹出的登录墙 observer.observe(document.body, { childList: true, subtree: true }); // 禁用时还原 X 关闭按钮显示(hideCloseBtn 是站点隐藏关闭按钮的类) if (!enabled) showCloseBtn(); }); // ---- 捕获用户主动登录的意图(capture 阶段,先于站点事件)---- document.addEventListener('click', function (e) { var el = e.target; if (!el || !el.closest) return; // 命中:弹窗自身(表单/验证码/微信登录tab)、头部"登录/注册"、 // 其它 class/id 含 login 的元素(如 header_user_unlogin) if (el.closest('.modal-boundingBox, [class*="login"], [id*="login"], [class*="Login"]')) { loginIntentAt = Date.now(); } }, true); // ---- 菜单开关:需要正常登录账号时可临时禁用 ---- // 禁用后还原 X 关闭按钮显示,弹窗仍可手动关闭 function showCloseBtn() { document.body.classList.remove('hideCloseBtn'); } GM_registerMenuCommand( (enabled ? '✅ 世强免登录-已启用(点击禁用)' : '⛔ 世强免登录-已禁用(点击启用)'), function () { enabled = !enabled; GM_setValue(STORAGE_KEY, enabled); if (!enabled) { showCloseBtn(); alert('已禁用自动关闭世强登录弹窗,刷新页面后可正常登录。'); } else { alert('已启用世强免登录浏览,刷新页面后生效。'); } } ); } /* ==================================================================== * * 第二部分:立创商城搜索限流恢复 * * ==================================================================== */ /** * Cookie 删除白名单:仅删除主域与关键子域的 Cookie。 * 原因:GM_cookie 按具体子域要求授权(如 overseas.szlcsc.com 会单独弹授权窗), * 逐一授权体验差;且限制标识分布在主域/关键子域,无关子域(如海外站)可跳过。 */ function inDeleteWhitelist(domain) { var ALLOW = { 'szlcsc.com': 1, 'www.szlcsc.com': 1, 'so.szlcsc.com': 1, 'pro.szlcsc.com': 1, 'jlc.com': 1, 'passport.jlc.com': 1, 'ickey.cn': 1, 'search.ickey.cn': 1, 'www.ickey.cn': 1, 'passport.ickey.cn': 1 }; var d = (domain || '').replace(/^\./, ''); return !!ALLOW[d]; } /** * 列出指定域的全部 Cookie(GM_cookie,含 HttpOnly),失败/超时返回 null。 * 供清理(cleanGuestState)、二次校验、预热统计复用。 * 超时 8 秒:ScriptCat 首次对某域调用 GM_cookie 时会弹授权窗,需给用户响应时间。 */ function listCookies(domain) { return new Promise(function (resolve) { var settled = false; var timer = setTimeout(function () { if (!settled) { settled = true; resolve(null); } }, 8000); try { GM_cookie('list', { domain: domain }, function (a, b) { if (settled) return; settled = true; clearTimeout(timer); // 兼容 (cookies, error) 与 (error, cookies) 两种回调签名 var cookies = (a && typeof a === 'object') ? a : ((b && typeof b === 'object') ? b : null); resolve(cookies); }); } catch (e) { if (!settled) { settled = true; clearTimeout(timer); resolve(null); } } }); } function initLcscRecovery() { // 仅在登录页且 redirectUrl 指向立创商城时生效 if (location.pathname.indexOf('/login') !== 0) return; var redirectUrl = ''; try { redirectUrl = new URL(location.href).searchParams.get('redirectUrl') || ''; } catch (e) { return; } var target = null; try { target = new URL(redirectUrl); } catch (e) {} if (!target || !/(^|\.)szlcsc\.com$/.test(target.hostname)) return; // 剥离跟踪参数:lcsc_vid(访客ID)会让服务端重新关联被限的旧身份,spm 为埋点参数 try { target.searchParams.delete('lcsc_vid'); target.searchParams.delete('spm'); } catch (e) {} var KEY_ENABLED = 'lcsc_auto_recover_enabled'; var KEY_FAIL_AT = 'lcsc_recover_fail_at'; var KEY_VERSION = 'lcsc_script_version'; var SCRIPT_VERSION = '3.1.0'; var COOLDOWN = 30 * 60 * 1000; // 恢复失败后的自动尝试冷却时长 var BOUNCE_WINDOW = 60 * 1000; // 60 秒内弹回登录页 = 恢复失败 var AUTO_DELAY = 2000; // 先给自动登录接口留 2 秒(若有有效会话会被自动登录带走) // 版本更新时清除旧的失败冷却记录:新版本的恢复逻辑应获得立即重试的机会, // 避免升级后仍被旧版本的失败记录压制 30 分钟 if (GM_getValue(KEY_VERSION, '') !== SCRIPT_VERSION) { GM_setValue(KEY_VERSION, SCRIPT_VERSION); GM_setValue(KEY_FAIL_AT, 0); } var enabled = GM_getValue(KEY_ENABLED, true); var failedAt = GM_getValue(KEY_FAIL_AT, 0); var inCooldown = Date.now() - failedAt < COOLDOWN; var ui = buildBar(target.href, doRecover); // 完整恢复流程:清理 → 设跨域标记 → 预热拿新身份 → 带诊断信息跳回。 // 诊断数据同时写入 GM 存储,弹回后可在提示条上看到上次实际执行情况, // 便于定位"清理不彻底/预热未种入新身份"等执行层问题。 function doRecover() { ui.setStatus('正在重置游客会话(清理 Cookie)…'); cleanGuestState().then(function (stats) { // 通知商城域(so/www.szlcsc.com)的脚本清理它们本域的本地存储 GM_setValue('lcsc_storage_clean_flag', Date.now()); ui.setStatus('正在获取新的游客身份…'); warmUpHomepage().then(function (warm) { var diag = '上次诊断[清Cookie: sz删' + stats.szlcscDeleted + '剩' + stats.szlcscLeft + (stats.szlcscSkipped ? '(跳' + stats.szlcscSkipped + ')' : '') + '/jlc删' + stats.jlcDeleted + '剩' + stats.jlcLeft + (stats.jlcSkipped ? '(跳' + stats.jlcSkipped + ')' : ''); if (stats.listFailed) diag += ' ⚠️Cookie读取失败:' + stats.listFailed; if (stats.szLeftNames) diag += ' sz残留[' + stats.szLeftNames + ']'; if (stats.jlcLeftNames) diag += ' jlc残留[' + stats.jlcLeftNames + ']'; diag += ' 预热:HTTP' + warm.status + '/sz现有' + warm.szTotal + ']'; GM_setValue('lcsc_last_diag', diag); try { sessionStorage.setItem('sk_lcsc_attempt_at', String(Date.now())); } catch (e) {} ui.setStatus('正在返回搜索结果…'); setTimeout(function () { // 跳回请求不携带 Referer:来自登录页的搜索请求可能触发服务端风控 try { var meta = document.createElement('meta'); meta.setAttribute('name', 'referrer'); meta.setAttribute('content', 'no-referrer'); (document.head || document.documentElement).appendChild(meta); } catch (e) {} location.replace(target.href); }, 600); }); }); } if (!enabled) { ui.setStatus('已禁用自动恢复。可点击「重试搜索」手动执行,或直接登录账号。'); return; } if (inCooldown) { var lastDiag = GM_getValue('lcsc_last_diag', ''); ui.setStatus('上次自动恢复未生效,30 分钟内已暂停自动尝试。' + lastDiag + ' 可点「重试搜索」立即再试,或直接登录。'); return; } // 弹回检测:上一次恢复尝试发生在 60 秒内 → 说明跳回搜索后立刻又被拦,恢复失败 var lastAttemptAt = 0; try { lastAttemptAt = parseInt(sessionStorage.getItem('sk_lcsc_attempt_at') || '0', 10) || 0; } catch (e) {} if (lastAttemptAt && Date.now() - lastAttemptAt < BOUNCE_WINDOW) { GM_setValue(KEY_FAIL_AT, Date.now()); try { sessionStorage.removeItem('sk_lcsc_attempt_at'); } catch (e) {} var bounceDiag = GM_getValue('lcsc_last_diag', ''); ui.setStatus('自动重置未生效,已暂停 30 分钟内自动尝试。' + bounceDiag + ' 可手动重试。'); return; } // 正常流程:延迟后自动重置游客会话并跳回搜索 var autoTimer = setTimeout(doRecover, AUTO_DELAY); // 若用户抢先点了「重试搜索」,取消自动定时器避免重复执行 ui.onRetry(function () { clearTimeout(autoTimer); }); // 用户开始操作登录页(真实键鼠事件)→ 取消自动恢复,避免影响正常登录 // 注:点击脚本自身的提示条(重试/返回首页/关闭)不算登录操作 ['pointerdown', 'keydown'].forEach(function (evt) { document.addEventListener(evt, function (e) { if (!e.isTrusted) return; var t = e.target; if (t && t.closest && t.closest('#sk-lcsc-bar')) return; clearTimeout(autoTimer); ui.setStatus('已暂停自动返回(检测到您正在操作登录)。如需免登录搜索可点击「重试搜索」。'); }, true); }); // 菜单开关 GM_registerMenuCommand( (enabled ? '✅ 立创搜索自动恢复-已启用(点击禁用)' : '⛔ 立创搜索自动恢复-已禁用(点击启用)'), function () { enabled = !enabled; GM_setValue(KEY_ENABLED, enabled); alert('立创搜索自动恢复已' + (enabled ? '启用' : '禁用') + '。'); } ); } /** * 重置立创/嘉立创游客会话(返回 Promise,resolve 清理统计用于诊断): * 1. GM_cookie 清理 szlcsc.com 与 jlc.com 域下全部 Cookie(含 HttpOnly), * 保留游客购物车(currentCartVo)与搜索历史(searchHistoryRecord); * 删除分两轮:第一轮传完整 Cookie 对象(含 partitionKey,分区 Cookie 需要); * 第二轮对仍残留的用 url 变体重删,最终统计剩余数与残留名单; * 2. 清空 passport.jlc.com 域全部 localStorage/sessionStorage/IndexedDB/Cache; * 3. 兜底:用 document.cookie 清理 JS 可见 Cookie。 * 注:能停留在登录页说明当前无有效 SSO 会话(有效会话会被 auto-login 接口 * 自动登录带走),因此清理不会导致已登录账号掉线。 */ function cleanGuestState() { var KEEP = { currentCartVo: 1, searchHistoryRecord: 1 }; var stats = { szlcscDeleted: 0, jlcDeleted: 0, szlcscLeft: -1, jlcLeft: -1, szLeftNames: '', jlcLeftNames: '', szlcscSkipped: 0, jlcSkipped: 0, listFailed: '' }; // 等待删除回调完成再返回,避免"还没删完就跳转"导致恢复失败 // 传入完整 Cookie 对象:分区 Cookie(Partitioned)删除时需要 partitionKey 匹配, // 只传 name/domain/path 会静默失败(实测"删38剩40"的原因) // 超时 10 秒:删除可能触发 ScriptCat 的分域授权弹窗,需给用户响应时间 function deleteCookie(c) { return new Promise(function (resolve) { var settled = false; function done() { if (settled) return; settled = true; clearTimeout(timer); resolve(); } var timer = setTimeout(done, 10000); try { GM_cookie('delete', c, done); } catch (e) { done(); } }); } // 第二轮删除:url 变体(domain 转 url + name + partitionKey),换一种匹配方式 function deleteCookieByUrl(c) { return new Promise(function (resolve) { var settled = false; function done() { if (settled) return; settled = true; clearTimeout(timer); resolve(); } var timer = setTimeout(done, 10000); try { var host = (c.domain || '').replace(/^\./, ''); GM_cookie('delete', { url: 'https://' + host + (c.path || '/'), name: c.name, partitionKey: c.partitionKey }, done); } catch (e) { done(); } }); } var domains = ['szlcsc.com', 'jlc.com']; return Promise.all(domains.map(function (d) { function record(left) { var n = left ? left.length : (left === null ? -1 : 0); var names = (left || []).filter(function (c) { return c.name && !KEEP[c.name]; }) .slice(0, 6).map(function (c) { return c.name; }).join(','); if (d === 'szlcsc.com') { stats.szlcscLeft = n; stats.szLeftNames = names; } else { stats.jlcLeft = n; stats.jlcLeftNames = names; } } return listCookies(d).then(function (cookies) { if (!cookies) { // list 失败(超时/异常/未授权),记录到诊断信息 stats.listFailed = (stats.listFailed ? stats.listFailed + '+' : '') + d; cookies = []; } var tasks = []; var skipped = 0; cookies.forEach(function (c) { if (!c || !c.name || KEEP[c.name]) return; // 白名单过滤:跳过无关子域 Cookie(如 overseas.szlcsc.com), // 避免逐个子域触发 ScriptCat 授权弹窗 if (!inDeleteWhitelist(c.domain)) { skipped++; return; } tasks.push(deleteCookie(c)); }); if (d === 'szlcsc.com') { stats.szlcscDeleted = tasks.length; stats.szlcscSkipped = skipped; } else { stats.jlcDeleted = tasks.length; stats.jlcSkipped = skipped; } // 兜底:JS 可见 Cookie 用 document.cookie 再清一遍(仅本域) document.cookie.split(';').forEach(function (pair) { var name = pair.split('=')[0].trim(); if (name && !KEEP[name]) { document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=' + d; } }); return Promise.all(tasks).then(function () { // 二次校验:删除后重新 list,对仍残留的用 url 变体做第二轮删除 return listCookies(d).then(function (left) { if (!left) { record(null); return; } var retry = left.filter(function (c) { return c.name && !KEEP[c.name] && inDeleteWhitelist(c.domain); }); if (!retry.length) { record(left); return; } return Promise.all(retry.map(deleteCookieByUrl)).then(function () { return listCookies(d).then(function (left2) { record(left2); }); }); }); }); }); })).then(function () { try { // 清空登录页域(passport.jlc.com)的全部本地存储(含设备指纹键,如 // jlcCasClientUuid、JlcTrackData、__00b204e9800998__ 等)。 // 游客购物车/搜索历史存在 szlcsc.com 域,不受影响; // 弹回检测时间戳在本函数返回之后才写入,不受影响。 localStorage.clear(); sessionStorage.clear(); } catch (e) {} // IndexedDB / Cache Storage 里的设备数据也一并清掉(尽力而为,异步不阻塞) try { if (indexedDB.databases) { indexedDB.databases().then(function (dbs) { dbs.forEach(function (db) { try { indexedDB.deleteDatabase(db.name); } catch (e) {} }); }); } } catch (e) {} try { if (window.caches) { caches.keys().then(function (keys) { keys.forEach(function (k) { try { caches.delete(k); } catch (e) {} }); }); } } catch (e) {} return stats; }); } /** * 清理 Cookie 后先匿名访问一次商城首页(默认携带并保存 Cookie): * 让服务端通过 Set-Cookie 分配全新游客身份,模拟"新游客先逛首页再搜索"的 * 正常流程。resolve { status, szTotal } 供诊断展示——szTotal 为预热后 * szlcsc.com 域 Cookie 总数,与清理后的剩余数对比可判断新身份是否已种入; * 请求失败/超时则放行——预热只是提高成功率的手段,不阻塞恢复。 */ function warmUpHomepage() { return new Promise(function (resolve) { var settled = false; var result = { status: 0, szTotal: -1 }; function done() { if (settled) return; settled = true; clearTimeout(timer); resolve(result); } var timer = setTimeout(done, 14000); // 预热 4s + list 统计(含授权等待)8s,放宽兜底 try { GM_xmlhttpRequest({ method: 'GET', url: 'https://www.szlcsc.com/', timeout: 4000, onload: function (resp) { if (resp && resp.status) result.status = resp.status; // 预热完成后统计 szlcsc.com 域 Cookie 总数(Set-Cookie 是否写入) listCookies('szlcsc.com').then(function (cookies) { result.szTotal = cookies ? cookies.length : -1; done(); }); }, onerror: done, ontimeout: done, onabort: done }); } catch (e) { done(); } }); } /* ==================================================================== * * 第三部分:立创商城域本地存储清理(配合恢复流程) * * ==================================================================== */ /** * 运行在 so.szlcsc.com / www.szlcsc.com 域: * 登录页发起会话恢复时会设置 lcsc_storage_clean_flag(GM 存储跨域共享), * 这里读到近期标记后清理本域 localStorage/sessionStorage/IndexedDB/Cache 中的 * 埋点/指纹数据(如 JlcTrackData、keyPair 等),防止页面 JS 读取后上报、 * 让服务端重新认出旧身份。 * 标记用后即删(且 5 分钟过期),正常浏览时本函数直接返回,零副作用。 */ function initLcscStorageClean() { var KEY_FLAG = 'lcsc_storage_clean_flag'; var flag = GM_getValue(KEY_FLAG, 0); if (!flag || Date.now() - flag > 5 * 60 * 1000) return; GM_deleteValue(KEY_FLAG); var KEEP = { currentCartVo: 1, searchHistoryRecord: 1 }; try { Object.keys(localStorage).forEach(function (k) { if (!KEEP[k]) localStorage.removeItem(k); }); } catch (e) {} try { sessionStorage.clear(); } catch (e) {} try { if (indexedDB.databases) { indexedDB.databases().then(function (dbs) { dbs.forEach(function (db) { try { indexedDB.deleteDatabase(db.name); } catch (e) {} }); }); } } catch (e) {} try { if (window.caches) { caches.keys().then(function (keys) { keys.forEach(function (k) { try { caches.delete(k); } catch (e) {} }); }); } } catch (e) {} } /** * 在登录页顶部显示提示条 * recover: 完整恢复流程回调(与自动恢复一致:清理→预热→跳回) * 返回 { setStatus(text) , onRetry(fn) } 供外部控制 */ function buildBar(searchUrl, recover) { var bar = document.createElement('div'); bar.id = 'sk-lcsc-bar'; bar.style.cssText = [ 'position:fixed', 'top:0', 'left:0', 'right:0', 'z-index:2147483647', 'display:flex', 'align-items:center', 'gap:12px', 'padding:10px 16px', 'box-sizing:border-box', 'background:#1f2937', 'color:#f9fafb', 'font:13px/1.5 -apple-system,"Microsoft YaHei","Segoe UI",sans-serif', 'box-shadow:0 2px 10px rgba(0,0,0,.35)' ].join(';'); var icon = document.createElement('span'); icon.textContent = '立创'; icon.style.cssText = 'flex:none;background:#e6a23c;color:#1f2937;font-weight:700;border-radius:4px;padding:2px 6px;font-size:12px'; var text = document.createElement('div'); text.style.cssText = 'flex:1;min-width:0'; var title = document.createElement('div'); title.textContent = '搜索次数达到游客上限,被强制跳转到登录页'; title.style.cssText = 'font-weight:600'; var status = document.createElement('div'); status.textContent = '即将自动重置游客会话并返回搜索…'; // 允许换行:诊断信息(清理统计/预热状态)较长,需完整可见 status.style.cssText = 'color:#d1d5db;font-size:12px;white-space:normal;word-break:break-all'; text.appendChild(title); text.appendChild(status); var actions = document.createElement('div'); actions.style.cssText = 'flex:none;display:flex;gap:8px;align-items:center'; var retry = document.createElement('button'); retry.textContent = '重试搜索'; retry.style.cssText = 'background:#2563eb;color:#fff;border:none;border-radius:4px;padding:6px 12px;font-size:13px;cursor:pointer'; var home = document.createElement('a'); home.textContent = '返回商城首页'; home.href = 'https://www.szlcsc.com/'; home.style.cssText = 'background:#374151;color:#fff;border-radius:4px;padding:6px 12px;font-size:13px;text-decoration:none;cursor:pointer'; var close = document.createElement('span'); close.textContent = '×'; close.title = '隐藏提示'; close.style.cssText = 'color:#9ca3af;font-size:20px;cursor:pointer;line-height:1;padding:0 2px'; actions.appendChild(retry); actions.appendChild(home); actions.appendChild(close); bar.appendChild(icon); bar.appendChild(text); bar.appendChild(actions); (document.body || document.documentElement).appendChild(bar); close.addEventListener('click', function () { bar.remove(); }); retry.addEventListener('click', function () { try { sessionStorage.removeItem('sk_lcsc_attempt_at'); } catch (e) {} GM_setValue('lcsc_recover_fail_at', 0); retry.textContent = '重置中…'; retry.disabled = true; // 点击本身就是一次交互,需要直接走恢复流程(与自动恢复共用同一函数) if (typeof recover === 'function') recover(); else setTimeout(function () { location.replace(searchUrl); }, 400); }); return { setStatus: function (t) { status.textContent = t; }, onRetry: function (fn) { retry.addEventListener('click', fn); } }; } /* ==================================================================== * * 第三部分:云汉芯城(ickey.cn)广告拦截 * * ==================================================================== */ /** * 拦截搜索页等弹出的广告(已实测分析其 DOM 结构): * 1. "新人福利"优惠券弹窗: *
全屏遮罩 *
广告弹窗(含优惠券图片与"一键领取"按钮) * 关闭按钮 *
*
* 2. 通用浮窗弹窗:.js_common_fuchuang_pc_dialog(站点通用 PC 浮窗广告) * 3. 其他浮窗:.xkfc * 广告由站点脚本延迟触发弹出,与登录状态/访问次数相关。 * 双保险策略: * 1. CSS 强制隐藏(display:none !important):广告弹出即被压制,遮罩也不再阻挡页面; * 2. MutationObserver 兜底:万一 CSS 被内联样式覆盖,发现广告实际可见时 * 直接写入内联 display:none !important 强制压掉(比模拟点击关闭按钮更可靠, * 不依赖站点关闭逻辑、无误点风险)。 */ function initIkeyAdBlock() { var KEY = 'ickey_adblock_enabled'; var enabled = GM_getValue(KEY, true); var AD_SELECTORS = ['.doubule-eleven-bg', '.doubule-eleven-pop', '.js_common_fuchuang_pc_dialog', '.xkfc']; function applyCss() { if (!enabled) return; try { // addStyleEarly:document-start 即注入(head 未就绪时挂 documentElement), // 广告从插入 DOM 的第一帧起就被压制,不闪现 addStyleEarly(AD_SELECTORS.join(', ') + ' { display: none !important; }'); } catch (e) {} } // 兜底:广告已实际可见(CSS 被内联样式覆盖等场景)→ 内联样式强制隐藏 function tryClose() { AD_SELECTORS.forEach(function (sel) { var el = document.querySelector(sel); if (!el) return; var cs = getComputedStyle(el); if (cs.display === 'none' || cs.visibility === 'hidden' || el.offsetHeight === 0) return; el.style.setProperty('display', 'none', 'important'); }); } applyCss(); // 广告是延迟弹出的,监听 DOM 变化持续压制(tryClose 很轻量,无需去抖) var mo = new MutationObserver(tryClose); function start() { mo.observe(document.documentElement, { childList: true, subtree: true }); } if (document.body) start(); else document.addEventListener('DOMContentLoaded', start); GM_registerMenuCommand( (enabled ? '关闭' : '开启') + '芯城(ickey.cn)广告拦截', function () { enabled = !enabled; GM_setValue(KEY, enabled); alert('芯城广告拦截已' + (enabled ? '开启' : '关闭') + ',刷新页面后生效'); } ); } /** * 自动关闭搜索页弹出的登录提醒弹窗并恢复搜索(Bootstrap Modal,已实测分析): * - 弹窗:.search-remind-dialog(页面中有多个实例,游客搜索多次后弹出, * 标题为"登录后搜索",含账号密码/手机免密登录表单); * 弹窗 DOM 页面加载时就已存在,弹出只是把 display 从 none 改为 block * (属性变化),因此 MutationObserver 必须监听 attributes 才能感知弹出; * - 关闭按钮:.close.clearBomFile(带 data-dismiss="modal"),但站点会把 * 按钮内联 style="display:none" 藏起来 → 点击前先恢复显示再模拟点击, * 走 Bootstrap 自身关闭逻辑(自动恢复滚动、清理遮罩); * - 实测:弹窗弹出时站点已中止搜索结果渲染(结果区被隐藏、.search-mask 遮罩 * 挡住结果列表),关闭弹窗不会恢复结果 → 搜索页上需重置游客会话 * (GM_cookie 清 ickey.cn 全域 Cookie,双轮删除防分区 Cookie)后刷新页面, * 让站点以全新游客身份重新执行搜索; * - 防死循环:刷新后 60 秒内又弹窗 → 判定恢复失败,进入 30 分钟冷却(只关弹窗不刷新); * - 登录让位:弹窗出现后先观察 1.2 秒,期间用户点击/输入弹窗(想登录)→ 不做任何处理。 * 注:验证码弹窗(.search-service-arrest-0509-bom)是反爬人机验证, * 不做自动关闭,以免影响正常搜索功能。 */ function initIkeyLoginClose() { var KEY = 'ickey_login_close_enabled'; var KEY_FAIL = 'ikey_recover_fail_at'; var ATTEMPT_KEY = 'sk_ikey_attempt_at'; var BOUNCE_WINDOW = 60 * 1000; // 刷新后弹回检测窗口 var COOLDOWN = 30 * 60 * 1000; // 恢复失败后的冷却期 var RECOVER_DELAY = 1200; // 登录让位观察窗口 var enabled = GM_getValue(KEY, true); var pending = false; // 防止同一弹窗重复调度 function forceHide(modal) { modal.style.setProperty('display', 'none', 'important'); modal.setAttribute('aria-hidden', 'true'); // Bootstrap modal 会锁定 body 滚动并可能残留遮罩层,手动恢复/清理 document.body.style.overflow = ''; document.body.classList.remove('modal-open'); var backdrops = document.querySelectorAll('.modal-backdrop'); for (var i = 0; i < backdrops.length; i++) { // 仅清理视口附近的遮罩(left 在 ±5000px 内), // 避免误删站点故意放到屏幕外(left:-9999px 等)的模板/传送门节点 var r = backdrops[i].getBoundingClientRect(); if (r.left > -5000 && r.left < 5000) backdrops[i].remove(); } } // 等待删除回调完成(10 秒兜底:删除可能触发 ScriptCat 分域授权弹窗) function deleteCookieFull(c) { return new Promise(function (resolve) { var settled = false; function done() { if (settled) return; settled = true; clearTimeout(timer); resolve(); } var timer = setTimeout(done, 10000); try { GM_cookie('delete', c, done); } catch (e) { done(); } }); } // url 变体删除(兜底,处理完整对象删除失败的情况) function deleteCookieByUrl(c) { return new Promise(function (resolve) { var settled = false; function done() { if (settled) return; settled = true; clearTimeout(timer); resolve(); } var timer = setTimeout(done, 10000); try { var h = (c.domain || '').replace(/^\./, ''); GM_cookie('delete', { url: 'https://' + h + (c.path || '/'), name: c.name, partitionKey: c.partitionKey }, done); } catch (e) { done(); } }); } function isSearchPage() { return /[?&]keyword=/.test(location.search); } // 重置游客会话:清 ickey.cn 全域 Cookie(两轮删除,白名单过滤)后刷新页面重新搜索 function recoverAndReload() { listCookies('ickey.cn').then(function (cookies) { var tasks = (cookies || []).filter(function (c) { return c && c.name && inDeleteWhitelist(c.domain); }).map(deleteCookieFull); return Promise.all(tasks).then(function () { return listCookies('ickey.cn'); }).then(function (left) { var retry = (left || []).filter(function (c) { return c && c.name && inDeleteWhitelist(c.domain); }).map(deleteCookieByUrl); return Promise.all(retry); }); }).then(function () { try { sessionStorage.setItem(ATTEMPT_KEY, String(Date.now())); } catch (e) {} location.reload(); }); } function handleModal(modal) { if (pending) return; pending = true; // 登录让位观察:1.2 秒内用户对弹窗有交互(点击/输入)→ 想正常登录,不处理 var interacted = false; function onUser() { interacted = true; } modal.addEventListener('pointerdown', onUser, true); modal.addEventListener('keydown', onUser, true); modal.addEventListener('focusin', onUser, true); setTimeout(function () { modal.removeEventListener('pointerdown', onUser, true); modal.removeEventListener('keydown', onUser, true); modal.removeEventListener('focusin', onUser, true); pending = false; if (interacted) return; // 关闭弹窗:优先走站点自身逻辑(Bootstrap data-dismiss) var btn = modal.querySelector('.close.clearBomFile') || modal.querySelector('.close-goods-btn.clearBomFile'); if (btn) { if (btn.style.display === 'none') btn.style.display = ''; btn.click(); setTimeout(function () { if (getComputedStyle(modal).display !== 'none') forceHide(modal); }, 300); } else { forceHide(modal); } // 仅搜索页:关闭弹窗不会恢复被中止的搜索结果,需重置会话刷新 if (!isSearchPage()) return; var now = Date.now(); var failAt = GM_getValue(KEY_FAIL, 0); if (failAt && now - failAt < COOLDOWN) return; // 冷却中,只关弹窗 var attemptAt = 0; try { attemptAt = parseInt(sessionStorage.getItem(ATTEMPT_KEY) || '0', 10) || 0; } catch (e) {} if (attemptAt && now - attemptAt < BOUNCE_WINDOW) { // 刷新后立刻又弹窗 → 恢复无效,进入冷却 GM_setValue(KEY_FAIL, now); try { sessionStorage.removeItem(ATTEMPT_KEY); } catch (e) {} return; } recoverAndReload(); }, RECOVER_DELAY); } function closeModals() { if (!enabled) return; var modals = document.querySelectorAll('.search-remind-dialog'); for (var i = 0; i < modals.length; i++) { var modal = modals[i]; var cs = getComputedStyle(modal); if (cs.display === 'none' || modal.offsetHeight === 0) continue; // 未弹出 handleModal(modal); } } closeModals(); // 弹窗为延迟/条件弹出:监听 DOM 变化 + 属性变化(display 切换)持续处理。 // attributeFilter 限定 style/class/aria-hidden,避免其他属性变化频繁触发。 var mo = new MutationObserver(closeModals); function start() { mo.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class', 'aria-hidden'] }); } if (document.body) start(); else document.addEventListener('DOMContentLoaded', start); GM_registerMenuCommand( (enabled ? '关闭' : '开启') + '芯城(ickey.cn)登录弹窗自动关闭', function () { enabled = !enabled; GM_setValue(KEY, enabled); alert('芯城登录弹窗自动关闭已' + (enabled ? '开启' : '关闭') + ',刷新页面后生效'); } ); } /* ==================================================================== * * 第五部分:汽车之家视频弹窗拦截 * * ==================================================================== */ /** * 自动关闭汽车之家页面弹出的播放器小窗口(合并自独立脚本"汽车之家删视频弹窗"): * - 弹窗特征:div[class*="video_player_container"](模糊匹配 CSS Modules 哈希类, * 如 .style_video_player_container___kqQY——站点重新构建后哈希变化也能命中, * 故不使用带哈希的精确类名)、iframe.liveplayer-box(直播播放器弹窗); * - 原脚本用 300ms 轮询 remove(),此处升级为: * 1. CSS 预隐藏(document-start 注入):弹窗从插入 DOM 第一帧起就被压制,不闪现; * 2. MutationObserver 事件驱动删除:插入即删(站点重新插入会再次触发), * 比轮询更精准且零空转开销; * 3. 删除前校验节点位置(left 在 ±5000px 内),避免误删站点屏幕外的模板节点。 */ function initAutohomeVideoBlock() { var KEY = 'autohome_video_block_enabled'; var enabled = GM_getValue(KEY, true); var PLAYER_SELECTORS = ['div[class*="video_player_container"]', 'iframe.liveplayer-box']; function applyCss() { if (!enabled) return; try { addStyleEarly(PLAYER_SELECTORS.join(', ') + ' { display: none !important; }'); } catch (e) {} } applyCss(); function removePlayers() { if (!enabled) return; PLAYER_SELECTORS.forEach(function (sel) { var els = document.querySelectorAll(sel); for (var i = 0; i < els.length; i++) { // 仅删除视口附近的节点,避免误删站点故意放到屏幕外的模板/传送门节点 try { var r = els[i].getBoundingClientRect(); if (r.left > -5000 && r.left < 5000) els[i].remove(); } catch (e) {} } }); } var mo = new MutationObserver(removePlayers); function start() { mo.observe(document.documentElement, { childList: true, subtree: true }); } if (document.body) start(); else document.addEventListener('DOMContentLoaded', start); onBodyReady(removePlayers); GM_registerMenuCommand( (enabled ? '关闭' : '开启') + '汽车之家(autohome.com.cn)视频弹窗拦截', function () { enabled = !enabled; GM_setValue(KEY, enabled); alert('汽车之家视频弹窗拦截已' + (enabled ? '开启' : '关闭') + ',刷新页面后生效'); } ); } })();