Skip to content

Instantly share code, notes, and snippets.

@ahmedazhar05
Last active July 19, 2023 15:33
Show Gist options
  • Save ahmedazhar05/861d742560bcf6d4cf5a49e4fa4695ac to your computer and use it in GitHub Desktop.
Save ahmedazhar05/861d742560bcf6d4cf5a49e4fa4695ac to your computer and use it in GitHub Desktop.
Udemy Fast-forward bookmarklet
javascript:(function forwarder(toggle_script_execution = false) {
const start_alert = () => console.log("%c Forwarder script started running...", "color: green");
const stop_alert = () => console.log("%c Forwarder script stopped running!", "color: red");
/* toggling the execution of this whole script */
if(toggle_script_execution && 'ff_set' in window) {
window.ff_set = !window.ff_set;
if(window.ff_set) start_alert();
} else if(!('ff_set' in window)) {
window.ff_set = true;
start_alert();
}
if(!window.ff_set) {
if(toggle_script_execution) stop_alert();
return;
}
/* time to wait for the video to load before moving to the end of the video */
const VIDEO_LOAD_TIME = 9000;
/* the duration to watch the video, for it to be considered 'watched', before moving to the next item in the course */
const VIDEO_WATCH_TIME = 3000;
/* the duration to read the article, for it to be considered 'read', before moving to the next item in the course */
const ARTICLE_READ_TIME = 12000;
/* time to wait for the exercise(non-lecture) to load before moving to the next item in the course */
const EXERCISE_LOAD_TIME = 3000;
function goToNextItem(is_gotoNext_button_available = true) {
if (!window.ff_set) return;
if(is_gotoNext_button_available) {
document.getElementById('go-to-next-item')?.click();
forwarder();
} else {
setTimeout(() => {
document.querySelector('[data-purpose="go-to-next"].item-link')?.click();
forwarder();
}, EXERCISE_LOAD_TIME);
}
}
function getCurrentItem(){
const get_li = () => document.querySelector('li[class*="curriculum-item-link--is-current"]');
const fix1 = () => document.querySelector('div[data-purpose="curriculum-section-container"]')?.querySelectorAll('.ud-accordion-panel-toggler').forEach(x => x.click());
const fix2 = () => document.querySelector('button[class*="course-content-toggle"].ud-heading-md')?.click();
let li = get_li();
if(li) return li;
/* else */
fix1();
li = get_li();
if(li) return li;
/* else */
fix2();
li = get_li();
if(li) return li;
/* else */
fix1();
li = get_li();
return li;
}
const currentItem = getCurrentItem();
const icon_element = currentItem.firstElementChild.lastElementChild.lastElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild;
const icon_type = icon_element.getAttribute('xlink:href');
const current_element_is_completed = currentItem.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.checked;
const current_element_is_not_a_lecture = !icon_type && icon_element?.nodeName.toUpperCase() == 'SPAN';
if(current_element_is_completed || current_element_is_not_a_lecture) {
goToNextItem(!current_element_is_not_a_lecture);
return;
}
if(icon_type.endsWith('video')){
setTimeout(() => {
if (!window.ff_set) return;
let video = document.querySelector('video');
if(video.paused) video.play();
const video_time = "0:" + document.querySelector('span[data-purpose="duration"]').textContent;
const last_second_of_the_video = video_time.split(":").slice(-3).map(Number).reverse().reduce((t, x, i) => t + x * Math.pow(60, i), 0);
video.currentTime = last_second_of_the_video - (VIDEO_WATCH_TIME + 2000) / 1000;
console.log('video-item forwarded at:', last_second_of_the_video + "s");
}, VIDEO_LOAD_TIME);
setTimeout(goToNextItem, VIDEO_LOAD_TIME + VIDEO_WATCH_TIME);
} else {
setTimeout(goToNextItem, ARTICLE_READ_TIME);
}
})(true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment