// ==UserScript== // @name Udemy - show section time // @namespace http://tampermonkey.net/ // @version 1.2 // @description For Udemy, displays the time a section has ( remaining time / total time). // @copyright 2017, Pedro Mass (https://github.com/pedro-mass) // @author pedro-mass // @match *.udemy.com/* // @grant none // @require http://code.jquery.com/jquery-3.2.0.min.js // @require https://greasyfork.org/scripts/5392-waitforkeyelements/code/WaitForKeyElements.js?version=115012 // @run-at document-idle // @downloadURL none // ==/UserScript== (function() { var selectors = { sectionCard: 'curriculum-navigation-section', sectionName: '.curriculum-navigation__section__title', // class needed by this user script sectionTime: '.section-time', lectureItem: '.lecture__item', lectureTime: '.lecture__item__link__time', lectureStatus: '.cur-status', lectureCheck: '.udi-check', lectureProgress : '#top-detail > div.detail__progress > div > div.fx', }; // run(); // waits for the cards to be loaded waitForKeyElements(selectors.sectionCard, run, true); /** Gets total and remaining time for each section. Displays these per section. Display the total of all sections */ function run() { var sections = $(selectors.sectionCard); var totalLectureTime = 0; var remainingLectureTime = 0; $.each(sections, function(index, section) { // remove previous time display $(section).find(selectors.sectionTime).remove(); // get the section title var title = $(section).find(selectors.sectionName).text(); // get the total times var totalTimeTexts = getTimeTexts(section, false); var totalTimeSeconds = textTimesToSeconds(totalTimeTexts); var totalTime = secondsToTextTime(totalTimeSeconds); // update the lecture time totalLectureTime += totalTimeSeconds; // initialize the text to display with the total time var textToDisplay = totalTime; // check if we need to display partial time if (checkPartialTime(section)) { // sum the partial times var partialTimeTexts = getTimeTexts(section, true); var partialTimeSeconds = textTimesToSeconds(partialTimeTexts); var partialTime = secondsToTextTime(partialTimeSeconds); // update the lecture time remainingLectureTime += partialTimeSeconds; // prepend partial time textToDisplay = partialTime + ' / ' + textToDisplay; } // check if we need to add up the total time to remaining time if (getRemainingParts(section) === 0) { remainingLectureTime += totalTimeSeconds; } // display the section text displaySectionTime(section, textToDisplay); }); // display lecture totals displayLectureTimeProgress(totalLectureTime, remainingLectureTime); // stops the script from running continuously return false; } function displayLectureTimeProgress(totalLectureTime, remainingLectureTime) { // start with total var displayText = secondsToTextTime(totalLectureTime); // conditional add remaining if (remainingLectureTime) { displayText = secondsToTextTime(remainingLectureTime) + ' / ' + displayText; } // surround in parens displayText = '(' + displayText + ')'; // add to DOM var lectureProgressClass = 'lecture-progress-time'; var lectureProgressSpans = $(selectors.lectureProgress).find('.' + lectureProgressClass); if (lectureProgressSpans.length > 0) { $(lectureProgressSpans[0]).text(displayText); } else { $(selectors.lectureProgress + ' > div').before( '' + displayText + '' ); } return displayText; } /* Gets the section parts and checks if it's not 0 or the total parts */ function checkPartialTime(section) { // get the section parts var sectionParts = getSectionParts(section); // determine what times to get var totalSections = sectionParts[1]; var sectionsToGo = sectionParts[0]; return sectionsToGo !== 0 && sectionsToGo != totalSections; } function getRemainingParts(section) { // get the section parts var sectionParts = getSectionParts(section); // determine what times to get return sectionParts[0]; } /** Get the section's time. Whether partial or total is determined by the passed in parameter. */ function getTimeTexts(section, isPartialTime) { // get the times var $lectures = $(section).find(selectors.lectureItem); // Check for partial time if (isPartialTime) { // filter down to just the non-completed ones $lectures = $lectures.filter(':not(.completed)'); } // get the time spans var timeSpans = $lectures.find(selectors.lectureTime); // convert to timeTexts and return return convertTimeSpansToTexts(timeSpans); } function displaySectionTime(section, displayText) { var sectionTimeClass = 'section-time'; // prepend to lecture status var totalTimeSpan = $(section).find(selectors.lectureStatus).find(sectionTimeClass); // check to see if we've already added the time to the DOM if (totalTimeSpan.length > 0) { $(totalTimeSpan[0]).text(displayText); } else { // we haven't, so create the element and add it $(section).find(selectors.lectureStatus) .prepend(''+ displayText + ''); } } function getSectionParts(section) { return $(section).find(selectors.lectureStatus).text() // split up the parts by "/" .split('/') // trim up the space .map(function(text) { return text.trim(); }); } function convertTimeSpansToTexts(timeSpans) { var timeTexts = []; for (var i=0; i hh:mm:ss function getTime(hours, minutes, seconds) { var result = ''; // get the hours part if (hours > 0) { result += hours + ':'; result += timePad(minutes); } else { // we didn't have any hours result += minutes; } // check for minutes if (minutes > 0) { result += ':' + timePad(seconds); } else { // we didn't have any minutes, but we should say 0 result += '0:' + timePad(seconds); } return result; } // time should be a length of 2, so prepend with 0 function timePad(timeSegment) { var result = timeSegment + ''; while (result.length < 2) { result = '0' + result; } return result; } })();