Greasy Fork is available in English.
申诉
当前为
// ==UserScript==
// @name anti-rickroll
// @version 12.6
// @description 申诉
// @author dext
// @match *://*/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @connect anti-rickroll.dext.top
// @run-at document-start
// @namespace http://tampermonkey.net/
// ==/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;
// --- 0. 免死金牌判定 ---
if (window.location.hash.includes('force-pass') || window.location.search.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.98); z-index:2147483647; display:flex; justify-content:center; align-items:center; backdrop-filter:blur(25px); }
.rick-card { background:#fff; padding:40px; border-radius:24px; width:360px; text-align:center; border:6px solid #ff4444; box-shadow: 0 20px 60px rgba(0,0,0,0.8); font-family: sans-serif; }
.rick-btn { padding:15px; border-radius:12px; cursor:pointer; border:none; font-weight:bold; width:100%; margin-top:15px; font-size:16px; transition: 0.2s; }
.btn-safe { background:#eee; color:#333; }
.btn-safe:hover { background:#ddd; }
.btn-danger { background:#ff4444; color:#fff; font-size:11px; opacity:0.5; }
.btn-danger:hover { opacity:1; }
.btn-appeal { background: transparent; color: #888; font-size: 12px; margin-top: 10px; text-decoration: underline; cursor: pointer; border: none; }
#rick-report-btn { position: fixed; bottom: 20px; left: 20px; z-index: 2147483646; background: rgba(0,0,0,0.7); color: white; padding: 8px 15px; border-radius: 20px; cursor: pointer; font-size: 13px; backdrop-filter: blur(5px); border: 1px solid rgba(255,255,255,0.2); display: flex; align-items: center; gap: 8px; }
a.rickroll-danger { outline: 3px dashed #ff4444 !important; outline-offset: 2px; background: rgba(255,0,0,0.1) !important; }
`);
// --- 1. 工具函数 ---
function getCleanUrl(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');
if (u.hostname.includes('bing.com') && u.pathname.includes('/ck/a')) {
let rawU = u.searchParams.get('u');
if (rawU) { try { return atob(rawU.substring(2).replace(/-/g, '+').replace(/_/g, '/')); } catch (e) {} }
}
return u.origin + u.pathname + u.search;
} catch (e) { return url; }
}
function isInternal(url) {
try {
const t = new URL(url);
const curr = window.location.hostname;
if (curr.includes('bing.com') && t.pathname.includes('/ck/a')) return false;
return t.hostname === curr;
} catch (e) { return true; }
}
function silenceMedia() {
document.querySelectorAll('video, audio').forEach(m => { m.pause(); m.muted = true; });
}
function smartExit(isIncoming) {
if (!isIncoming) { document.getElementById('rick-breaker-overlay')?.remove(); return; }
if (document.referrer && !document.referrer.includes(window.location.hostname)) {
window.location.replace(document.referrer);
} else if (window.history.length > 1) {
window.history.back();
} else {
window.close(); setTimeout(() => { window.location.href = "about:blank"; }, 150);
}
}
// --- 2. 申诉逻辑 ---
function appealRickroll(url, btnElement) {
const originalText = btnElement.innerText;
btnElement.innerText = "正在提交申诉...";
btnElement.disabled = true;
GM_xmlhttpRequest({
method: "POST",
url: API_ENDPOINT,
data: JSON.stringify({
url: url,
isAppeal: true,
title: document.title,
snippet: document.body ? document.body.innerText.substring(0, 500) : ""
}),
headers: { "Content-Type": "application/json" },
onload: (res) => {
const d = JSON.parse(res.responseText);
if (!d.isRickroll) {
btnElement.innerText = "✅ 申诉成功!";
setTimeout(() => {
window.location.href = url + (url.includes('#') ? '&' : '#') + 'force-pass';
}, 1000);
} else {
btnElement.innerText = "❌ AI 依然认为是 Rickroll";
setTimeout(() => { btnElement.innerText = originalText; btnElement.disabled = false; }, 2000);
}
}
});
}
// --- 3. UI 渲染 ---
function renderOverlay(title, url, isIncoming = false) {
if (document.getElementById('rick-breaker-overlay')) return;
const silencer = setInterval(silenceMedia, 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:#444; font-size:13px; line-height:1.5;">此链接已被云端标记为 <b>Rickroll</b>。</p>
<button class="rick-btn btn-safe" id="r-back">${isIncoming ? '离开' : '关闭'}</button>
<button class="rick-btn btn-danger" id="r-go">我非要看</button>
<button class="btn-appeal" id="r-appeal">这是误报?点击申诉</button>
</div>`;
(document.body || document.documentElement).appendChild(overlay);
document.getElementById('r-back').onclick = () => { clearInterval(silencer); smartExit(isIncoming); };
document.getElementById('r-appeal').onclick = (e) => appealRickroll(url, e.target);
document.getElementById('r-go').onclick = () => {
clearInterval(silencer); overlay.remove();
const jumpUrl = url + (url.includes('#') ? '&' : '#') + 'force-pass';
if (isIncoming) window.location.replace(jumpUrl);
else { const a = document.createElement('a'); a.href = jumpUrl; a.target = "_blank"; a.click(); }
};
}
// --- 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 d = JSON.parse(res.responseText);
cache.set(url, { isRickroll: !!d.isRickroll, status: 'done' });
if (d.isRickroll) document.querySelectorAll(`a`).forEach(a => { if(getCleanUrl(a.href) === url) a.classList.add('rickroll-danger'); });
} catch (e) {}
activeRequests--; processQueue();
},
onerror: () => { activeRequests--; processQueue(); }
});
}
function scan() {
document.querySelectorAll('a[href]').forEach(a => {
const url = getCleanUrl(a.href);
if (!url.startsWith('http') || isInternal(url) || cache.has(url)) return;
cache.set(url, { isRickroll: false, status: 'pending' });
queue.push(url);
});
processQueue();
}
window.addEventListener('click', (e) => {
const a = e.target.closest('a');
if (!a || !a.href.startsWith('http')) return;
const url = getCleanUrl(a.href);
if (isInternal(url) || a.dataset.rickSafe === '1' || url.includes('force-pass')) return;
const res = cache.get(url);
if (res && res.status === 'done' && res.isRickroll) {
e.preventDefault(); e.stopPropagation();
renderOverlay("链路风险拦截", url, false);
return;
}
e.preventDefault(); e.stopPropagation();
GM_xmlhttpRequest({
method: "POST", url: API_ENDPOINT, data: JSON.stringify({ url }), headers: { "Content-Type": "application/json" },
onload: (res) => {
const d = JSON.parse(res.responseText);
cache.set(url, { isRickroll: !!d.isRickroll, status: 'done' });
if (d.isRickroll) renderOverlay("实时风险拦截", url, false);
else { a.dataset.rickSafe = '1'; a.click(); }
},
onerror: () => { a.dataset.rickSafe = '1'; a.click(); }
});
}, true);
function createReportButton() {
if (document.getElementById('rick-report-btn') || sessionStorage.getItem('rick-btn-hidden') === '1') return;
const btn = document.createElement('div');
btn.id = 'rick-report-btn';
btn.innerHTML = `<span id="rick-do-report">🛡️ 我被骗了!</span><span id="rick-close-report" style="margin-left:8px;opacity:0.5">×</span>`;
document.body.appendChild(btn);
document.getElementById('rick-do-report').onclick = () => {
const b = document.getElementById('rick-report-btn');
b.innerText = "🔍 AI 复审中...";
GM_xmlhttpRequest({
method: "POST", url: API_ENDPOINT, data: JSON.stringify({ url: window.location.href, isFeedback: true, title: document.title, snippet: document.body.innerText.substring(0, 800) }),
headers: { "Content-Type": "application/json" },
onload: (res) => {
if (JSON.parse(res.responseText).isRickroll) { b.innerText = "✅ 举报成功!"; renderOverlay("举报生效拦截", window.location.href, true); }
else { b.innerText = "❌ AI 判定安全"; setTimeout(() => b.remove(), 2000); }
}
});
};
document.getElementById('rick-close-report').onclick = (e) => { e.stopPropagation(); btn.remove(); sessionStorage.setItem('rick-btn-hidden', '1'); };
}
GM_xmlhttpRequest({
method: "POST", url: API_ENDPOINT, data: JSON.stringify({ url: window.location.href }), headers: { "Content-Type": "application/json" },
onload: (res) => { if (JSON.parse(res.responseText).isRickroll) { window.stop(); renderOverlay("入境风险拦截", window.location.href, true); } }
});
window.addEventListener('load', () => { createReportButton(); setInterval(scan, 4000); });
})();