油猴 tampermonkey 屏蔽关键词和动态自定义范围按钮脚本

如果任何网站则修改为 :@match *://*/*

// ==UserScript==
// @name         屏蔽包含特定关键词的商品(精确匹配独立关键词)
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  自动隐藏标题中包含指定的独立关键词的商品
// @author       Your Name
// @match        https://shop.gigab2b.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 创建设置面板
    function createSettingsPanel() {
        const panel = document.createElement('div');
        panel.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #ffffff;
            padding: 20px;
            border-radius: 10px;
            z-index: 9999;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            max-width: 600px;
            min-width: 400px;
            transition: transform 0.3s ease;
        `;

        panel.innerHTML = `
            <style>
                .keyword-filter-panel h3 {
                    margin: 0 0 20px 0;
                    color: #333;
                    font-size: 18px;
                    border-bottom: 2px solid #f0f0f0;
                    padding-bottom: 10px;
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                }
                .keyword-filter-panel input[type="text"] {
                    padding: 8px 12px;
                    border: 1px solid #ddd;
                    border-radius: 6px;
                    font-size: 14px;
                    transition: border-color 0.3s;
                    outline: none;
                }
                .keyword-filter-panel input[type="text"]:focus {
                    border-color: #4a90e2;
                    box-shadow: 0 0 0 2px rgba(74,144,226,0.2);
                }
                .keyword-filter-panel select {
                    padding: 8px 12px;
                    border: 1px solid #ddd;
                    border-radius: 6px;
                    font-size: 14px;
                    background-color: white;
                    cursor: pointer;
                    outline: none;
                }
                .keyword-filter-panel button {
                    padding: 8px 16px;
                    border: none;
                    border-radius: 6px;
                    font-size: 14px;
                    cursor: pointer;
                    transition: all 0.3s;
                }
                .keyword-filter-panel .primary-btn {
                    background: #4a90e2;
                    color: white;
                }
                .keyword-filter-panel .primary-btn:hover {
                    background: #357abd;
                }
                .keyword-filter-panel .secondary-btn {
                    background: #f5f5f5;
                    color: #666;
                }
                .keyword-filter-panel .secondary-btn:hover {
                    background: #e8e8e8;
                }
                .keyword-filter-panel .remove-btn {
                    background: #ff4d4f;
                    color: white;
                    padding: 6px 12px;
                }
                .keyword-filter-panel .remove-btn:hover {
                    background: #ff7875;
                }
                .keyword-filter-panel .rule-row {
                    display: flex;
                    gap: 10px;
                    align-items: center;
                    margin-bottom: 15px;
                    padding: 10px;
                    background: #f9f9f9;
                    border-radius: 8px;
                }
                .keyword-filter-panel .button-group {
                    margin-top: 20px;
                    display: flex;
                    gap: 10px;
                    justify-content: flex-end;
                }
                .minimize-btn {
                    background: none;
                    border: none;
                    color: #666;
                    cursor: pointer;
                    padding: 4px 8px;
                    font-size: 20px;
                }
                .minimize-btn:hover {
                    color: #333;
                }
                .panel-minimized {
                    transform: translateY(calc(100% - 40px));
                }
                .panel-header {
                    cursor: pointer;
                    user-select: none;
                }
            </style>
            <div class="keyword-filter-panel">
                <h3 class="panel-header">
                    <span>关键词过滤设置</span>
                    <button class="minimize-btn">_</button>
                </h3>
                <div id="keywordPairs"></div>
                <div class="button-group">
                    <button id="addKeywordPair" class="secondary-btn">添加新规则</button>
                    <button id="saveSettings" class="primary-btn">保存设置</button>
                </div>
            </div>
        `;

        document.body.appendChild(panel);
        return panel;
    }

    // 创建规则输入行
    function createKeywordPairRow() {
        const row = document.createElement('div');
        row.className = 'rule-row';
        row.innerHTML = `
            <input type="text" placeholder="关键词A" style="width: 100px;">
            <input type="text" placeholder="关键词B" style="width: 100px;">
            <select>
                <option value="AorB">包含A或B</option>
                <option value="AnotB">包含A不含B</option>
                <option value="AandB">同时包含A和B</option>
                <option value="notA">不包含A</option>
            </select>
            <input type="text" placeholder="备注" style="width: 150px;">
            <button class="remove-btn removeRule">删除</button>
        `;
        return row;
    }

    // 保存设置到localStorage
    function saveSettings() {
        const keywordPairs = [];
        document.querySelectorAll('#keywordPairs > div').forEach(row => {
            const inputs = row.querySelectorAll('input');
            const select = row.querySelector('select');
            if (inputs[0].value || inputs[1].value) {
                keywordPairs.push({
                    keywordA: inputs[0].value,
                    keywordB: inputs[1].value,
                    condition: select.value,
                    note: inputs[2].value
                });
            }
        });
        localStorage.setItem('keywordFilterSettings', JSON.stringify(keywordPairs));
        hideProductsByKeywords();

        // 显示保存成功提示
        const toast = document.createElement('div');
        toast.style.cssText = `
            position: fixed;
            bottom: 80px;
            right: 20px;
            background: rgba(0,0,0,0.7);
            color: white;
            padding: 10px 20px;
            border-radius: 4px;
            z-index: 10000;
        `;
        toast.textContent = '设置已保存';
        document.body.appendChild(toast);
        setTimeout(() => toast.remove(), 2000);
    }

    // 从localStorage加载设置
    function loadSettings() {
        const settings = localStorage.getItem('keywordFilterSettings');
        return settings ? JSON.parse(settings) : [];
    }

    // 检查标题是否匹配条件
    function checkTitle(title, config) {
        if (!config.keywordA && !config.keywordB) return false;

        const regexA = config.keywordA ? new RegExp(`\\b${config.keywordA}\\b`, 'i') : null;
        const regexB = config.keywordB ? new RegExp(`\\b${config.keywordB}\\b`, 'i') : null;

        switch(config.condition) {
            case 'AorB':
                return (regexA && regexA.test(title)) || (regexB && regexB.test(title));
            case 'AnotB':
                return (regexA && regexA.test(title)) && (!regexB || !regexB.test(title));
            case 'AandB':
                return (regexA && regexB && regexA.test(title) && regexB.test(title));
            case 'notA':
                return regexA && !regexA.test(title);
            default:
                return false;
        }
    }

    // 处理按钮状态
    function handleImportButton(button) {
        if (button.textContent.trim() === 'Edit On import List') {
            button.disabled = true;
            button.style.opacity = '0.5';
            button.style.cursor = 'not-allowed';
        }
    }

    // 隐藏商品的主函数
    function hideProductsByKeywords() {
        const settings = loadSettings();
        // 首先重置所有商品的显示状态
        document.querySelectorAll('.card-outter-container').forEach(item => {
            const productContainer = item.closest('div');
            if (productContainer) {
                productContainer.style.display = '';
            }
        });

        // 如果没有规则,直接返回,保持所有商品显示
        if (settings.length === 0) {
            return;
        }

        // 然后根据规则隐藏符合条件的商品
        document.querySelectorAll('.card-outter-container').forEach(item => {
            const title = item.innerText.toLowerCase();
            const productContainer = item.closest('div');

            for (const config of settings) {
                if (checkTitle(title, config)) {
                    if (productContainer) {
                        productContainer.style.display = 'none';
                        console.log(`已隐藏商品: ${title} (${config.note})`);
                    }
                    break;
                }
            }
        });

        // 处理所有导入按钮
        document.querySelectorAll('.el-button.el-button--info.sh-button.product-btn').forEach(handleImportButton);
    }

    // 初始化设置面板
    const panel = createSettingsPanel();
    const keywordPairsContainer = panel.querySelector('#keywordPairs');

    // 添加已保存的规则
    const savedSettings = loadSettings();
    savedSettings.forEach(setting => {
        const row = createKeywordPairRow();
        const inputs = row.querySelectorAll('input');
        const select = row.querySelector('select');
        inputs[0].value = setting.keywordA || '';
        inputs[1].value = setting.keywordB || '';
        select.value = setting.condition;
        inputs[2].value = setting.note || '';
        keywordPairsContainer.appendChild(row);
    });

    // 如果没有保存的规则,添加一个空行
    if (savedSettings.length === 0) {
        keywordPairsContainer.appendChild(createKeywordPairRow());
    }

    // 绑定事件
    panel.querySelector('#addKeywordPair').addEventListener('click', () => {
        keywordPairsContainer.appendChild(createKeywordPairRow());
    });

    panel.querySelector('#saveSettings').addEventListener('click', saveSettings);

    // 删除规则的事件委托
    keywordPairsContainer.addEventListener('click', (e) => {
        if (e.target.classList.contains('removeRule')) {
            e.target.parentElement.remove();
            // 如果删除后没有规则了,添加一个空行
            if (keywordPairsContainer.children.length === 0) {
                keywordPairsContainer.appendChild(createKeywordPairRow());
            }
            saveSettings();
        }
    });

    // 最小化功能
    const minimizeBtn = panel.querySelector('.minimize-btn');
    const panelHeader = panel.querySelector('.panel-header');
    let isMinimized = false;

    function toggleMinimize() {
        isMinimized = !isMinimized;
        panel.classList.toggle('panel-minimized');
        minimizeBtn.textContent = isMinimized ? '□' : '_';
    }

    minimizeBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        toggleMinimize();
    });

    panelHeader.addEventListener('click', () => {
        if (isMinimized) {
            toggleMinimize();
        }
    });

    // 等待页面加载完成后执行脚本
    window.addEventListener('load', hideProductsByKeywords);

    // 处理动态加载的内容
    const observer = new MutationObserver((mutations) => {
        hideProductsByKeywords();
        // 额外检查新加载的按钮
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1) { // 元素节点
                    const buttons = node.querySelectorAll('.el-button.el-button--info.sh-button.product-btn');
                    buttons.forEach(handleImportButton);
                }
            });
        });
    });
    observer.observe(document.body, { childList: true, subtree: true });
})();

By 行政