您现在的位置是:网站首页 > 博客日记 >

根据xpath标识广告油猴脚本|屏蔽广告

作者:YXN-js 阅读量:159 发布日期:2025-02-26

localStorage版

// ==UserScript==
// @name         XPath元素阻止程序_localStorage版
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  localStorage版元素屏蔽工具,支持XPath规则管理
// @author       YXN
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 生成网站专属存储键名
    const storageKey = `xpath_blocker_${location.hostname}`;

    // 样式增强
    const css = `
        #blocker-btn {
            position: fixed;
            bottom: 30px;
            right: 30px;
            z-index: 2147483647;
            width: 45px;
            height: 45px;
            border-radius: 50%;
            background: #2196F3;
            color: white;
            border: none;
            cursor: pointer;
            box-shadow: 0 3px 6px rgba(0,0,0,0.16);
            font-size: 20px;
            transition: transform 0.2s;
        }
        .blocker-dialog {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 8px 24px rgba(0,0,0,0.2);
            z-index: 2147483646;
            min-width: 320px;
        }
        .rule-item {
            display: flex;
            align-items: center;
            padding: 8px;
            border-bottom: 1px solid #eee;
        }
        .rule-index {
            width: 30px;
            color: #666;
        }
        .rule-text {
            flex: 1;
            font-family: monospace;
            overflow-x: auto;
        }
        .delete-btn {
            color: #f44336;
            cursor: pointer;
            margin-left: 10px;
        }
    `;

    // 注入全局样式
    const style = document.createElement('style');
    style.textContent = css;
    document.head.appendChild(style);

    class BlockerSystem {
        constructor() {
            this.rules = this.loadRules();
            this.initUI();
            this.setupObserver();
        }

        // 从localStorage加载规则
        loadRules() {
            try {
                return JSON.parse(localStorage.getItem(storageKey)) || [];
            } catch {
                return [];
            }
        }

        // 保存规则到localStorage
        saveRules() {
            localStorage.setItem(storageKey, JSON.stringify(this.rules));
        }

        // 初始化界面
        initUI() {
            this.createButton();
            this.applyRules();
        }

        // 创建悬浮按钮
        createButton() {
            this.btn = document.createElement('button');
            this.btn.id = 'blocker-btn';
            this.btn.textContent = '✖';
            this.btn.addEventListener('click', () => this.showMainDialog());
            document.body.appendChild(this.btn);
        }

        // 显示主对话框
        showMainDialog() {
            const dialog = document.createElement('div');
            dialog.className = 'blocker-dialog';
            dialog.innerHTML = `
                <h3>元素屏蔽系统</h3>
                <div style="margin:15px 0">
                    <button id="add-rule">➕ 添加新规则</button>
                    <button id="manage-rules">???? 管理规则</button>
                </div>
            `;

            dialog.querySelector('#add-rule').addEventListener('click', () => this.showAddDialog());
            dialog.querySelector('#manage-rules').addEventListener('click', () => this.showRuleManager());

            this.showModal(dialog);
        }

        // 显示添加规则对话框
        showAddDialog() {
            const dialog = document.createElement('div');
            dialog.className = 'blocker-dialog';
            dialog.innerHTML = `
                <h3>添加XPath规则</h3>
                <textarea
                    id="xpath-input"
                    placeholder="输入XPath表达式(每行一个规则)"
                    style="width:100%; height:100px; margin:10px 0"
                ></textarea>
                <div style="text-align:right">
                    <button class="cancel">取消</button>
                    <button class="confirm">保存</button>
                </div>
            `;

            dialog.querySelector('.cancel').addEventListener('click', () => dialog.remove());
            dialog.querySelector('.confirm').addEventListener('click', () => {
                const input = dialog.querySelector('textarea').value;
                this.addRules(input.split('\n').map(x => x.trim()).filter(x => x));
                dialog.remove();
                this.applyRules();
            });

            this.showModal(dialog);
        }

        // 显示规则管理器
        showRuleManager() {
            const dialog = document.createElement('div');
            dialog.className = 'blocker-dialog';
            dialog.innerHTML = `
                <h3>已保存规则(共${this.rules.length}条)</h3>
                <div id="rule-list" style="max-height:300px;overflow-y:auto;margin:10px 0"></div>
                <div style="text-align:right">
                    <button class="cancel">关闭</button>
                </div>
            `;

            const listContainer = dialog.querySelector('#rule-list');
            this.rules.forEach((rule, index) => {
                const item = document.createElement('div');
                item.className = 'rule-item';
                item.innerHTML = `
                    <div class="rule-index">${index + 1}.</div>
                    <div class="rule-text">${rule}</div>
                    <div class="delete-btn" data-index="${index}">????️</div>
                `;
                item.querySelector('.delete-btn').addEventListener('click', (e) => {
                    const index = parseInt(e.target.dataset.index);
                    this.deleteRule(index);
                    item.remove();
                });
                listContainer.appendChild(item);
            });

            dialog.querySelector('.cancel').addEventListener('click', () => dialog.remove());
            this.showModal(dialog);
        }

        // 显示模态框
        showModal(content) {
            const overlay = document.createElement('div');
            overlay.style = `
                position:fixed;
                top:0;
                left:0;
                width:100%;
                height:100%;
                background:rgba(0,0,0,0.5);
                z-index:2147483645;
            `;
            overlay.appendChild(content);
            overlay.addEventListener('click', (e) => {
                if (e.target === overlay) overlay.remove();
            });
            document.body.appendChild(overlay);
        }

        // 添加新规则
        addRules(newRules) {
            newRules.forEach(rule => {
                if (!this.rules.includes(rule)) {
                    this.rules.push(rule);
                }
            });
            this.saveRules();
        }

        // 删除单条规则
        deleteRule(index) {
            if (index >= 0 && index < this.rules.length) {
                this.rules.splice(index, 1);
                this.saveRules();
                this.applyRules();
            }
        }

        // 应用所有规则
        applyRules() {
            this.rules.forEach(rule => {
                try {
                    const nodes = document.evaluate(
                        rule,
                        document,
                        null,
                        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
                        null
                    );
                    for (let i = 0; i < nodes.snapshotLength; i++) {
                        const node = nodes.snapshotItem(i);
                        node.style.display = 'none';
                    }
                } catch (e) {
                    console.warn(`无效的XPath规则: ${rule}`, e);
                }
            });
        }

        // 设置DOM监听
        setupObserver() {
            new MutationObserver(() => {
                this.applyRules();
            }).observe(document, {
                childList: true,
                subtree: true
            });
        }
    }

    // 初始化系统
    new BlockerSystem();
})();

