您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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()