GreasyFork AI Safety Checker

在 GreasyFork 主頁面顯示 AI 安全檢查提示,支援多語言與網域檢查,可選啟用 Google Safe Browsing API。

当前为 2025-03-14 提交的版本,查看 最新版本

// ==UserScript==
// @name         GreasyFork AI Safety Checker
// @namespace    http://tampermonkey.net/
// @version      2.0.3
// @description  在 GreasyFork 主頁面顯示 AI 安全檢查提示,支援多語言與網域檢查,可選啟用 Google Safe Browsing API。
// @match        https://greasyfork.org/*scripts/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_info
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Tampermonkey 版本檢查
    const MINIMUM_TAMPERMONKEY_VERSION = '5.0.0';
    if (GM_info.version < MINIMUM_TAMPERMONKEY_VERSION) {
        console.warn(`Warning: Tampermonkey ${GM_info.version} is outdated, recommended: ${MINIMUM_TAMPERMONKEY_VERSION}`);
    }

    // 語言設定
    let userLang = GM_getValue('userSelectedLanguage', navigator.language.startsWith('zh') ? 'zh-CN' : 'en');
    const translations = {
        'zh-CN': { safetyNotice: 'AI 安全提示:${grant} - 检查结果:${details}', /* 其他翻譯 */ },
        'en': { safetyNotice: 'AI Safety Notice: ${grant} - Check Result: ${details}', /* 其他翻譯 */ }
    };
    function t(key, params = {}) {
        let text = translations[userLang][key] || translations['en'][key];
        for (const [p, v] of Object.entries(params)) text = text.replace(`\${${p}}`, v);
        return text;
    }

    // 選單設定
    let politicalCheckEnabled = GM_getValue('politicalCheckEnabled', false);
    let apiCheckEnabled = GM_getValue('apiCheckEnabled', false);
    GM_registerMenuCommand(politicalCheckEnabled ? '禁用政治检查' : '启用政治检查', () => {
        GM_setValue('politicalCheckEnabled', !politicalCheckEnabled);
        location.reload();
    });
    GM_registerMenuCommand(apiCheckEnabled ? '禁用 API 检查' : '启用 API 检查', () => {
        GM_setValue('apiCheckEnabled', !apiCheckEnabled);
        location.reload();
    });
    GM_registerMenuCommand('设置 Google API Key', () => {
        const key = prompt('Enter Google Safe Browsing API Key');
        if (key) GM_setValue('googleApiKey', key);
    });

    // 抓取代碼
    const fetchScriptCode = () => {
        const codeUrl = `${window.location.origin}${window.location.pathname}/code`;
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: codeUrl,
                onload: (res) => resolve(new DOMParser().parseFromString(res.responseText, 'text/html').querySelector('pre')?.textContent || 'No code found'),
                onerror: () => reject('Fetch failed')
            });
        });
    };

    // 分析腳本
    const analyzeScript = async (code) => {
        const matches = code.split('\n').filter(l => l.startsWith('// @match')).map(l => l.replace('// @match', '').trim());
        let details = '';
        if (politicalCheckEnabled) details += (await checkPoliticalRedirection(code)) || 'No political issues';
        if (apiCheckEnabled) {
            const apiResult = await checkDomainWithGoogle(matches[0] || window.location.host);
            details += apiResult ? `; Google API: ${apiResult}` : '';
        }
        return t('safetyNotice', { grant: 'GM_xmlhttpRequest', details: details || 'No risks detected' });
    };

    // 主邏輯
    fetchScriptCode().then(analyzeScript).then(warning => {
        const notice = document.createElement('div');
        notice.textContent = warning;
        document.querySelector('.install-link')?.parentNode.insertBefore(notice, document.querySelector('.install-link'));
    }).catch(console.error);
})();