Greasy Fork

来自缓存

Greasy Fork is available in English.

晋江文学城作者屏蔽

在搜索结果页面屏蔽不想看的作者的文章

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         晋江文学城作者屏蔽
// @namespace    http://tampermonkey.net/
// @version      0.8
// @description  在搜索结果页面屏蔽不想看的作者的文章
// @author       CursorAI
// @license MIT
// @match        *://*.jjwxc.net/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 添加样式
    GM_addStyle(`
        .block-panel {
            position: fixed;
            right: 20px;
            top: 20px;
            background: white;
            padding: 15px;
            border: 1px solid #ccc;
            border-radius: 5px;
            z-index: 1001;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            width: 300px;
            transition: all 0.3s ease;
        }
        .block-panel.login-active {
            top: 320px !important;
        }
        .block-panel h3 {
            margin: 0 0 10px 0;
            color: #333;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .block-panel input {
            padding: 5px;
            margin-right: 5px;
            width: 200px;
        }
        .block-panel button {
            padding: 5px 10px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }
        .blocked-content {
            display: none !important;
        }
        #blockList {
            max-height: 300px;
            overflow-y: auto;
            margin-top: 10px;
            display: none;
        }
        #blockList.show {
            display: block;
        }
        .author-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 5px;
            border-bottom: 1px solid #eee;
        }
        .remove-btn {
            background: #ff4444 !important;
            padding: 2px 8px !important;
            font-size: 12px;
        }
        .toggle-btn {
            background: #666 !important;
        }
    `);

    let blockedAuthors = GM_getValue('blockedAuthors', []);
    let contextMenu = null;

    // 添加一个辅助函数来检查登录状态
    function hasLoginElements() {
        return document.getElementById('qrCodeDiv') || document.querySelector('.login-qrcode');
    }

    // 简化 createControlPanel 函数
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.className = 'block-panel';

        if (hasLoginElements()) {
            panel.classList.add('login-active');
        }

        panel.innerHTML = `
            <h3>
                作者屏蔽
                <button class="toggle-btn" id="toggleList">显示列表</button>
            </h3>
            <div>
                <input type="text" id="authorInput" placeholder="输入要屏蔽的作者名称">
                <button id="addBlock">添加</button>
            </div>
            <div id="blockList"></div>
            <div style="margin-top: 10px; display: flex; gap: 10px;">
                <button id="exportList" style="background: #666;">导出列表</button>
                <button id="importList" style="background: #666;">导入列表</button>
            </div>
        `;

        document.body.appendChild(panel);

        // 绑定事件
        document.getElementById('addBlock').addEventListener('click', () => addBlockedAuthor());
        document.getElementById('toggleList').addEventListener('click', toggleBlockList);

        // 绑定导出/导入事件
        document.getElementById('exportList').addEventListener('click', exportBlockList);
        document.getElementById('importList').addEventListener('click', importBlockList);

        updateBlockList();
    }

    // 切换列表显示
    function toggleBlockList() {
        const blockList = document.getElementById('blockList');
        const toggleBtn = document.getElementById('toggleList');
        const isShown = blockList.classList.toggle('show');
        toggleBtn.textContent = isShown ? '隐藏列表' : '显示列表';
    }

    // 创建右键菜单
    function createContextMenu(e, author) {
        if (contextMenu) {
            contextMenu.remove();
        }

        // 创建新菜单元素
        const menu = document.createElement('div');

        // 获取鼠标位置
        const x = e.clientX;
        const y = e.clientY;

        // 获取窗口尺寸
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;
        const menuWidth = 150;
        const menuHeight = 40;

        // 调整位置,确保菜单不会超出视窗
        let adjustedX = x;
        let adjustedY = y;

        // 如果菜单会超出右边界,向左偏移
        if (x + menuWidth > windowWidth) {
            adjustedX = x - menuWidth;
        }

        // 如果菜单会超出下边界,向上偏移
        if (y + menuHeight > windowHeight) {
            adjustedY = y - menuHeight;
        }

        const menuStyle = `
            position: fixed;
            left: ${adjustedX}px;
            top: ${adjustedY}px;
            background: white;
            border: 1px solid #ccc;
            border-radius: 4px;
            padding: 5px 0;
            box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
            z-index: 999999 !important;
            min-width: 120px;
            user-select: none;
            font-size: 14px;
            color: #333;
        `.trim();

        menu.style.cssText = menuStyle;

        // 创建菜单项
        const menuItem = document.createElement('div');
        const menuItemStyle = `
            padding: 8px 15px;
            cursor: pointer;
            white-space: nowrap;
            background: white;
            transition: background-color 0.2s;
        `.trim();

        menuItem.style.cssText = menuItemStyle;

        const isBlocked = blockedAuthors.includes(author);
        menuItem.textContent = `${isBlocked ? '取消屏蔽' : '屏蔽'} "${author}"`;

        // 添加hover效果
        menuItem.addEventListener('mouseover', () => {
            menuItem.style.backgroundColor = '#f0f0f0';
        });

        menuItem.addEventListener('mouseout', () => {
            menuItem.style.backgroundColor = 'white';
        });

        // 添加点击事件
        menuItem.addEventListener('click', () => {
            if (isBlocked) {
                removeBlockedAuthor(author);
            } else {
                addBlockedAuthor(author);
            }
            menu.remove();
            contextMenu = null;
        });

        menu.appendChild(menuItem);
        document.body.appendChild(menu);
        contextMenu = menu;
    }

    // 修改绑定右键事件的函数
    function bindContextMenu() {
        document.addEventListener('contextmenu', function(e) {
            const authorLink = e.target.closest('a[href*="oneauthor.php"]');
            if (authorLink) {
                e.preventDefault();
                e.stopPropagation();
                const author = authorLink.textContent.trim();
                createContextMenu(e, author);  // 传入事件对象
                return false;
            }
        }, true);

        // 点击其他地方关闭菜单
        document.addEventListener('click', function(e) {
            if (contextMenu && !contextMenu.contains(e.target)) {
                contextMenu.remove();
                contextMenu = null;
            }
        });
    }

    // 添加屏蔽作者
    function addBlockedAuthor(author) {
        const authorName = author || document.getElementById('authorInput')?.value.trim();
        if (authorName && !blockedAuthors.includes(authorName)) {
            blockedAuthors.push(authorName);
            GM_setValue('blockedAuthors', blockedAuthors);
            updateBlockList();
            hideBlockedContent();
            if (document.getElementById('authorInput')) {
                document.getElementById('authorInput').value = '';
            }
        }
    }

    // 移除屏蔽作者
    function removeBlockedAuthor(author) {
        blockedAuthors = blockedAuthors.filter(a => a !== author);
        GM_setValue('blockedAuthors', blockedAuthors);
        updateBlockList();
        hideBlockedContent();
    }

    // 更新屏蔽列表显示
    function updateBlockList() {
        const blockList = document.getElementById('blockList');
        if (blockList) {
            blockList.innerHTML = blockedAuthors
                .sort((a, b) => a.localeCompare(b, 'zh-CN'))
                .map(author => `
                    <div class="author-item">
                        <span class="author-name">${author}</span>
                        <button class="remove-btn" data-author="${author}">删除</button>
                    </div>
                `).join('');

            blockList.querySelectorAll('.remove-btn').forEach(button => {
                button.addEventListener('click', function() {
                    const author = this.getAttribute('data-author');
                    removeBlockedAuthor(author);
                });
            });
        }
    }

    // 隐藏被屏蔽的内容
    function hideBlockedContent() {
        const authorElements = document.querySelectorAll('a[href*="oneauthor.php"]');
        authorElements.forEach(authorElement => {
            const authorName = authorElement.textContent.trim();
            if (blockedAuthors.includes(authorName)) {
                let articleContainer = authorElement.closest('tr');
                if (articleContainer) {
                    articleContainer.classList.add('blocked-content');
                }
            }
        });
    }

    // 导出黑名单
    function exportBlockList() {
        const data = {
            version: '1.0',
            timestamp: new Date().toISOString(),
            authors: blockedAuthors
        };

        const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.href = url;
        a.download = `晋江作者黑名单_${new Date().toLocaleDateString()}.json`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    // 导入黑名单
    function importBlockList() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';

        input.onchange = function(e) {
            const file = e.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = function(e) {
                try {
                    const data = JSON.parse(e.target.result);

                    // 验证文件格式
                    if (!data.authors || !Array.isArray(data.authors)) {
                        throw new Error('无效的黑名单文件格式');
                    }

                    // 显示导入选项对话框
                    const importType = confirm(
                        `发现 ${data.authors.length} 个作者。\n` +
                        `点击"确定"合并到当前列表\n` +
                        `点击"取消"覆盖当前列表`
                    );

                    if (importType) {
                        // 合并选项:添加新作者到现有列表
                        const newAuthors = data.authors.filter(author => !blockedAuthors.includes(author));
                        if (newAuthors.length > 0) {
                            blockedAuthors = [...blockedAuthors, ...newAuthors];
                            GM_setValue('blockedAuthors', blockedAuthors);
                            updateBlockList();
                            hideBlockedContent();
                            alert(`合并成功!新增 ${newAuthors.length} 个作者。`);
                        } else {
                            alert('没有新的作者需要添加。');
                        }
                    } else {
                        // 覆盖选项:完全替换现有列表
                        blockedAuthors = [...new Set(data.authors)]; // 去重
                        GM_setValue('blockedAuthors', blockedAuthors);
                        updateBlockList();
                        hideBlockedContent();
                        alert(`覆盖成功!共导入 ${blockedAuthors.length} 个作者。`);
                    }
                } catch (err) {
                    alert('导入失败:' + err.message);
                }
            };
            reader.readAsText(file);
        };

        input.click();
    }

    // 简化 observer 部分
    const observer = new MutationObserver(() => {
        const panel = document.querySelector('.block-panel');
        if (panel) {
            panel.classList.toggle('login-active', hasLoginElements());
        }
    });

    // 初始化
    function init() {
        setTimeout(() => {
            // 清理可能存在的旧面板
            const oldPanels = document.querySelectorAll('.block-panel');
            oldPanels.forEach(panel => panel.remove());

            // 创建新面板
            createControlPanel();
            hideBlockedContent();
            bindContextMenu();

            // 找到所有可能的登录按钮
            const loginLinks = document.querySelectorAll('a[href*="login"], a[onclick*="login"]');
            loginLinks.forEach(link => {
                link.addEventListener('click', () => {
                    document.querySelector('.block-panel')?.classList.add('login-active');
                });
            });

            // 监听关闭按钮
            document.addEventListener('click', (e) => {
                if (e.target.matches('a[onclick*="unblockUI"]')) {
                    document.querySelector('.block-panel')?.classList.remove('login-active');
                }
            });

            // 添加登录元素检测和位置调整
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        }, 1500);
    }

    window.addEventListener('load', init);
})();