Greasy Fork is available in English.

9gag show video control

add video controls to 9gag gif and video post. Add volume slider on chrome browser

// ==UserScript==
// @name         9gag show video control
// @namespace    http://javalatte.xyz 
// @version      1.5.2
// @description  add video controls to 9gag gif and video post. Add volume slider on chrome browser
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @author       Akzn
// @match        https://9gag.com/*
// ==/UserScript==

'use strict';
var timer;
var isChrome = !!window.chrome && !!window.chrome.webstore;
var isFirefox = (navigator.userAgent.indexOf("Firefox") != -1)? true : false;

//--- CSS styles
//--- Button autoplay
GM_addStyle (".gmPersistentButton {background: var(--palette-primary);position: fixed;bottom: 1em;right: 1em;z-index: 6666;border-radius: 18px;}.gmPersistentButton button {cursor: pointer;background: var(--palette-primary);color: white;font-size: 14px;font-style: normal;font-weight: 700;line-height: 20px;letter-spacing: 0em;bottom: 1em;right: 1em;z-index: 6666;padding: 1em;border: var(--palette-primary);border-radius: 18px;opacity: 0.8;}.gmPersistentButton:hover, .gmPersistentButton button:hover {background-color: var(--palette-primary-hover);}");

// Slider for chrome
if(isChrome==true){
    GM_addStyle (".div-slider {opacity: 0;text-align: center;padding-top: 5px;width: 29px;height: 120px;position: absolute;bottom: 50px;right: 24px;cursor: pointer;z-index: 99999;border-radius: 15px;background-color: rgba(0, 0, 0, 0.8);}");
    GM_addStyle(".volume-slider{-webkit-appearance: slider-vertical;width: 30px;height: 160px;position: absolute;top: 12px;right: 0px;cursor: pointer;z-index: 99999;height: 100px;width: 2px;margin: auto 13px;}");
 }

//--- Add the button.
$("body").append (
    '<div class="gmPersistentButton">'
  + '<button id="gmAutoplayVideoBtn">Init failed!</button></div>'
);

//--- Define and init the matching control object:
var btnControl  = new PersistentButton (
  "gmAutoplayVideoBtn",        //-- HTML id
  "StopContinueBtn",      //-- Storage label
  ["Autoplay Video : Off", "Autoplay Video : On"],   //-- Text that the button cycles through
  [false, true]           //-- Matching values for the button's states
);

//--- Activate the button click-handler.
$("#gmAutoplayVideoBtn").click ( function () {
    btnControl.SetNextValue ();
    var btnValue    = this.value;
    keepgoing       = btnValue
    
    _handlegmAutoplayVideoBtnClick(keepgoing)
} );

//--- Button object
function PersistentButton (htmlID, setValName, textArry, valueArry) {
  //--- Initialize the button to last stored value or default.
  var buttonValue     = valueArry[0];
  fetchValue ();
  storeValue ();      //-- Store, in case it wasn't already.
  setButtonTextAndVal ();

  //--- DONE with init.  Set click and keyboard listeners externally.

  //***** Public functions:
  this.Reset          = function () {
      buttonValue     = valueArry[0];
      storeValue ();
      setButtonTextAndVal ();
  };

  this.SetNextValue   = function () {
      var numValues   = valueArry.length;
      var valIndex    = 0;

      for (var J = numValues - 1;  J >= 0;  --J) {
          if (buttonValue == valueArry[J]) {
              valIndex    = J;
              break;
          }
      }
      valIndex++;
      if (valIndex >= numValues)
          valIndex    = 0;

      buttonValue     = valueArry[valIndex];

      storeValue ();
      setButtonTextAndVal ();
  };


  //***** Private functions:
  function fetchValue () {
      buttonValue     = GM_getValue (setValName, buttonValue);
  }

  function storeValue () {
      GM_setValue (setValName, buttonValue);
  }

  function setButtonTextAndVal () {
      var buttonText  = "*ERROR!*";

      for (var J = valueArry.length - 1;  J >= 0;  --J) {
          if (buttonValue == valueArry[J]) {
              buttonText  = textArry[J];
              break;
          }
      }

      var theBtn      = document.getElementById (htmlID);
      if (theBtn) {
          theBtn.textContent  = buttonText;
          theBtn.setAttribute ("value", buttonValue);
      }
      else
          alert ('Missing persistent button with ID: ' + htmlID + '!');
  }
}

