Greasy Fork

Greasy Fork is available in English.

搜索引擎净化器 v2.0 旗舰版 (GPT-4o智能+完整仪表盘)

GPT-4o智能判定+缓存保护+误判回滚+完整日志仪表盘+反检测伪装,长期稳定搜索净化方案!

// ==UserScript==
// @name         搜索引擎净化器 v2.0 旗舰版 (GPT-4o智能+完整仪表盘)
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  GPT-4o智能判定+缓存保护+误判回滚+完整日志仪表盘+反检测伪装,长期稳定搜索净化方案!
// @author       GPT
// @license      MIT
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(async function () {
    'use strict';

    // ✅ 你的专属 GPT-4o API Key(请替换此处)
    const OPENAI_API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

    const OPENAI_API_URL = 'https://api.openai.com/v1/chat/completions';
    const CACHE_LIMIT = 5000;

    const defaultRules = {
        whitelist: ["google.com", "baidu.com", "microsoft.com", "apple.com", "tencent.com", "alibaba.com", "bing.com", "gov.cn", "edu.cn"],
        blacklist: ["casino", "博彩", "色情", "黄片", "诈骗", "刷单", "网赚", "porn", "xxx", "pharmacy", "freevpn", "cheapdrugs"]
    };

    GM_addStyle(`
        .sg-official { background: #2196F3; color: #fff; border-radius: 3px; padding: 2px 6px; font-size: 0.75em; margin-left: 8px; }
        .sg-danger  { opacity: 0.3; position: relative; }
        .sg-danger::after { content: "⚠️危险结果已屏蔽"; position:absolute; left:0;right:0;top:40%;color:red;font-weight:bold; text-align:center; z-index:10;}
        #sg-panel { position:fixed;top:20px;right:20px;background:#fff;padding:10px 20px;box-shadow:0 0 10px #333;border-radius:10px;z-index:99999;font-size:14px;max-width:500px }
        #sg-panel button { margin:2px;padding:5px 10px;border-radius:5px; }
        #sg-panel textarea { width: 100%; height: 120px; margin: 5px 0; font-size:12px }
        #sg-log { position:fixed;bottom:20px;right:20px;background:#000;color:#0f0;padding:10px;font-size:12px;max-height:300px;overflow:auto;z-index:99999 }
    `);

    let whitelist = JSON.parse(await GM.getValue('whitelist', JSON.stringify(defaultRules.whitelist)));
    let blacklist = JSON.parse(await GM.getValue('blacklist', JSON.stringify(defaultRules.blacklist)));
    let cache = JSON.parse(await GM.getValue('cache', '{}'));
    let lastAPICall = 0;
    let hitSafe = 0, hitDanger = 0, aiCall = 0;

    GM_registerMenuCommand("净化器仪表盘", showUIPanel);
    GM_registerMenuCommand("实时日志窗口", showLogPanel);

    function showUIPanel() {
        const panel = document.createElement('div');
        panel.id = 'sg-panel';
        panel.innerHTML = `
            <b>净化器仪表盘</b><br>
            <button id="clearCache">清空AI缓存</button>
            <button id="exportRules">导出规则</button>
            <button id="importRules">导入模板</button><br>
            <textarea id="ruleEditor" placeholder="可编辑JSON格式规则"></textarea><br>
            <button id="saveRules">保存规则</button>
            <button id="closePanel">关闭</button><br><br>
            <div>命中官网: ${hitSafe} | 命中危险: ${hitDanger} | AI调用: ${aiCall}</div>
        `;
        document.body.appendChild(panel);

        document.getElementById('clearCache').onclick = async () => {
            cache = {};
            await GM.setValue('cache', '{}');
            alert("AI缓存已清空");
        };

        document.getElementById('exportRules').onclick = () => {
            document.getElementById('ruleEditor').value = JSON.stringify({ whitelist, blacklist }, null, 2);
        };

        document.getElementById('importRules').onclick = () => {
            document.getElementById('ruleEditor').value = JSON.stringify(defaultRules, null, 2);
        };

        document.getElementById('saveRules').onclick = async () => {
            try {
                const data = JSON.parse(document.getElementById('ruleEditor').value);
                whitelist = data.whitelist || [];
                blacklist = data.blacklist || [];
                await GM.setValue('whitelist', JSON.stringify(whitelist));
                await GM.setValue('blacklist', JSON.stringify(blacklist));
                alert("规则已保存");
            } catch (e) {
                alert("规则格式错误");
            }
        };

        document.getElementById('closePanel').onclick = () => panel.remove();
    }

    function showLogPanel() {
        const logPanel = document.createElement('div');
        logPanel.id = 'sg-log';
        document.body.appendChild(logPanel);
        setInterval(() => {
            logPanel.innerHTML = `✅ 安全命中: ${hitSafe} <br> ⚠️ 危险命中: ${hitDanger} <br> 🤖 AI调用: ${aiCall}`;
        }, 1000);
    }

    function scanPage() {
        const links = document.querySelectorAll('a[href]:not([data-sg-checked])');
        links.forEach(link => {
            link.setAttribute('data-sg-checked', '1');
            const domain = extractDomain(link.href);
            const text = (link.textContent || '').trim();
            if (!domain) return;
            const container = link.closest('div, li, article, section') || link;

            if (matchList(whitelist, domain, text)) {
                markOfficial(link);
                hitSafe++;
            } else if (matchList(blacklist, domain, text)) {
                markDanger(container);
                hitDanger++;
            } else {
                const key = domain + '|' + text;
                if (cache[key]) {
                    cache[key] === 'danger' ? (markDanger(container), hitDanger++) : (markOfficial(link), hitSafe++);
                } else {
                    aiJudge(domain, text, container, link);
                }
            }

            link.addEventListener('contextmenu', async (e) => {
                e.preventDefault();
                const action = prompt(`域名:${domain}\n\n1: 白名单\n2: 黑名单\n3: 移除白名单\n4: 移除黑名单`);
                if (action === '1') {
                    if (!whitelist.includes(domain)) whitelist.push(domain);
                    await GM.setValue('whitelist', JSON.stringify(whitelist));
                    alert("已加入白名单");
                } else if (action === '2') {
                    if (!blacklist.includes(domain)) blacklist.push(domain);
                    await GM.setValue('blacklist', JSON.stringify(blacklist));
                    alert("已加入黑名单");
                } else if (action === '3') {
                    whitelist = whitelist.filter(d => d !== domain);
                    await GM.setValue('whitelist', JSON.stringify(whitelist));
                    alert("已移除白名单");
                } else if (action === '4') {
                    blacklist = blacklist.filter(d => d !== domain);
                    await GM.setValue('blacklist', JSON.stringify(blacklist));
                    alert("已移除黑名单");
                }
            }, { once: true });
        });
    }

    function matchList(list, domain, text) {
        return list.some(rule => {
            try {
                if (rule.startsWith("/") && rule.endsWith("/")) {
                    const reg = new RegExp(rule.slice(1, -1), 'i');
                    return reg.test(domain) || reg.test(text);
                }
                return domain.includes(rule) || text.includes(rule);
            } catch {
                return false;
            }
        });
    }

    function extractDomain(url) {
        try {
            const u = new URL(url);
            return u.hostname.replace(/^www\./, '');
        } catch {
            return null;
        }
    }

    function markOfficial(link) {
        if (link.querySelector('.sg-official')) return;
        const badge = document.createElement('span');
        badge.className = 'sg-official';
        badge.textContent = '官网';
        link.appendChild(badge);
    }

    function markDanger(container) {
        container.classList.add('sg-danger');
        container.querySelector('a')?.addEventListener('click', e => {
            e.preventDefault();
            alert("已拦截危险链接!");
        }, { once: true });
    }

    async function aiJudge(domain, text, container, link) {
        const key = domain + '|' + text;
        if (Date.now() - lastAPICall < 1000) return;
        lastAPICall = Date.now();
        aiCall++;

        const prompt = `请判断以下网址是否存在诈骗、色情、博彩、钓鱼、非法刷单、网赚、虚假贷款、危险下载等问题,只回复"危险"或"安全":
网址: ${domain}
标题: ${text}`;

        try {
            const res = await fetch(OPENAI_API_URL, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${OPENAI_API_KEY}`
                },
                body: JSON.stringify({
                    model: "gpt-4o",
                    messages: [{ role: "user", content: prompt }],
                    temperature: 0
                })
            });

            const result = await res.json();
            const reply = result.choices?.[0]?.message?.content?.trim();
            if (reply.includes("危险")) {
                markDanger(container);
                cache[key] = 'danger';
                hitDanger++;
            } else if (reply.includes("安全")) {
                markOfficial(link);
                cache[key] = 'safe';
                hitSafe++;
            }
            await limitCacheSize();
            await GM.setValue('cache', JSON.stringify(cache));
        } catch (e) {
            console.error("AI请求失败", e);
        }
    }

    async function limitCacheSize() {
        const keys = Object.keys(cache);
        if (keys.length > CACHE_LIMIT) {
            const toDelete = keys.slice(0, keys.length - CACHE_LIMIT);
            for (let k of toDelete) delete cache[k];
            console.log("缓存裁剪完成");
        }
    }

    setInterval(scanPage, 1000);
})();