Greasy Fork 还支持 简体中文。

DuckDuckGo and Google Search Filter

Remove search results from DuckDuckGo and Google by URL

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         DuckDuckGo and Google Search Filter
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Remove search results from DuckDuckGo and Google by URL
// @author       sedevacante
// @include      http*://www.google.*/search?*
// @match        *://duckduckgo.com/*
// @grant        none
// @license      GPLv2; http://www.gnu.org/licenses/
// ==/UserScript==

(function () {
    'use strict';

    // Function to load blocked URLs from localStorage
    function loadBlockedUrls() {
        return JSON.parse(localStorage.getItem('blockedUrls') || '[]');
    }

    // Function to save blocked URLs to localStorage
    function saveBlockedUrls(urls) {
        localStorage.setItem('blockedUrls', JSON.stringify(urls));
    }

    // Function to block an individual search result
    function blockResult(url, element) {
        let blockedUrls = loadBlockedUrls();
        if (!blockedUrls.includes(url)) {
            blockedUrls.push(url);
            saveBlockedUrls(blockedUrls);
        }
        element.remove(); // Completely remove the result from the page
    }

    // Function to check and remove already blocked URLs on page load
    function removeBlockedResults() {
        const blockedUrls = loadBlockedUrls();

        // DuckDuckGo logic
        const duckResults = document.querySelectorAll('ol.react-results--main li');
        duckResults.forEach((li) => {
            const link = li.querySelector('a');
            if (link && blockedUrls.includes(link.href)) {
                li.remove(); // Completely remove the result if blocked
            }
        });

        // Google logic
        const googleResults = document.querySelectorAll('div#rso div[data-ved]');
        googleResults.forEach((div) => {
            const link = div.querySelector('a');
            if (link && blockedUrls.includes(link.href)) {
                div.remove(); // Completely remove the result if blocked
            }
        });
    }

    // Function to add "X" buttons next to each search result (only if not blocked)
    function addBlockButtons() {
        const blockedUrls = loadBlockedUrls();

        // DuckDuckGo logic
        const duckResults = document.querySelectorAll('ol.react-results--main li');
        duckResults.forEach((li) => {
            const link = li.querySelector('a');
            // Only add "X" button if URL is not blocked
            if (link && !blockedUrls.includes(link.href)) {
                if (!li.querySelector('.block-btn')) {
                    const blockBtn = document.createElement('button');
                    blockBtn.textContent = 'X';
                    blockBtn.className = 'block-btn';
                    blockBtn.style.marginLeft = '10px';
                    blockBtn.addEventListener('click', (e) => {
                        e.preventDefault();
                        blockResult(link.href, li);  // Completely remove the result
                    });
                    li.appendChild(blockBtn);
                }
            }
        });

        // Google logic
        const googleResults = document.querySelectorAll('div#rso div[data-ved]');
        googleResults.forEach((div) => {
            const link = div.querySelector('a');
            // Only add "X" button if URL is not blocked
            if (link && !blockedUrls.includes(link.href)) {
                if (!div.querySelector('.block-btn')) {
                    const blockBtn = document.createElement('button');
                    blockBtn.textContent = 'X';
                    blockBtn.className = 'block-btn';
                    blockBtn.style.marginLeft = '10px';
                    blockBtn.addEventListener('click', (e) => {
                        e.preventDefault();
                        blockResult(link.href, div);  // Completely remove the result
                    });
                    div.appendChild(blockBtn);
                }
            }
        });
    }

    // Function to handle page changes (URL changes or dynamic content loads)
    function monitorPageChanges() {
        let lastUrl = location.href;
        new MutationObserver(() => {
            const currentUrl = location.href;
            if (currentUrl !== lastUrl) {
                lastUrl = currentUrl;
                setTimeout(() => {
                    // Re-run the block and button logic on page change
                    removeBlockedResults();
                    addBlockButtons();
                }, 500);  // Delay to ensure content is loaded
            }
        }).observe(document.body, { childList: true, subtree: true });
    }

    // Initial check for blocked URLs
    removeBlockedResults();
    addBlockButtons();

    // Observer to dynamically add block buttons as new results load
    const observer = new MutationObserver((mutations) => {
        addBlockButtons();
        removeBlockedResults(); // Ensure blocked results are removed on page changes
    });

    // Observe body for changes
    observer.observe(document.body, { childList: true, subtree: true });

    // Monitor URL changes and handle page navigation
    monitorPageChanges();

})();