PWNEDuo (based on DuoHacker).

Duolingo automation auto answer script. Include skill leveling up (13.01.2023 update)

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        PWNEDuo (based on DuoHacker).
// @description  Duolingo automation auto answer script. Include skill leveling up (13.01.2023 update)
// @namespace   Violentmonkey Scripts
// @match       https://*.duolingo.com/*
// @grant       none
// @version     1.0.4
// @author      hprnv
// @license MIT
// ==/UserScript==
 
var intervalId;
var isAutoMode = false;
function addButtons() {
    
    if(window.location.pathname == '/learn'){
        let button = document.querySelector('a[data-test="global-practice"]');
        if(button){
            button.click();
            return;
        }
    }
    
    if (document.getElementById("solveAllButton") !== null) {
        return;
    }
 
    let original = document.querySelectorAll('[data-test="player-next"]')[0];
    let wrapper = document.getElementsByClassName('_10vOG')[0];
    if (original == undefined) {
        let startButton = document.querySelector('[data-test="start-button"]');
        if (startButton == undefined) {
            return;
        }
        let wrapper = startButton.parentNode;
        let autoComplete = document.createElement('a');
        autoComplete.className = startButton.className;
        autoComplete.id = "solveAllButton";
        autoComplete.innerText = "COMPLETE SKILL";
        autoComplete.removeAttribute('href');
        autoComplete.onclick = function () {
            startSolving();
            setInterval(function () {
                let startButton = document.querySelector('[data-test="start-button"]');
                if (startButton && startButton.innerText.startsWith("START")) {
                    startButton.click();
                }
            }, 3000);
            startButton.click();
        };
        wrapper.appendChild(autoComplete);
    } else {
 
        wrapper.style.display = "flex";
 
        let solveCopy = document.createElement('button');
        let pauseCopy = document.createElement('button');
 
        solveCopy.id = 'solveAllButton';
        if (intervalId) {
            solveCopy.innerHTML = 'PAUSE SOLVE';
        } else {
            solveCopy.innerHTML = 'SOLVE ALL';
        }
        solveCopy.disabled = false;
        pauseCopy.innerHTML = 'SOLVE';
 
        const buttonStyle = `
            min-width: 150px;
            font-size: 17px;
            border:none;
            border-bottom: 4px solid #58a700;
            border-radius: 18px;
            padding: 13px 16px;
            transform: translateZ(0);
            transition: filter .2s;
            font-weight: 700;
            letter-spacing: .8px;
            background: #55CD2E;
            color:#fff;
            margin-left:20px;
            cursor:pointer;
        `;
 
        solveCopy.style.cssText = buttonStyle;
        pauseCopy.style.cssText = buttonStyle;
 
        //Hover effect for buttons
 
        function mouseOver(x) {
            x.style.filter = "brightness(1.1)";
        }
 
        function mouseLeave(x) {
            x.style.filter = "none";
        }
 
        let buttons = [solveCopy, pauseCopy]
 
        buttons.forEach(button => {
            button.addEventListener("mousemove", () => {
                mouseOver(button);
            });
        });
 
        buttons.forEach(button => {
            button.addEventListener("mouseleave", () => {
                mouseLeave(button);
            });
        });
 
 
 
        original.parentElement.appendChild(pauseCopy);
        original.parentElement.appendChild(solveCopy);
 
 
        solveCopy.addEventListener('click', solving);
        pauseCopy.addEventListener('click', solve);
    }
}
 
setInterval(addButtons, 3000);
 
function solving() {
    if (intervalId) {
        pauseSolving();
    } else {
        startSolving();
    }
}
 
function startSolving() {
    if (intervalId) {
        return;
    }
    document.getElementById("solveAllButton").innerText = "PAUSE SOLVE";
    isAutoMode = true;
    intervalId = setInterval(solve, 500);
}
 
function pauseSolving() {
    if (!intervalId) {
        return;
    }
    document.getElementById("solveAllButton").innerText = "SOLVE ALL";
    isAutoMode = false;
    clearInterval(intervalId);
    intervalId = undefined;
}
 
