Versalyt / uBlock Origin Integration Anti-AdBlock Killer

// ==UserScript==
// @name         uBlock Origin Integration Anti-AdBlock Killer
// @namespace    http://tampermonkey.net/
// @version      2.0.0
// @description  Robustly bypasses Anti-Adblock mechanisms by neutralizing detection scripts and removing overlays, focusing on runtime tactics to complement uBlock Origin. Optimized for performance and compatibility.
// @author       John (Optimized by Gemini)
// @run-at       document-start
// @grant        none
// @license      MIT
// @include      *://*.website-with-anti-adblock.com/*
// @include      *://*.another-annoying-site.net/*
// @note         [IMPORTANT] This script is disabled by default. Add the sites you need with "@include" rules above, or enable it manually for specific sites via the Tampermonkey menu for best performance.
// @downloadURL https://openuserjs.org/install/Versalyt/uBlock_Origin_Integration_Anti-AdBlock_Killer.user.js
// @updateURL   https://openuserjs.org/meta/Versalyt/uBlock_Origin_Integration_Anti-AdBlock_Killer.meta.js
// ==/UserScript==

(function() {
    'use strict';

    /**
     * Utility: Safe wrapper for async or complex tasks to prevent script crashes.
     */
    function safeExecute(task, name) {
        try {
            task();
            console.debug(`[uBO-Enhancer v2] Task succeeded: ${name}`);
        } catch (err) {
            console.warn(`[uBO-Enhancer v2] Task failed: ${name}`, err);
        }
    }

    /**
     * Neutralize common anti-adblock global flags and functions using a safer method.
     * This is safer than a global window proxy and less likely to break sites.
     */
    function neutralizeDetectionAPIs() {
        const flagsToNeutralize = [
            'blockAdBlock', 'BlockAdBlock', 'fuckAdBlock', 'AdBlockDetected',
            'adblockDetector', 'canRunAds', 'isAdBlockActive', 'adBlockEnabled',
            'blockDetect', 'adsbygoogle', 'google_ad_client', 'adblockUser',
            'adBlocker'
        ];

        flagsToNeutralize.forEach(flag => {
            try {
                Object.defineProperty(window, flag, {
                    get: () => false,
                    set: () => {},
                    configurable: true
                });
            } catch (e) {
                // Ignore errors, property might already be defined non-configurably.
            }
        });

        const functionsToNeutralize = {
            'detectAdBlock': () => {},
            'checkAdBlock': () => false,
            'adBlockDetected': () => false,
            'showAdBlockMessage': () => {}
        };

        for (const funcName in functionsToNeutralize) {
            try {
                Object.defineProperty(window, funcName, {
                    value: functionsToNeutralize[funcName],
                    writable: false,
                    configurable: false
                });
            } catch (e) {
                // Ignore errors
            }
        }
    }

    /**
     * Prevent timer-based detection checks.
     */
    function protectTimerFunctions() {
        const originalSetTimeout = window.setTimeout;
        const suspiciousStrings = /adblock|detect|banner|sponsor/i;

        window.setTimeout = function(fn, delay, ...args) {
            if (typeof fn === 'string' && suspiciousStrings.test(fn)) {
                console.debug('[uBO-Enhancer v2] Blocked suspicious setTimeout call.');
                return null;
            }
            return originalSetTimeout.call(window, fn, delay, ...args);
        };
    }

    /**
     * Prevent detection based on faking ad element visibility and dimensions.
     * This tricks scripts that check if an ad element is visible or has a valid size.
     */
    function preventDetectionByElementChecks() {
        const originalGetComputedStyle = window.getComputedStyle;
        const adRelatedClasses = /ad |banner|sponsor|advert/i;

        window.getComputedStyle = function(element, pseudoElt) {
            const style = originalGetComputedStyle.call(this, element, pseudoElt);
            if (element && adRelatedClasses.test(element.className)) {
                return new Proxy(style, {
                    get(target, prop) {
                        if (prop === 'display') return 'block';
                        if (prop === 'visibility') return 'visible';
                        if (prop === 'opacity') return '1';
                        return Reflect.get(target, prop);
                    }
                });
            }
            return style;
        };

        const originalGetBoundingClientRect = Element.prototype.getBoundingClientRect;
        Element.prototype.getBoundingClientRect = function() {
            const rect = originalGetBoundingClientRect.call(this);
            if (this && adRelatedClasses.test(this.className)) {
                return {
                    ...rect,
                    width: Math.max(rect.width, 300),
                    height: Math.max(rect.height, 250),
                    x: rect.x || 0,
                    y: rect.y || 0,
                    top: rect.top || 0,
                    left: rect.left || 0,
                    right: rect.right || 300,
                    bottom: rect.bottom || 250,
                };
            }
            return rect;
        };
    }

    /**
     * Monitors the DOM for anti-adblock overlays and removes them.
     * Includes support for searching inside Shadow DOM.
     */
    function removeAdblockOverlays() {
        const suspiciousSelectors = [
            '[class*="adblock"]', '[id*="adblock"]',
            '[class*="ad-block"]', '[id*="ad-block"]',
            '[class*="blocker"]', '[id*="blocker"]',
            '[class*="whitelist"]', '[id*="whitelist"]',
            '[class*="pleasedisable"]', '[id*="pleasedisable"]'
        ].join(', ');

        const observerOptions = { childList: true, subtree: true };

        function isElementAnOverlay(element) {
            try {
                const style = getComputedStyle(element);
                const text = (element.innerText || element.textContent || '').toLowerCase();
                
                // Behavioral check: is it fixed and covering a large part of the screen?
                const isPositionedAsOverlay = (style.position === 'fixed' || style.position === 'absolute') && parseInt(style.zIndex) > 1000;
                const rect = element.getBoundingClientRect();
                const coversScreen = rect.width > window.innerWidth * 0.8 && rect.height > window.innerHeight * 0.8;
                
                // Content check: does it contain suspicious text?
                const hasBlockingText = /adblock|bloqueador|disable|desative|whitelist/i.test(text);

                if (isPositionedAsOverlay && (coversScreen || hasBlockingText)) {
                    console.info('[uBO-Enhancer v2] Anti-adblock overlay detected and removed:', element);
                    element.remove();
                    
                    // Restore scrolling to the page
                    document.body.style.overflow = '';
                    document.documentElement.style.overflow = '';
                    
                    return true;
                }
            } catch (e) {
                // Ignore errors for elements that might be removed during checks.
            }
            return false;
        }

        function scanNode(node) {
            if (node.nodeType !== 1) return; // Only scan element nodes

            // Scan direct children
            if (node.matches(suspiciousSelectors)) {
                isElementAnOverlay(node);
            }
            // Scan descendants
            node.querySelectorAll(suspiciousSelectors).forEach(isElementAnOverlay);

            // Scan inside Shadow DOM, if it exists
            if (node.shadowRoot) {
                scanNode(node.shadowRoot);
            }
        }

        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                for (const addedNode of mutation.addedNodes) {
                    scanNode(addedNode);
                }
            }
        });
        
        // Function to start observing a root (document or a shadowRoot)
        function observeRoot(rootNode) {
            scanNode(rootNode); // Initial scan
            observer.observe(rootNode, observerOptions);
        }
        
        // Initial scan and observation of the main document
        if (document.body) {
             observeRoot(document.body);
        } else {
            document.addEventListener('DOMContentLoaded', () => observeRoot(document.body), { once: true });
        }
        
        // Scan for all existing and future shadow roots
        function scanForShadowRoots(root) {
             root.querySelectorAll('*').forEach(el => {
                 if (el.shadowRoot) {
                     observeRoot(el.shadowRoot);
                 }
             });
        }
        
        // Run after DOM is ready and periodically
        const startShadowDOMScan = () => scanForShadowRoots(document.documentElement);
        if (document.readyState === 'complete') {
            startShadowDOMScan();
        } else {
            window.addEventListener('load', startShadowDOMScan, { once: true });
        }
    }


    /**
     * Initialize all enhancements safely.
     */
    function init() {
        // --- Phase 1: Run immediately at document-start ---
        // These need to run before the page's scripts.
        const immediateTasks = [
            { fn: neutralizeDetectionAPIs, name: 'Neutralize Detection APIs' },
            { fn: protectTimerFunctions, name: 'Protect Timer Functions' },
            { fn: preventDetectionByElementChecks, name: 'Prevent Element-based Detection' }
        ];

        immediateTasks.forEach(task => safeExecute(task.fn, task.name));

        // --- Phase 2: Run when the DOM is interactive/loaded ---
        // These tasks operate on DOM elements.
        const delayedTasks = [
            { fn: removeAdblockOverlays, name: 'Remove Adblock Overlays' }
        ];

        const runDelayedTasks = () => {
            delayedTasks.forEach(task => safeExecute(task.fn, task.name));
        };

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', runDelayedTasks, { once: true });
        } else {
            runDelayedTasks();
        }

        console.info('[uBO-Enhancer v2] Script loaded and initialized.');
    }

    init();
})();