Super Duolingo Ad Blocker

Block ads and unwanted promotional content on Duolingo, including dynamically named ad classes, while preserving essential lesson content and handling fullscreen ads by pressing the exit button automatically or selecting "No Thanks" on specific ads.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Super Duolingo Ad Blocker
// @version      1.0
// @description  Block ads and unwanted promotional content on Duolingo, including dynamically named ad classes, while preserving essential lesson content and handling fullscreen ads by pressing the exit button automatically or selecting "No Thanks" on specific ads.
// @author       Zinovia
// @match        https://*.duolingo.com/*
// @grant        none
// @namespace https://greasyfork.org/users/1340999
// ==/UserScript==

(function() {
    'use strict';

    // Function to inject CSS into the document
    function addStyles(css) {
        const style = document.createElement('style');
        style.type = 'text/css';
        style.textContent = css;
        document.head.appendChild(style);
    }

    // CSS to hide specific promotional and ad content
    const styles = `
        /* Specific divs associated with ads and promotions, conditional on not being essential content */
        div[data-test="purchase-step-active"],
        div._3D_HB,
        div._16rRh,
        div._16rRh._2cnFr._1T_BQ,
        div._1tzFd,
        div._1Qh5D._36g4N._2YF0P.uapW2,
        div._3ZUrl._2BflZ,
        div.MGk8p,
        div._3ywWe,
        div._1145W,
        div.Vm8CO._2zxQ8,
        iframe[name="__privateStripeController7431"] {
            display: none !important;
        }
    `;

    // Inject styles into the document
    addStyles(styles);

    // Function to dynamically hide elements
    function hideElements() {
        const selectors = [
            'div[data-test="purchase-step-active"]',
            'div._3D_HB',
            'div._16rRh',
            'div._16rRh._2cnFr._1T_BQ',
            'div._1tzFd',
            'div._1Qh5D._36g4N._2YF0P.uapW2',
            'div._3ZUrl._2BflZ',
            'div.MGk8p',
            'div._3ywWe',
            'div._1145W',
            'div.Vm8CO._2zxQ8',
            'iframe[name="__privateStripeController7431"]'
        ];

        selectors.forEach(selector => {
            document.querySelectorAll(selector).forEach(element => {
                if (!element.closest('#session/PlayerFooter') && 
                    !element.closest('div._1QQhE') &&
                    !element.closest('div._3rB4d._1VTif._2HXQ9')) { // Ensure essential content is not hidden
                    element.style.display = 'none';
                }
            });
        });
    }

    // Function to press the exit button on fullscreen ads
    function pressExitButton() {
        const exitButton = document.querySelector('._3vGNs._2YF0P._1Udkq');
        if (exitButton) {
            exitButton.click();
            console.log('Fullscreen ad exit button clicked!');
        }
    }

    // Function to click the "No Thanks" button on the new type of full-screen ad
    function pressNoThanksButton() {
        const noThanksButton = document.querySelector('button._1Qh5D._36g4N._2YF0P._76ebC._3h0lA._1S2uf.cnGdv');
        if (noThanksButton) {
            noThanksButton.click();
            console.log('No Thanks button clicked!');
        }
    }

    // Function to click the button in the lesson
    function clickLessonButton() {
        const button = document.querySelector('._3vGNs._2YF0P._1Udkq');
        if (button) {
            button.click();
            console.log('Lesson button clicked!');
        }
    }

    // Function to handle the blank screen issue
    function handleBlankScreen() {
        const continueButton = document.querySelector('button[data-test="player-next"]');
        if (continueButton) {
            continueButton.click();
            console.log('Continue button clicked!');
        }
        const reviewLessonButton = document.querySelector('button span._1o-YO:contains("Review lesson")');
        if (reviewLessonButton) {
            reviewLessonButton.click();
            console.log('Review lesson button clicked!');
        }
    }

    // Run initial functions
    hideElements();
    pressExitButton();
    pressNoThanksButton();
    clickLessonButton();
    handleBlankScreen();

    // Observe DOM changes and apply modifications as necessary
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.type === 'childList') {
                hideElements();
                pressExitButton();
                pressNoThanksButton();
                clickLessonButton();
                handleBlankScreen();
            }
        });
    });

    // Start observing the body for child list changes
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    console.log('Super Duolingo Ad Blocker initialized.');
})();