function solve() {
    let selAgain = document.querySelectorAll('[data-test="player-practice-again"]');
    if (selAgain.length === 1 && isAutoMode) {
        // Make sure it's the `practice again` button
        //if (selAgain[0].innerHTML.toLowerCase() === 'practice again') {
            // Click the `practice again` button
            selAgain[0].click();
            // Terminate
            return;
        //}
    }
    try {
        window.sol = FindReact(document.getElementsByClassName('_3FiYg')[0]).props.currentChallenge;
    } catch {
        let next = document.querySelector('[data-test="player-next"]');
        if (next) {
            next.click();
        }
        return;
    }
    if (!window.sol) {
        return;
    }
    let btn = null;
 
    let selNext = document.querySelectorAll('[data-test="player-next"]');
    
 
    if (selNext.length === 1) {
        // Save the button element
        btn = selNext[0];
        if(document.querySelectorAll('[data-test*="challenge-speak"]').length > 0){
            let buttonSkip = document.querySelector('button[data-test="player-skip"]');
            if(buttonSkip){
                buttonSkip.click();
            }
        }
 
        if (document.querySelectorAll('[data-test="challenge-choice"]').length > 0) {
            if (window.sol.correctIndices) {
                window.sol.correctIndices?.forEach(index => {
                    document.querySelectorAll('[data-test="challenge-choice"]')[index].children[0].click();
                });
                // Click the first element
            } else if (window.sol.articles) {
                var article = '';
                for (var i = 0; i < window.sol.articles.length; i++) {
                    if (window.sol.correctSolutions[0].startsWith(window.sol.articles[i])) {
                        Array.from(document.querySelectorAll('[data-test="challenge-choice"]'))
                            .find((elm) =>
                                elm.querySelector('[data-test="challenge-judge-text"]').innerText == window.sol.articles[i]
                            ).click();
                        article = window.sol.articles[i];
                        break;
                    }
                }
                let elm = document.querySelectorAll('[data-test="challenge-text-input"]')[0];
                let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
                nativeInputValueSetter.call(elm, window.sol.correctSolutions ? window.sol.correctSolutions[0].replace(article + ' ', '') : (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank).text : window.sol.prompt));
                let inputEvent = new Event('input', {
                    bubbles: true
                });
 
                elm.dispatchEvent(inputEvent);
            } else {
                document.querySelectorAll('[data-test="challenge-choice"]')[window.sol.correctIndex].click();
            }
            // Click the solve button
            btn.click();
        }
 
        if (document.querySelectorAll('[data-test="challenge-choice-card"]').length > 0) {
            // Click the first element
            if (window.sol.correctIndices) {
                window.sol.correctIndices?.forEach(index => {
                    document.querySelectorAll('[data-test="challenge-choice-card"]')[index].children[0].click();
                });
            } else {
                document.querySelectorAll('[data-test="challenge-choice-card"]')[window.sol.correctIndex].click();
            }
            // Click the solve button
            btn.click();
        }
 
        if (window.sol.type == 'listenMatch') {
            let nl = document.querySelectorAll('[data-test="challenge-tap-token"]');
            window.sol.pairs?.forEach((pair) => {
                for (let i = 0; i < nl.length; i++) {
                    let nlInnerText;
                    if (nl[i].querySelectorAll('[data-test="challenge-tap-token-text"]').length > 1) {
                        nlInnerText = nl[i].querySelector('[data-test="challenge-tap-token-text"]').innerText.toLowerCase().trim();
                    } else {
                        nlInnerText = FindSubReact(nl[i]).text.toLowerCase().trim();
                    }
                    if (
                        (
                            nlInnerText == pair.learningWord.toLowerCase().trim() ||
                            nlInnerText == pair.translation.toLowerCase().trim()
                        ) &&
                        !nl[i].disabled
                    ) {
                        nl[i].click();
                    }
                }
            });
        }
 
        if (window.sol.type == 'listenSpell') {
            let tokens = window.sol.displayTokens.filter(x => x.damageStart !== undefined);
            let elms = document.querySelectorAll('._2cjP3._2IKiF');
            let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
 
            var solutionCharacters = [];
            for (let tok of tokens) {
                for (let i = tok.damageStart; i < tok.damageEnd; i++) {
                    solutionCharacters.push(tok.text[i]);
                }
            }
 
            for (var elmIndex = 0; elmIndex < elms.length; elmIndex++) {
                nativeInputValueSetter.call(elms[elmIndex], solutionCharacters[elmIndex]);
 
                let inputEvent = new Event('input', {
                    bubbles: true
                });
 
                elms[elmIndex].dispatchEvent(inputEvent);
            }
        }
 
        if (document.querySelectorAll('[data-test="challenge-tap-token"]').length > 0) {
            // Click the first element
            if (window.sol.pairs) {
                let nl = document.querySelectorAll('[data-test="challenge-tap-token"]');
                if (document.querySelectorAll('[data-test="challenge-tap-token-text"]').length == document.querySelectorAll('[data-test="challenge-tap-token"]').length) {
                    window.sol.pairs?.forEach((pair) => {
                        for (let i = 0; i < nl.length; i++) {
                            const nlInnerText = nl[i].querySelector('[data-test="challenge-tap-token-text"]').innerText.toLowerCase().trim();
                            if (
                                (
                                    nlInnerText == pair.learningToken.toLowerCase().trim() ||
                                    nlInnerText == pair.fromToken.toLowerCase().trim()
                                ) &&
                                !nl[i].disabled
                            ) {
                                nl[i].click();
                            }
                        }
                    });
                }
            } else if(!window.sol.correctTokens){
                let clicked = {}
                let nl = document.querySelectorAll('[data-test="challenge-tap-token"]');
                window.sol.correctIndices?.forEach(index => {
                    let correctAnswer = window.sol.choices[index];
                    for (let i = 0; i < nl.length; i++) {
                        if ((nl[i].innerText).toLowerCase().trim() == correctAnswer.text.toLowerCase().trim() && !nl[i].disabled && !clicked[i]) {
                            clicked[i] = 1;
                            nl[i].click();
                            break;
                        }
                    }
                });
            } else {
                let clicked = {}
                let nl = document.querySelectorAll('[data-test="challenge-tap-token"]');
                window.sol.correctIndices?.forEach(index => {
                    let correctAnswer = window.sol.correctTokens[index];
                    for (let i = 0; i < nl.length; i++) {
                        if ((nl[i].innerText).toLowerCase().trim() == correctAnswer.toLowerCase().trim() && !nl[i].disabled && !clicked[i]) {
                            clicked[i] = 1;
                            nl[i].click();
                            break;
                        }
                    }
                });
            }
            // Click the solve button
            btn.click();
        }
 
        if (document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) {
 
            let elm = document.querySelectorAll('[data-test="challenge-text-input"]')[0];
            let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
            nativeInputValueSetter.call(elm, window.sol.correctSolutions ? window.sol.correctSolutions[0] : (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank).text : window.sol.prompt));
            let inputEvent = new Event('input', {
                bubbles: true
            });
 
            elm.dispatchEvent(inputEvent);
        }
 
 
		 if (document.querySelectorAll('[data-test*="challenge-partialReverseTranslate"]').length > 0) {
            let elm = document.querySelector('[data-test*="challenge-partialReverseTranslate"]')?.querySelector("span[contenteditable]");
            let nativeInputNodeTextSetter = Object.getOwnPropertyDescriptor(Node.prototype, "textContent").set
            nativeInputNodeTextSetter.call(elm, '"' + window.sol?.displayTokens?.filter(t => t.isBlank)?.map(t=>t.text)?.join()?.replaceAll(',', '') + '"');
            let inputEvent = new Event('input', {
                bubbles: true
            });
 
            elm.dispatchEvent(inputEvent);
        }
 
        if (document.getElementsByTagName('textarea').length > 0) {
            let elm = document.getElementsByTagName('textarea')[0]
 
            let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
            nativeInputValueSetter.call(elm, window.sol.correctSolutions ? window.sol.correctSolutions[0] : window.sol.prompt);
 
            let inputEvent = new Event('input', {
                bubbles: true
            });
 
            elm.dispatchEvent(inputEvent);
        }
 
        // Continue
        btn.click();
    }
}
 
function FindSubReact(dom, traverseUp = 0) {
    const key = Object.keys(dom).find(key => key.startsWith("__reactProps$"));
    return dom.parentElement[key].children.props;
}
 
function FindReact(dom, traverseUp = 0) {
    const key = Object.keys(dom.parentElement).find(key => key.startsWith("__reactProps$"));
    return dom.parentElement[key].children[0]._owner.stateNode;
}
 
window.findReact = FindReact;
 
window.ss = startSolving;