Greasy Fork

Greasy Fork is available in English.

Duolingo Blur

Blur the text unless shift is held

当前为 2025-07-14 提交的版本,查看 最新版本

// ==UserScript==
// @name         Duolingo Blur
// @description  Blur the text unless shift is held
// @namespace    http://tampermonkey.net/
// @version      1.0.3
// @author       You
// @match        https://www.duolingo.com/*
// @license      MIT
// ==/UserScript==

const duoBlurClass = 'duo-blur'

const skipDataTests = [
    'session-duo',
    'session-complete-slide',
    'daily-quest-progress-slide',
    'daily-quest-reward-slide',
]

const style = document.createElement('style');
style.textContent = `
    .duo-blur .XxgPa {
        filter: blur(6px);
    }
`;
document.head.appendChild(style);
document.body.classList.add(duoBlurClass)

function setBlur(enabled) {
    if (enabled && !document.body.classList.contains(duoBlurClass)) {
        document.body.classList.add(duoBlurClass);
    } else if (!enabled && document.body.classList.contains(duoBlurClass)) {
        document.body.classList.remove(duoBlurClass);
    }
}

let hideBlurOverride = false;

function setShiftDown(shiftDown) {
    setBlur(!shiftDown);
    hideBlurOverride = shiftDown;
}

document.addEventListener('keydown', e => {
    if (e.key === 'Shift') {
        setShiftDown(true);
        hideBlurOverride = true;
    } else if (e.key === 'Enter') {
        document.getElementsByClassName("_1rcV8 _1VYyp _1ursp _7jW2t PbV1v _2sYfM _19ped")[0]?.click() // start lesson
        document.getElementsByClassName("_1rcV8 _1VYyp _1ursp _7jW2t _2CzYJ _2JGBA _1A_ri")[0]?.click() // complete legendary
    }
});
document.addEventListener('keyup', e => {
    if (e.key === 'Shift') {
        setShiftDown(false);
    }
});

function hasSpeakerButton() {
    return !!document.getElementsByClassName('_1OCYa').length
}

function shouldSkipScreen() {
    for (const dataTest of skipDataTests) {
        if (document.querySelector(`[data-test="${dataTest}"]`)) {
            return true
        }
    }

    return false
}

function clickNext() {
    document.querySelector('[data-test="player-next"]')?.click()
}

function onTimer() {
    if (!hideBlurOverride) {
        setBlur(hasSpeakerButton());
    }

    if (shouldSkipScreen()) {
        console.log('SKIP')
        clickNext()
    }
}

document.addEventListener('visibilitychange', () => {
    if (document.hidden) setShiftDown(false);
});

window.addEventListener('blur', () => {
    setShiftDown(false);
});

setInterval(onTimer, 50)