DuckDuckGo and Google Search Filter

Remove search results from DuckDuckGo and Google by URL

// ==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();

})();