Greasy Fork is available in English.
Fuckrickroll
当前为
// ==UserScript==
// @name anti-rickroll
// @namespace http://tampermonkey.net/
// @version 11.2
// @description Fuckrickroll
// @author dext
// @match *://*/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @connect anti-rickroll.dext.top
// @run-at document-start
// ==/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 包含 #force-pass,则当前页面彻底不扫描、不拦截
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.85); 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; transition: 0.2s; }
.btn-safe { background:#f0f0f0; color:#333; }
.btn-danger { background:#ff4444; color:#fff; font-size:11px; opacity:0.6; }
.btn-danger:hover { opacity:1; }
a.rickroll-danger { outline: 2px dashed #ff4444 !important; outline-offset: 2px; background: rgba(255,0,0,0.1) !important; }
`);
// 辅助:停止页面一切媒体播放
function silencePage() {
document.querySelectorAll('video, audio').forEach(m => {
m.pause();
m.muted = true;
});
}
// 1. 脱壳逻辑
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;
}
// 2. 核心拦截渲染 (支持新标签页和当前页)
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 = `
<div class="rick-card">
<div style="font-size:50px">🚫</div>
<h2 style="color:#ff4444; margin:10px 0;">${title}</h2>
<p style="color:#666; font-size:14px;">目标已被识别为 <b>Rickroll</b>。<br>页面已被安全冻结。</p>
<button class="rick-btn btn-safe" id="r-back">立刻返回</button>
<button class="rick-btn btn-danger" id="r-go">我非要看 (不再拦截)</button>
</div>`;
// 针对“入境拦截”,直接附加到 html 上
(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);
}
};
document.getElementById('r-go').onclick = () => {
clearInterval(silencer);
overlay.remove();
// 在当前 URL 后面打标,并重新加载以绕过脚本拦截
if (isIncoming) {
window.location.replace(window.location.href + (window.location.hash ? '&' : '#') + 'force-pass');
} else {
const a = document.createElement('a');
a.href = url + (url.includes('#') ? '&' : '#') + 'force-pass';
a.target = "_blank"; // 强制看的时候通常是在新标签页
document.body.appendChild(a);
a.click();
}
};
}
// 3. 入境自检
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) {}
}
});
}
// 4. 并发扫描
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();
}
});
}
function scanPage() {
const EXCLUDE = /\.(jpg|jpeg|png|gif|css|js|woff|zip|pdf|mp4)($|\?)/i;
document.querySelectorAll('a[href]').forEach(a => {
const url = getRealUrl(a.href);
if (!url.startsWith('http') || url.includes(window.location.hostname) || EXCLUDE.test(url) || cache.has(url)) return;
cache.set(url, 'pending');
queue.push(url);
});
processQueue();
}
// 5. 点击接管
window.addEventListener('click', function(e) {
const a = e.target.closest('a');
if (!a || !a.href || !a.href.startsWith('http')) return;
if (a.href.includes('force-pass') || a.dataset.rickSafe === '1') return;
const url = getRealUrl(a.href);
e.preventDefault();
e.stopPropagation();
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) {
renderOverlay("重定向拦截", url, false);
} else {
a.dataset.rickSafe = '1';
a.click();
}
} catch (e) { a.dataset.rickSafe = '1'; a.click(); }
}
});
}, true);
checkIncoming();
window.addEventListener('DOMContentLoaded', scanPage);
setInterval(scanPage, 5000);
})();