GreasyFork 脚本过滤器

GreasyFork脚本过滤器(仅标题过滤)

目前為 2025-05-30 提交的版本,檢視 最新版本

// ==UserScript==
// @name         GreasyFork 脚本过滤器
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  GreasyFork脚本过滤器(仅标题过滤)
// @author       YourName
// @match        https://gf.qytechs.cn/zh-CN/scripts*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    
    // 配置
    const CONFIG = {
        keywords: GM_getValue('filterKeywords', []) || [],
        caseSensitive: GM_getValue('caseSensitive', false),
        panelExpanded: GM_getValue('panelExpanded', true)
    };
    
    // 调试函数(在控制台输出信息)
    function debugLog(message) {
        console.log('[GF Filter] ' + message);
    }
    
    // 添加样式(增加!important覆盖GreasyFork样式)
    GM_addStyle(`
        .gf-sidebar {
            position: fixed !important;
            left: 0 !important;
            top: 50% !important;
            transform: translateY(-50%) translateX(-100%) !important;
            z-index: 99999 !important;
            display: flex !important;
            transition: transform 0.3s ease !important;
        }
        .gf-sidebar.expanded {
            transform: translateY(-50%) translateX(0) !important;
        }
        .gf-control-panel {
            background: #2c3e50 !important;
            color: white !important;
            width: 280px !important;
            padding: 12px !important;
            border-radius: 0 8px 8px 0 !important;
            box-shadow: 2px 2px 8px rgba(0,0,0,0.2) !important;
        }
        .gf-panel-header {
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            padding-bottom: 8px !important;
            margin-bottom: 10px !important;
            border-bottom: 1px solid #3498db !important;
        }
        .gf-panel-title {
            color: #3498db !important;
            font-weight: bold !important;
            font-size: 16px !important;
        }
        .gf-close-btn {
            background: #e74c3c !important;
            color: white !important;
            border: none !important;
            width: 24px !important;
            height: 24px !important;
            border-radius: 50% !important;
            font-size: 14px !important;
            cursor: pointer !important;
        }
        .gf-input-group {
            display: flex !important;
            margin-bottom: 10px !important;
        }
        .gf-input-group input {
            flex: 1 !important;
            padding: 8px 10px !important;
            border: 1px solid #3498db !important;
            border-radius: 4px !important;
            background: rgba(0,0,0,0.2) !important;
            color: white !important;
        }
        .gf-button {
            background: #3498db !important;
            color: white !important;
            border: none !important;
            padding: 8px 12px !important;
            border-radius: 4px !important;
            cursor: pointer !important;
            margin-left: 5px !important;
            font-weight: bold !important;
        }
        .gf-keywords-container {
            max-height: 200px !important;
            overflow-y: auto !important;
            margin-bottom: 10px !important;
        }
        .gf-keyword-item {
            background: #3498db !important;
            padding: 6px 10px !important;
            border-radius: 4px !important;
            margin-bottom: 6px !important;
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
        }
        .gf-remove-keyword {
            background: none !important;
            border: none !important;
            color: white !important;
            cursor: pointer !important;
            font-weight: bold !important;
        }
        .gf-control-buttons {
            display: flex !important;
            justify-content: space-between !important;
        }
        .gf-toggle-btn {
            background: #95a5a6 !important;
            color: white !important;
            border: none !important;
            padding: 6px 10px !important;
            border-radius: 0 4px 4px 0 !important;
            font-weight: bold !important;
            cursor: pointer !important;
            writing-mode: vertical-rl !important;
            height: 70px !important;
            position: absolute !important;
            left: 100% !important;
            top: 50% !important;
            transform: translateY(-50%) !important;
            z-index: 100001 !important;
        }
        .gf-hidden-script {
            display: none !important;
        }
    `);
    
    // 创建侧边栏
    function createSidebar() {
        try {
            debugLog("开始创建侧边栏...");
            
            // 检查是否已存在
            if (document.getElementById('gf-sidebar')) {
                debugLog('侧边栏已存在');
                return document.getElementById('gf-sidebar');
            }
            
            // 创建容器
            const sidebar = document.createElement('div');
            sidebar.id = 'gf-sidebar';
            sidebar.className = 'gf-sidebar';
            if (CONFIG.panelExpanded) sidebar.classList.add('expanded');
            
            debugLog(`侧边栏初始状态: ${CONFIG.panelExpanded ? '展开' : '折叠'}`);
            
            // 控制面板
            const controlPanel = document.createElement('div');
            controlPanel.className = 'gf-control-panel';
            controlPanel.innerHTML = `
                <div class="gf-panel-header">
                    <div class="gf-panel-title">脚本过滤设置</div>
                    <button class="gf-close-btn" id="gf-close-btn">×</button>
                </div>
                <div class="gf-input-group">
                    <input type="text" id="gf-keyword-input" placeholder="输入屏蔽词...">
                    <button class="gf-button" id="gf-add-keyword">添加</button>
                </div>
                <div class="gf-keywords-container" id="gf-keywords-list">
                    ${CONFIG.keywords.length ? '' : '<div style="color:#bdc3c7;padding:8px;text-align:center;">无屏蔽关键词</div>'}
                </div>
                <div class="gf-control-buttons">
                    <button class="gf-button" id="gf-clear-keywords">清除所有</button>
                    <div>
                        <input type="checkbox" id="gf-case-sensitive" ${CONFIG.caseSensitive ? 'checked' : ''}>
                        <label for="gf-case-sensitive" style="margin-left:5px;font-size:13px;">区分大小写</label>
                    </div>
                </div>
            `;
            sidebar.appendChild(controlPanel);
            
            // 切换按钮
            const toggleBtn = document.createElement('button');
            toggleBtn.className = 'gf-toggle-btn';
            toggleBtn.id = 'gf-toggle-btn';
            toggleBtn.textContent = '过滤设置';
            sidebar.appendChild(toggleBtn);
            
            // 添加到页面(确保在body中)
            document.body.appendChild(sidebar);
            debugLog('侧边栏已创建并添加到页面');
            
            return sidebar;
        } catch (error) {
            debugLog('创建侧边栏时出错: ' + error.message);
            return null;
        }
    }
    
    // 初始化
    function init() {
        try {
            debugLog("脚本开始初始化");
            debugLog(`关键词数量: ${CONFIG.keywords.length}`);
            debugLog(`侧边栏初始展开状态: ${CONFIG.panelExpanded}`);
            
            // 创建侧边栏
            const sidebar = createSidebar();
            if (!sidebar) {
                debugLog('侧边栏创建失败,停止初始化');
                return;
            }
            
            // 获取关键元素
            const keywordsList = document.getElementById('gf-keywords-list');
            const keywordInput = document.getElementById('gf-keyword-input');
            const caseSensitiveCheckbox = document.getElementById('gf-case-sensitive');
            
            // 渲染关键词
            function renderKeywords() {
                if (!keywordsList) {
                    debugLog("关键词容器未找到");
                    return;
                }
                
                keywordsList.innerHTML = '';
                
                if (CONFIG.keywords.length === 0) {
                    keywordsList.innerHTML = '<div style="color:#bdc3c7;padding:8px;text-align:center;">无屏蔽关键词</div>';
                    debugLog("已渲染:无关键词状态");
                    return;
                }
                
                const fragment = document.createDocumentFragment();
                CONFIG.keywords.forEach(keyword => {
                    const item = document.createElement('div');
                    item.className = 'gf-keyword-item';
                    item.innerHTML = `${keyword} <button class="gf-remove-keyword" data-keyword="${keyword}">×</button>`;
                    fragment.appendChild(item);
                });
                
                keywordsList.appendChild(fragment);
                debugLog(`已渲染关键词: ${CONFIG.keywords.length}个`);
            }
            
            // 初始渲染
            renderKeywords();
            
            // 添加关键词
            function addKeyword(keyword) {
                keyword = keyword.trim();
                if (keyword && !CONFIG.keywords.includes(keyword)) {
                    CONFIG.keywords.push(keyword);
                    GM_setValue('filterKeywords', CONFIG.keywords);
                    renderKeywords();
                    filterScripts();
                    debugLog(`已添加关键词: ${keyword}`);
                }
            }
            
            // 移除关键词
            function removeKeyword(keyword) {
                const index = CONFIG.keywords.indexOf(keyword);
                if (index !== -1) {
                    CONFIG.keywords.splice(index, 1);
                    GM_setValue('filterKeywords', CONFIG.keywords);
                    renderKeywords();
                    filterScripts();
                    debugLog(`已移除关键词: ${keyword}`);
                }
            }
            
            // 切换侧边栏
            function toggleSidebar() {
                if (!sidebar) {
                    debugLog("侧边栏元素未找到");
                    return;
                }
                
                const isExpanded = sidebar.classList.contains('expanded');
                sidebar.classList.toggle('expanded', !isExpanded);
                CONFIG.panelExpanded = !isExpanded;
                GM_setValue('panelExpanded', CONFIG.panelExpanded);
                
                debugLog(`侧边栏状态切换: ${isExpanded ? '折叠' : '展开'}`);
            }
            
            // 过滤脚本
            function filterScripts() {
                try {
                    debugLog("开始过滤脚本...");
                    
                    // 更新配置
                    if (caseSensitiveCheckbox) {
                        CONFIG.caseSensitive = caseSensitiveCheckbox.checked;
                        GM_setValue('caseSensitive', CONFIG.caseSensitive);
                        debugLog(`大小写敏感设置: ${CONFIG.caseSensitive}`);
                    }
                    
                    // 获取脚本项(使用GreasyFork的实际选择器)
                    const scriptItems = document.querySelectorAll('.script-list > li');
                    if (!scriptItems.length) {
                        debugLog("未找到脚本项");
                        return;
                    }
                    
                    debugLog(`找到 ${scriptItems.length} 个脚本项`);
                    
                    // 无关键词时快速处理
                    if (CONFIG.keywords.length === 0) {
                        scriptItems.forEach(item => item.classList.remove('gf-hidden-script'));
                        debugLog("无关键词,显示所有脚本");
                        return;
                    }
                    
                    let hiddenCount = 0;
                    
                    // 高效过滤
                    scriptItems.forEach(item => {
                        const titleElement = item.querySelector('h2 a');
                        if (!titleElement) return;
                        
                        const titleText = titleElement.textContent || titleElement.innerText;
                        let shouldHide = false;
                        
                        for (const keyword of CONFIG.keywords) {
                            const caseSensitive = CONFIG.caseSensitive;
                            const contains = caseSensitive ? 
                                titleText.includes(keyword) : 
                                titleText.toLowerCase().includes(keyword.toLowerCase());
                            
                            if (contains) {
                                shouldHide = true;
                                break;
                            }
                        }
                        
                        if (shouldHide) {
                            item.classList.add('gf-hidden-script');
                            hiddenCount++;
                        } else {
                            item.classList.remove('gf-hidden-script');
                        }
                    });
                    
                    debugLog(`过滤完成: 隐藏了 ${hiddenCount} 个脚本`);
                } catch (error) {
                    debugLog('过滤脚本时出错: ' + error.message);
                }
            }
            
            // 事件处理
            function setupEvents() {
                try {
                    debugLog("设置事件监听器...");
                    
                    // 单个事件委托处理所有点击
                    sidebar.addEventListener('click', function(e) {
                        const target = e.target;
                        
                        if (target.id === 'gf-add-keyword' && keywordInput) {
                            addKeyword(keywordInput.value);
                            keywordInput.value = '';
                            keywordInput.focus();
                        }
                        else if (target.id === 'gf-clear-keywords') {
                            CONFIG.keywords = [];
                            GM_setValue('filterKeywords', CONFIG.keywords);
                            renderKeywords();
                            filterScripts();
                            debugLog("已清除所有关键词");
                        }
                        else if (target.id === 'gf-close-btn' || target.id === 'gf-toggle-btn') {
                            toggleSidebar();
                        }
                        else if (target.classList.contains('gf-remove-keyword')) {
                            const keyword = target.getAttribute('data-keyword');
                            if (keyword) removeKeyword(keyword);
                        }
                    });
                    
                    // 输入框回车事件
                    if (keywordInput) {
                        keywordInput.addEventListener('keypress', function(e) {
                            if (e.key === 'Enter') {
                                addKeyword(this.value);
                                this.value = '';
                            }
                        });
                    }
                    
                    // 复选框事件
                    if (caseSensitiveCheckbox) {
                        caseSensitiveCheckbox.addEventListener('change', filterScripts);
                    }
                    
                    debugLog("事件监听器设置完成");
                } catch (error) {
                    debugLog('设置事件时出错: ' + error.message);
                }
            }
            
            // 设置事件
            setupEvents();
            
            // 初始过滤
            filterScripts();
            
            // 添加调试按钮
            const debugBtn = document.createElement('button');
            debugBtn.textContent = '调试过滤器';
            debugBtn.style.position = 'fixed';
            debugBtn.style.bottom = '10px';
            debugBtn.style.right = '10px';
            debugBtn.style.padding = '8px';
            debugBtn.style.zIndex = '100000';
            debugBtn.addEventListener('click', function() {
                debugLog("手动调试信息:");
                debugLog(`侧边栏状态: ${sidebar.classList.contains('expanded') ? '展开' : '折叠'}`);
                debugLog(`关键词数量: ${CONFIG.keywords.length}`);
                debugLog(`大小写敏感: ${CONFIG.caseSensitive}`);
                
                // 检查侧边栏位置
                const rect = sidebar.getBoundingClientRect();
                debugLog(`侧边栏位置: left=${rect.left}px, top=${rect.top}px, width=${rect.width}px, height=${rect.height}px`);
                
                // 检查样式
                const style = window.getComputedStyle(sidebar);
                debugLog(`侧边栏显示: ${style.display}, 可见性: ${style.visibility}, 透明度: ${style.opacity}`);
                debugLog(`transform: ${style.transform}`);
                
                // 检查z-index
                debugLog(`z-index: ${style.zIndex}`);
            });
            document.body.appendChild(debugBtn);
            
            debugLog("初始化完成");
            
        } catch (error) {
            debugLog('初始化过程中出错: ' + error.message);
        }
    }
    
    // 启动脚本(带重试机制)
    function start() {
        try {
            // 确保body元素存在
            if (!document.body) {
                setTimeout(start, 100);
                return;
            }
            
            // 执行初始化
            init();
            
            // 添加最终检查
            setTimeout(() => {
                const sidebar = document.getElementById('gf-sidebar');
                if (!sidebar) {
                    debugLog("警告:侧边栏未创建,尝试重新初始化");
                    init();
                } else {
                    debugLog("侧边栏状态确认");
                }
            }, 1000);
        } catch (error) {
            debugLog('启动过程中出错: ' + error.message);
        }
    }
    
    // 启动
    if (document.readyState === 'complete') {
        start();
    } else {
        window.addEventListener('load', start);
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址