// ==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 // @downloadURL https://update.greasyfork.icu/scripts/463490/Udemy%20Progress%20Control.user.js // @updateURL https://update.greasyfork.icu/scripts/463490/Udemy%20Progress%20Control.meta.js // ==/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 ='Complete' 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 ='Reset' 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 ='Check All' 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 ='Uncheck All{actioSeccion(seccion,false)}; seccion.appendChild(checkAllSeccionnBtn) seccion.appendChild(uncheckAllSeccionnBtn) } } main()