// ==UserScript== // @name anti-rickroll // @namespace http://tampermonkey.net/ // @version 3.1 // @description 静默并行扫描,修复检测完成后不放行的问题 // @author dext // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect anti-rickroll.dext.top // @run-at document-idle // @downloadURL none // ==/UserScript== (function() { 'use strict'; const API_ENDPOINT = "https://anti-rickroll.dext.top"; const MAX_CONCURRENT = 10; const cache = new Map(); // URL -> {isRick: bool, status: 'pending'|'done'} const queue = []; let activeRequests = 0; GM_addStyle(` #rick-guard-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); z-index: 2147483647; display: flex; justify-content: center; align-items: center; backdrop-filter: blur(8px); } .rick-modal { background: #fff; padding: 30px; border-radius: 15px; width: 320px; text-align: center; border: 2px solid #ff4444; font-family: sans-serif; } .rick-btns { display: flex; gap: 10px; margin-top: 20px; } .rick-btn { flex: 1; padding: 12px; border-radius: 8px; cursor: pointer; border: none; font-weight: bold; } .btn-go { background: #ff4444; color: white; } .btn-cancel { background: #eee; } `); // 扫描控制核心 function processQueue() { if (queue.length === 0 || activeRequests >= MAX_CONCURRENT) return; const url = queue.shift(); activeRequests++; GM_xmlhttpRequest({ method: "POST", url: API_ENDPOINT, headers: { "Content-Type": "application/json" }, data: JSON.stringify({ url: url }), timeout: 6000, onload: (res) => { try { const data = JSON.parse(res.responseText); updateCache(url, !!data.isRickroll); } catch (e) { updateCache(url, false); } activeRequests--; processQueue(); }, onerror: () => { updateCache(url, false); activeRequests--; processQueue(); }, ontimeout: () => { updateCache(url, false); activeRequests--; processQueue(); } }); } function updateCache(url, result) { cache.set(url, { isRick: result, status: 'done' }); // 触发一个自定义事件,通知正在等待的点击逻辑 window.dispatchEvent(new CustomEvent('rick_checked_' + url, { detail: result })); } function scan() { document.querySelectorAll('a[href]').forEach(a => { const url = a.href; if (!url.startsWith('http') || cache.has(url)) return; cache.set(url, { isRick: false, status: 'pending' }); queue.push(url); processQueue(); }); } // 点击拦截与等待逻辑 window.addEventListener('click', function(e) { const a = e.target.closest('a'); if (!a || !a.href || !a.href.startsWith('http')) return; if (a.dataset.rickVerified === '1') return; // 已人工放行 const result = cache.get(a.href); // 情况1:已经在缓存里且判定为危险 if (result && result.status === 'done' && result.isRick) { e.preventDefault(); showWarning(a.href, a); return; } // 情况2:已经在缓存里且判定为安全 if (result && result.status === 'done' && !result.isRick) { return; // 正常放行 } // 情况3:正在检测中或尚未开始检测 e.preventDefault(); e.stopPropagation(); // 临时锁定,避免重复弹窗 if (a.dataset.rickWaiting === '1') return; a.dataset.rickWaiting = '1'; // 监听检测完成的信号 const checkHandler = (ev) => { const isRickroll = ev.detail; delete a.dataset.rickWaiting; if (isRickroll) { showWarning(a.href, a); } else { a.dataset.rickVerified = '1'; a.click(); // 安全,重新触发点击 } }; // 如果完全没在队列里,手动推入 if (!result) { cache.set(a.href, { isRick: false, status: 'pending' }); queue.unshift(a.href); // 优先插队扫描 processQueue(); } window.addEventListener('rick_checked_' + a.href, checkHandler, { once: true }); }, true); function showWarning(url, el) { const div = document.createElement('div'); div.id = 'rick-guard-overlay'; div.innerHTML = `
该链接被识别为 Rickroll 或钓鱼网页。