// ==UserScript== // @name Youtube Extended Controls // @namespace https://greasyfork.org/de/scripts/xxx // @version 0.1 // @description Adding keyboard shortcuts for cycling playback speed setting and looping a specific time span // @author Guitar Hero // @grant none // @include https://youtube.com/watch* // @include https://www.youtube.com/watch* // @downloadURL none // ==/UserScript== (function() { control = { setup: { init: function() { console.log("init"); control.setup.enableLoopButton(); control.setup.enableSpeedButton(); // registrateOnLocationChange(); document.addEventListener("keydown", control.setup.keyWatcher, false); }, registrateShortcut: function(key, functionToCall) { console.log("registering function for key: " + key); control.keyToFunctionMap[key.charCodeAt(0)] = functionToCall; }, keyWatcher: function(e) { console.log("key pressed!"); //check if video or "nothing" is focussed (to exclude text fields) if (document.activeElement.id != "" && document.activeElement.id != "movie_player") { console.log("not the right focus"); return; } if (!e) { e = window.event; } control.callFunctionByKey(e.keyCode); }, registrateOnLocationChange: function() { var pushState = history.pushState; history.pushState = function () { var changedUrl = arguments[2]; pushState.apply(history, arguments); control.setup.init(); } }, enableLoopButton: function() { try { control.setup.registrateShortcut("A", control.loop.handler); } catch(ex) { console.log("error enabling loop button: " + ex); } }, enableSpeedButton: function() { try { control.speed.speedSet = control.video.playbackRate; control.setup.registrateShortcut("S", control.speed.handler); } catch(ex) { console.log("error enabling speed button: " + ex); } } }, keyToFunctionMap: {}, video: document.querySelector('.html5-main-video'), speed: { availableSpeeds: [1, 0.75, 0.5, 0.25, 0.1], speedSet: -1, handler: function() { var index = control.speed.availableSpeeds.indexOf(control.speed.speedSet); index = ++index % control.speed.availableSpeeds.length; control.speed.setSpeed(control.speed.availableSpeeds[index]); }, setSpeed: function(speed) { control.speed.speedSet = speed; control.video.playbackRate = speed; } }, loop: { begin: null, end: null, active: false, reset: function() { control.loop.begin = null; control.loop.end = null; control.loop.active = false; }, worker: function() { console.log("loop worker"); if (control.loop.active == false) { console.log("loop worker not active, exiting"); return; } if (control.video.getCurrentTime() > control.loop.end) { console.log("loop worker - set to beginning"); control.jumpToPosition(control.loop.begin); } console.log("loop worker - setting timeout"); setTimeout(control.loop.worker, 100); }, handler: function() { //set loop begin if (control.loop.begin == null) { console.log("setting loop begin"); control.loop.begin = control.video.getCurrentTime(); return; } //set loop end if (control.loop.end == null) { console.log("setting loop end"); control.loop.end = control.video.getCurrentTime(); control.loop.active = true; control.jumpToPosition(control.loop.begin); //activate loopWorker which sets back time setTimeout(control.loop.worker, 100); return; } //button pressed a third time -> deactivating loop console.log("resetting loop"); control.loop.reset(); } }, callFunctionByKey: function(key) { console.log("call function by key"); if (control.keyToFunctionMap[key]==null) { return; } control.keyToFunctionMap[key](); }, jumpToPosition: function(time) { console.log("jumping to " + time); control.video.currentTime = time; } }; control.setup.init(); })();