//--- Video control
function addVideoControl(){
    var vids = document.getElementsByTagName('video');
    for( var i = 0; i < vids.length; i++ ){           
        var elem = vids.item(i);
        elem.setAttribute("preload","none")

        if(!elem.hasAttribute("controls")){
            //--- bind play button
            $(elem).bind('play', function (e) {
                isViewable = isElementXPercentInViewport(e.target,90)
                if (isViewable) {
                    e.target.setAttribute('pause','false')
                }
            });
            $(elem).bind('pause', function (e) {
                e.target.setAttribute('pause','true')
            });

            elem.setAttribute("controls", "");            
            elem.volume = 0.5;

            setVideoPlay(elem)

            // console.log('video controls added');
            
            //add volume slider to chrome video. Why tf chrome dev removed their dafault slider
            if((elem.parentNode.parentNode.getElementsByClassName('video-post').length>0) && (isChrome == true)){
                var slider = document.createElement("div");
                slider.setAttribute("class",'div-slider');

                slider.innerHTML = '<input id="vol-control" class="volume-slider" type="range" min="0" max="1" step="0.1"></input>';

                elem.parentNode.insertBefore(slider, elem.parentNode.parentNode.nextSibling);

                var nSlider = elem.parentNode.parentNode.parentNode.getElementsByTagName('input');
                nSlider[0].addEventListener("input",setVolume,false);
                nSlider[0].addEventListener("change",setVolume,false);
                nSlider[0].elem = elem;
                nSlider[0].value = elem.volume;


                elem.slider = nSlider[0];
                elem.addEventListener("mouseover",sliderIn,false);
                elem.addEventListener("mouseout",sliderOut,false);

                nSlider[0].slider = nSlider[0];
                nSlider[0].addEventListener("mouseover",sliderIn,false);
                nSlider[0].addEventListener("mouseout",sliderOut,false);
            }
        }

        if ($("#gmAutoplayVideoBtn").val() == "false") {
            // to handle 9gag very own autoplay js
            if(elem.getAttribute("pause")=='true'){
                elem.pause();
            } 
        }

        elem.addEventListener("click",handlePauseElem,false)
        if(elem.parentNode.querySelector('.presenting')){
            elem.parentNode.querySelector('.presenting').addEventListener("click",handlePausePlayButton,false)
        }
        if(elem.parentNode.parentNode.querySelector('.video-post')){
            elem.parentNode.parentNode.querySelector('.video-post').addEventListener("click",handlePauseBox,false)
        }

        if(elem.parentNode.parentNode.querySelector('.gif-post')){
            elem.parentNode.parentNode.querySelector('.gif-post').addEventListener("click",handlePauseBox,false)
        }

    }
}

function sliderIn(evt){
    evt.target.slider.parentNode.style.opacity = 1;
}

function sliderOut(evt){
    evt.target.slider.parentNode.style.opacity = 0;
}

function setVolume(evt){
    var elem = evt.target.elem;
    elem.volume = evt.target.value;
    elem.muted = false;
}

function handlePauseBox(evt){
    var elem = evt.target;
    setVideoPlay(elem.getElementsByTagName('video')[0])
}

function handlePausePlayButton(evt){
    var elem = evt.target;
    setVideoPlay(elem.parentNode.parentNode.getElementsByTagName('video')[0])
}

function handlePauseElem(evt){
    var elem = evt.target;
    setVideoPlay(elem)
}

function setVideoPlay(elem,buttonStorageValue = null){
    if (buttonStorageValue == null) {
        if ($("#gmAutoplayVideoBtn").val() == "true") {
            elem.setAttribute("pause", "false");
        } else {
            if(elem.getAttribute("pause")=='true'){
                elem.setAttribute("pause", "false");
            } else {
                elem.setAttribute("pause", "true");
            }
        }
    } else {
        if (buttonStorageValue == 'false') {
            elem.setAttribute("pause", "true");
            elem.pause()
        } else if(buttonStorageValue == 'true'){
            elem.setAttribute("pause", "false");
            elem.play()
        }
    }
    
}

// TO check viewbility
const isElementXPercentInViewport = function(el, percentVisible) {
    let
      rect = el.getBoundingClientRect(),
      windowHeight = (window.innerHeight || document.documentElement.clientHeight);
  
    return !(
      Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-rect.height) * 100)) < percentVisible ||
      Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
    )
};

// handle toggle autoplay
function _handlegmAutoplayVideoBtnClick(value){
    var vids = document.getElementsByTagName('video');
    for( var i = 0; i < vids.length; i++ ){           
        var elem = vids.item(i);
        setVideoPlay(elem,value)
    }
    console.log('autoplay : '+value)
}

timer = setInterval(addVideoControl, 300);