// ==UserScript== // @name anti-rickroll // @namespace http://tampermonkey.net/ // @version 11.3 // @description fuck-rickroll // @author dext // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect anti-rickroll.dext.top // @run-at document-start // @downloadURL none // ==/UserScript== (function() { 'use strict'; const API_ENDPOINT = "https://anti-rickroll.dext.top"; const cache = new Map(); const queue = []; let activeRequests = 0; const MAX_CONCURRENT = 3; // 如果 URL 包含强制放行标记,彻底退出 if (window.location.hash.includes('force-pass')) return; GM_addStyle(` #rick-breaker-overlay { position: fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.9); z-index:2147483647; display:flex; justify-content:center; align-items:center; backdrop-filter:blur(20px); } .rick-card { background:#fff; padding:40px; border-radius:24px; width:350px; text-align:center; border:5px solid #ff4444; box-shadow: 0 20px 50px rgba(0,0,0,0.5); font-family: sans-serif; } .rick-btn { padding:14px; border-radius:12px; cursor:pointer; border:none; font-weight:bold; width:100%; margin-top:12px; font-size:15px; } .btn-safe { background:#f0f0f0; color:#333; } .btn-danger { background:#ff4444; color:#fff; font-size:11px; opacity:0.6; } a.rickroll-danger { outline: 2px dashed #ff4444 !important; background: rgba(255,0,0,0.1) !important; } `); // 核心判定:是否为真正的内链 function isInternalLink(url) { try { const target = new URL(url); const current = window.location; // 只有协议和域名完全一致,才判定为内链 return target.protocol === current.protocol && target.hostname === current.hostname; } catch (e) { return true; // 无法解析的通常是相对路径,视为内链 } } // 脱壳逻辑 function getRealUrl(url) { try { const u = new URL(url); if (u.hostname.includes('google.com') && u.searchParams.has('q')) return u.searchParams.get('q'); if (u.hostname.includes('baidu.com') && u.searchParams.has('url')) return u.searchParams.get('url'); } catch (e) {} return url; } function silencePage() { document.querySelectorAll('video, audio').forEach(m => { m.pause(); m.muted = true; }); } // 拦截 UI 逻辑(兼容本页跳转和新页跳转) function renderOverlay(title, url, isIncoming = false) { if (document.getElementById('rick-breaker-overlay')) return; const silencer = setInterval(silencePage, 200); const overlay = document.createElement('div'); overlay.id = 'rick-breaker-overlay'; overlay.innerHTML = `
🚫

${title}

已拦截 Rickroll 风险链接。

`; (document.body || document.documentElement).appendChild(overlay); document.getElementById('r-back').onclick = () => { if (isIncoming && window.history.length > 1) { window.history.back(); } else { overlay.remove(); clearInterval(silencer); // 如果是本页强行跳过来的,点返回要尝试跳回 if (!isIncoming) window.stop(); } }; document.getElementById('r-go').onclick = () => { clearInterval(silencer); overlay.remove(); // 拼接强制放行 Hash const jumpUrl = url + (url.includes('#') ? '&' : '#') + 'force-pass'; window.location.href = jumpUrl; }; } // 入境自检 function checkIncoming() { const url = window.location.href; if (url.length < 25 || /google|baidu|bing/.test(window.location.hostname)) return; GM_xmlhttpRequest({ method: "POST", url: API_ENDPOINT, data: JSON.stringify({ url }), headers: { "Content-Type": "application/json" }, onload: (res) => { try { const data = JSON.parse(res.responseText); if (data.isRickroll) { silencePage(); renderOverlay("入境风险拦截", url, true); } } catch (e) {} } }); } // 并发预检 function processQueue() { if (queue.length === 0 || activeRequests >= MAX_CONCURRENT) return; const url = queue.shift(); activeRequests++; GM_xmlhttpRequest({ method: "POST", url: API_ENDPOINT, data: JSON.stringify({ url }), headers: { "Content-Type": "application/json" }, onload: (res) => { try { const data = JSON.parse(res.responseText); cache.set(url, data.isRickroll); if (data.isRickroll) { document.querySelectorAll('a').forEach(a => { if(getRealUrl(a.href) === url) a.classList.add('rickroll-danger'); }); } } catch (e) {} activeRequests--; processQueue(); }, onerror: () => { activeRequests--; processQueue(); } }); } function scanPage() { const EXCLUDE = /\.(jpg|jpeg|png|gif|css|js|woff|zip|pdf|mp4)($|\?)/i; document.querySelectorAll('a[href]').forEach(a => { const rawUrl = a.href; const realUrl = getRealUrl(rawUrl); // 严格跳过:1. 必须是 http 2. 必须不是内链 3. 排除静态资源 4. 没扫过 if (!realUrl.startsWith('http') || isInternalLink(realUrl) || EXCLUDE.test(realUrl) || cache.has(realUrl)) return; cache.set(realUrl, 'pending'); queue.push(realUrl); }); processQueue(); } // 点击接管 (核心:拦截本标签页点击) window.addEventListener('click', function(e) { const a = e.target.closest('a'); if (!a || !a.href || !a.href.startsWith('http')) return; const realUrl = getRealUrl(a.href); // 如果是内链,直接放行,不进入拦截逻辑 if (isInternalLink(realUrl)) return; // 如果已经带了标记,放行 if (realUrl.includes('force-pass') || a.dataset.rickSafe === '1') return; e.preventDefault(); e.stopPropagation(); GM_xmlhttpRequest({ method: "POST", url: API_ENDPOINT, data: JSON.stringify({ url: realUrl }), headers: { "Content-Type": "application/json" }, onload: (res) => { try { const data = JSON.parse(res.responseText); if (data.isRickroll) { renderOverlay("重定向拦截", realUrl, false); } else { a.dataset.rickSafe = '1'; // 判定是否需要新开窗口 if (a.target === '_blank' || e.ctrlKey || e.metaKey) { window.open(realUrl, '_blank'); } else { window.location.href = realUrl; } } } catch (e) { window.location.href = realUrl; } } }); }, true); checkIncoming(); window.addEventListener('DOMContentLoaded', scanPage); setInterval(scanPage, 5000); })();