Greasy Fork

Greasy Fork is available in English.

Udemy Progress Control

The script can automatically check or uncheck off completed lessons of courses or sections, saving users time and effort in manually marking them as completed.

// ==UserScript==
// @name         Udemy Progress Control
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  The script can automatically check or uncheck off completed lessons of courses or sections, saving users time and effort in manually marking them as completed.
// @author       realzam
// @match        https://www.udemy.com/course/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=udemy.com
// @grant        none
// @license MIT
// ==/UserScript==


function awaitToElement(element){
    return new Promise((resolve) => {
        let nIntervId = setInterval(()=>{
            const isReady=document.querySelectorAll(element).length != 0
            if(isReady){
                resolve()
                clearInterval(nIntervId)
            }
        },100)
        });
}

function seccionCollapse(seccion,action){
    return new Promise(async(resolve) => {
        const seccionButtonCollapse =seccion.querySelector('button[type="button"]')
        const isChecked = seccion.querySelector('span[data-checked]').getAttribute('data-checked') === 'checked'
        console.log(seccion.getAttribute('data-purpose'),isChecked)
        if(isChecked!=action){
            seccionButtonCollapse.click()
            if(action){
                await awaitToElement('ul.ud-unstyled-list')
            }
        }
        resolve()
    });
}

const isPageLoaded = async()=> awaitToElement('div[data-purpose="curriculum-section-container"]')

async function actioSeccion(seccion,action){
    await seccionCollapse(seccion,true)
    const leccions=seccion.childNodes[2].childNodes[0].childNodes[0].childNodes
    for(const leccion of leccions)
    {
        if(leccion.querySelector('input').checked !=action)
        {
            leccion.querySelector('input').click()
        }
    }
    await seccionCollapse(seccion,false)

}

async function actionCourse(seccions,action){
    for(const seccion of seccions)
    {
        await actioSeccion(seccion,action)
    }
}


async function main() {
    await isPageLoaded();
    const seccions = document.querySelector('#ct-sidebar-scroll-container > div > div').childNodes;
    const courseActions = document.querySelector('section[data-purpose="sidebar"]').childNodes[0];

    let completeAllCourseBtn = document.createElement("div");
    completeAllCourseBtn.tabIndex=0
    completeAllCourseBtn.role="button"
    completeAllCourseBtn.className = "item-link ud-btn ud-btn-small ud-btn-primary ud-heading-sm";
    completeAllCourseBtn.innerHTML ='<span>Complete</span>'
    completeAllCourseBtn.onclick = ()=>{actionCourse(seccions,true)};

    let resetCourseBtn = document.createElement("div");
    resetCourseBtn.tabIndex=0
    resetCourseBtn.role="button"
    resetCourseBtn.className = "item-link ud-btn ud-btn-small ud-btn-secondary ud-heading-sm";
    resetCourseBtn.innerHTML ='<span>Reset</span>'
    resetCourseBtn.onclick = ()=>{actionCourse(seccions,false)};

    courseActions.appendChild(completeAllCourseBtn)
    courseActions.appendChild(resetCourseBtn)

    for(const seccion of seccions)
    {
        let checkAllSeccionnBtn = document.createElement("div");
        checkAllSeccionnBtn.tabIndex=0
        checkAllSeccionnBtn.role="button"
        checkAllSeccionnBtn.className = "item-link ud-btn ud-btn-small ud-btn-primary ud-heading-sm";
        checkAllSeccionnBtn.innerHTML ='<span>Check All</span>'
        checkAllSeccionnBtn.style.margin='5px'
        checkAllSeccionnBtn.onclick = ()=>{actioSeccion(seccion,true)}

        let uncheckAllSeccionnBtn = document.createElement("div");
        uncheckAllSeccionnBtn.tabIndex=0
        uncheckAllSeccionnBtn.role="button"
        uncheckAllSeccionnBtn.className = "item-link ud-btn ud-btn-small ud-btn-secondary ud-heading-sm";
        uncheckAllSeccionnBtn.innerHTML ='<span>Uncheck All</span';
        uncheckAllSeccionnBtn.style.margin='5px'
        uncheckAllSeccionnBtn.onclick = ()=>{actioSeccion(seccion,false)};

        seccion.appendChild(checkAllSeccionnBtn)
        seccion.appendChild(uncheckAllSeccionnBtn)
    }

}

main()