GM存储版

// ==UserScript==
// @name         XPath元素阻止程序_GM存储版
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  支持GM存储和规则管理的元素屏蔽工具
// @author       YourName
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // 生成网站唯一键名
    const getSiteKey = () => `xpath_rules_${location.hostname}`;

    // 样式配置
    GM_addStyle(`
        #blocker-btn {
            position: fixed;
            bottom: 30px;
            right: 30px;
            z-index: 2147483647;
            width: 45px;
            height: 45px;
            border-radius: 50%;
            background: #2196F3;
            color: white;
            border: none;
            cursor: pointer;
            box-shadow: 0 3px 6px rgba(0,0,0,0.16);
            font-size: 20px;
            transition: transform 0.2s;
        }
        #blocker-btn:hover {
            transform: scale(1.1);
        }
        .blocker-dialog {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 8px 24px rgba(0,0,0,0.2);
            z-index: 2147483646;
            min-width: 320px;
        }
        .blocker-textarea {
            width: 100%;
            height: 120px;
            margin: 12px 0;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            resize: vertical;
        }
        .blocker-btns {
            display: flex;
            gap: 8px;
            justify-content: flex-end;
        }
        .blocker-btn {
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        .blocker-confirm {
            background: #4CAF50;
            color: white;
        }
        .blocker-cancel {
            background: #f44336;
            color: white;
        }
    `);

    class ElementBlocker {
        constructor() {
            this.rules = GM_getValue(getSiteKey(), []);
            this.observer = null;
            this.init();
        }

        init() {
            // 初始化界面
            this.createButton();

            // 应用现有规则
            this.applyRules();

            // 监听动态内容
            this.setupMutationObserver();

            // 注册管理命令
            GM_registerMenuCommand('管理屏蔽规则', () => this.showRuleManager());
        }

        createButton() {
            this.btn = document.createElement('button');
            this.btn.id = 'blocker-btn';
            this.btn.textContent = '⛔';
            this.btn.addEventListener('click', () => this.showDialog());
            document.body.appendChild(this.btn);
        }

        showDialog() {
            if (this.dialog) return;

            this.dialog = document.createElement('div');
            this.dialog.className = 'blocker-dialog';
            this.dialog.innerHTML = `
                <h3 style="margin:0 0 15px">元素屏蔽器</h3>
                <textarea class="blocker-textarea"
                    placeholder="输入要屏蔽的XPath表达式(每行一个)"></textarea>
                <div class="blocker-btns">
                    <button class="blocker-btn blocker-cancel">取消</button>
                    <button class="blocker-btn blocker-confirm">确定</button>
                </div>
            `;

            // 事件绑定
            this.dialog.querySelector('.blocker-cancel').addEventListener('click', () => this.closeDialog());
            this.dialog.querySelector('.blocker-confirm').addEventListener('click', () => {
                const textarea = this.dialog.querySelector('textarea');
                this.processInput(textarea.value);
                this.closeDialog();
            });

            document.body.appendChild(this.dialog);
        }

        closeDialog() {
            this.dialog.remove();
            this.dialog = null;
        }

        processInput(input) {
            const newRules = input.split('\n')
                .map(x => x.trim())
                .filter(x => x.length > 0);

            if (newRules.length > 0) {
                this.rules = [...new Set([...this.rules, ...newRules])];
                this.saveRules();
                this.applyRules();
            }
        }

        applyRules() {
            this.rules.forEach(rule => {
                try {
                    const nodes = document.evaluate(
                        rule,
                        document,
                        null,
                        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
                        null
                    );

                    for (let i = 0; i < nodes.snapshotLength; i++) {
                        const node = nodes.snapshotItem(i);
                        if (node) node.style.display = 'none';
                    }
                } catch (e) {
                    console.warn(`无效的XPath规则: ${rule}`, e);
                }
            });
        }

        saveRules() {
            GM_setValue(getSiteKey(), this.rules);
        }

        setupMutationObserver() {
            this.observer = new MutationObserver(mutations => {
                let shouldUpdate = false;
                mutations.forEach(mutation => {
                    if (mutation.addedNodes.length > 0) shouldUpdate = true;
                });
                if (shouldUpdate) this.applyRules();
            });

            this.observer.observe(document, {
                childList: true,
                subtree: true
            });
        }

        showRuleManager() {
            const manager = document.createElement('div');
            manager.className = 'blocker-dialog';
            manager.innerHTML = `
                <h3 style="margin:0 0 15px">当前屏蔽规则 (${this.rules.length}条)</h3>
                <div style="max-height: 300px; overflow-y: auto; margin-bottom: 15px">
                    ${this.rules.map((rule, index) => `
                        <div style="padding: 8px; border-bottom: 1px solid #eee;">
                            <span style="color:#666">${index + 1}.</span>
                            <code>${rule}</code>
                        </div>
                    `).join('')}
                </div>
                <div class="blocker-btns">
                    <button class="blocker-btn blocker-cancel">关闭</button>
                    <button class="blocker-btn" style="background:#ff9800"
                        id="delete-rule">删除规则</button>
                </div>
            `;

            // 事件绑定
            manager.querySelector('.blocker-cancel').addEventListener('click', () => manager.remove());
            manager.querySelector('#delete-rule').addEventListener('click', () => {
                const index = prompt('请输入要删除的规则编号(列表中的数字):');
                const num = parseInt(index) - 1;

                if (!isNaN(num) && num >= 0 && num < this.rules.length) {
                    this.rules.splice(num, 1);
                    this.saveRules();
                    this.applyRules();
                    alert(`已删除第 ${num + 1} 条规则`);
                    manager.remove();
                } else {
                    alert('无效的编号输入');
                }
            });

            document.body.appendChild(manager);
        }
    }

    // 启动脚本
    new ElementBlocker();
})();

 

 

 

YXN-js

2025-02-26