NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name i-Achelois.videoPlayer // @namespace https://zaw.li // @version 0.1 // @description Adds a variable speed slider into the (i-)NTULearn recorded lectures // @author Lit3Nitride // @homepage https://github.com/Lit3Nitride/i-Achelois // @license GPL-3.0+; http://www.gnu.org/licenses/gpl-3.0.txt // @match https://*.ntu.edu.sg/aculearn* // @grant none // ==/UserScript== (function() { 'use strict'; // Set up the variables. // // btn // is one of the radio buttons that we'll // keep and use to actually change the speed // // slider // is the volume slider we'll insert // // sliderNum // is the text box that displays the current speed // // sliderText // is the rounded speed multiplied by 100 // so that we can display 2 decimal places var btn, slider, sliderNum, sliderText // This is the function that keeps checking // for the video player to be loaded before // starting the script proper (function load() { btn = document.getElementById("mep_0_rate_25") if (btn === null) setTimeout(load, 100) else init() })() // Setup of the rest of the script once the video player is loaded function init() { // Remove the annoying thumbnail nonsense document.getElementById("div_index").parentNode.removeChild(document.getElementById("div_index")) // The container of all the speed selectors var rateSelect = document.getElementsByClassName("mejs-rate-selector")[0] // Resize the container since we now need only to fit the slider rateSelect.style["height"] = "25px" rateSelect.style["width"] = "150px" rateSelect.style["margin-bottom"] = "-5px" // Make the first radio button invisible (without removing it) rateSelect.children[0].rows[0].style["display"] = "none" // Add in the slider and the current speed text box rateSelect.children[0].rows[1].innerHTML = '\ <td>\ <input type="range" min="52.5" max="200" value="100" id="btnSlider" step="any" style="width:80%;">\ </td>\ <td style="color: white">\ <span id="sliderNum">1.00</span>×\ </td>' // Assign the newly created elements into our pre-defined variables slider = document.getElementById("btnSlider") sliderNum = document.getElementById("sliderNum") // Remove the rest of the speed buttons for (var i=rateSelect.children[0].rows.length-1; i>1; i--) rateSelect.children[0].rows[i].remove() // Assign the trigger that handles speed change to changes of the slider rateSelect.children[0].rows[1].children[0].children[0].onmousedown = function() {trigger(true)} rateSelect.children[0].rows[1].children[0].children[0].onmouseup = trigger rateSelect.children[0].rows[1].children[0].children[0].onchange = trigger // Make the rate button a "reset" button (like how clicking on // the volume button mutes the video document.getElementsByClassName("mejs-rate-button")[0].children[0].onclick = function(){ slider.value = 100 doTrigger() } } // Precheck to see if the speed should be continually updated function trigger(triggerStart) { // Check if the mouse button is being held down // If so, keep updating the speed window.isTriggered = typeof triggerStart == "undefined" ? false:triggerStart setTimeout(doTrigger, 20) } // The actual changing of speed function doTrigger() { // We interpolate the slider so that // // 1. Have the values that correspond to the original speed buttons // f(2) -> 8.00 // f(1) -> 1.00 // f(?) -> 0.25 // // 2. Have |f'(1)| < f'(2) and f'(1) < f'( ? ) because when we are closer // to speed 1.00, we want to fine-tune it more, but when we are further // from 1.00, we just want the video to be really fast or really slow // so we want the slider to change more further from there // // A polynomial curve of order 3 centered about x=1 fits this description, // then we solve for the parameters btn.value = 7*(slider.value/100 - 1)**3+1 // Multiply the value by 100 and round it, which corresponds to 2 decimal places sliderText = Math.round(btn.value*100) // Print it out with the decimal point sliderNum.textContent = (sliderText < 100 ? 0:sliderText.toString().substr(0,1)) + "." + sliderText.toString().substr(sliderText >= 100) // Basically we've changed the value of the lone radio survivor into // the speed we want and click it btn.click() // Keep repeating if the mouse is still triggered if (window.isTriggered) setTimeout(doTrigger, 20) } })();