YouTube Speeder

Finer control of youtube playback speed.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name     YouTube Speeder
// @version  1
// @author   Thertzlor
// @description  Finer control of youtube playback speed.
// @grant    none
// @include  https://www.youtube.com/*
// @namespace https://greasyfork.org/users/817301
// ==/UserScript==

var wait = setInterval(function(){
  var player = document.getElementById("movie_player");
  if(!player) return;
  clearInterval(wait);
  var display = player.appendChild(document.createElement("div"));
  display.style.opacity="0";
  display.style.background="black";
  display.style.position= "absolute";
  display.style.right="2%";
  display.style.bottom ="10%";
  display.style.padding='5px';
  display.style.zIndex ="2999999999"
  display.style.transition="opacity 0.3s ease-in"
  var config = JSON.parse(localStorage.getItem('yt-speed')||"{}");
  var vid =  document.getElementsByTagName("video")[0];
  var currentTime = document.getElementsByClassName("ytp-time-current")[0]
  var duration = document.getElementsByClassName("ytp-time-duration")[0]
  var videoRate = config.rate||1
  var interval = config.interval || .05;
  var currentRate;
  var textTimer;
  var speeding= false;
  if (config.rate !== 1) speeder(0)

  setInterval(function(){
    if(vid.playbackRate !== config.rate) vid.playbackRate = config.rate;
  },300)


  function fancyTimeFormat(time){
    time = Math.round(time)
    var hrs = ~~(time / 3600);
    var mins = ~~((time % 3600) / 60);
    var secs = ~~time % 60;
    var ret = "";
    if (hrs > 0) ret += "" + hrs + ":" + (mins < 10 ? "0" : "");
    ret += "" + mins + ":" + (secs < 10 ? "0" : "");
    ret += "" + secs;
    return ret;
  }

  function displayTime(){
    speeding = true;
    if(currentRate == 1) return void (duration.innerHTML=duration.innerHTML.split(" ")[0])
    var durationArray = duration.innerHTML.split(" ")[0].split(":");
    var originalDuration = (durationArray.length == 3)? ((parseInt(durationArray[0])*60*60) + (parseInt(durationArray[1])*60) + parseInt(durationArray[2])) : ((parseInt(durationArray[0])*60)+parseInt(durationArray[1])) ;
    var cur = currentTime.innerHTML.split(":");
    var originalRate = (cur.length == 3)? ((parseInt(cur[0])*60*60) + (parseInt(cur[1])*60) + parseInt(cur[2])) : ((parseInt(cur[0])*60)+parseInt(cur[1])) ;
    var newDuration = fancyTimeFormat(originalDuration/currentRate)
    var newRate = fancyTimeFormat(originalRate/currentRate)
    duration.innerHTML = duration.innerHTML.split(" ")[0]+" ("+newRate+" / "+newDuration+")";
  }

  function showText(text){
    display.innerHTML = text
    display.style.opacity=".8";
    clearInterval(textTimer);
    textTimer = window.setTimeout(function(){display.style.opacity="0";},800)
  }

  document.getElementsByClassName('ytp-settings-menu')[0].addEventListener('click', function(){
    if(vid.playbackRate !== currentRate){
      config.rate = vid.playbackRate;
      currentRate = vid.playbackRate;
      if(speeding === false) setInterval(function(){displayTime()},1000)
    }
  })

  function speeder(rate){
    videoRate += rate;
    currentRate = rate? Math.round(videoRate*1000)/1000 : videoRate;
    vid.playbackRate = currentRate
    config.rate = currentRate
    showText(currentRate.toString(10))
    localStorage.setItem('yt-speed', JSON.stringify(config));
    if(speeding === false) setInterval(function(){displayTime()},1000)
  }

  document.body.addEventListener("keydown",function(e){
    if((!e.altKey) || !(e.code === 'ArrowUp' || e.code === 'ArrowDown')) return
    if(e.shiftKey){
      interval += .05*(e.code === 'ArrowUp'?1:-1);
      interval = Math.max(Math.round(interval * 100)/100,0)
      config.interval = interval
      showText('set interval to '+interval)
      localStorage.setItem('yt-speed', JSON.stringify(config));
    } else speeder(interval * (e.code === 'ArrowUp'?1:-1));
  })

},20)