raingart / HTML5 video time jump

// ==UserScript==
// @name         HTML5 video time jump
// @namespace    html5-jump
// @version      0.5
// @description  hotkey duble "Ctrl"
// @author       raingart
// @include      http*://*
// @run-at       document-end
// @license      Apache-2.0
// ==/UserScript==
/*jshint esversion: 6 */

// skip is not iframe
//if (window.self === window.top) return;

(function() {

const sec_jump = 85;
let video;

document.addEventListener('play', captureActiveVideoElement, true);
document.addEventListener('playing', registerShortcutKeys, { capture: true, once: true });

function captureActiveVideoElement(evt) {
  video = evt.target;
}

function registerShortcutKeys(evt) {
  /*{ label: 'alt', value: 18 },
  { label: 'shift', value: 16 },
  { label: 'ctrl', value: 17, selected: true },*/
  doubleKeyPressListener(timeLeap.bind(video), 17);
}

function timeLeap() {
   let sec = Math.floor(sec_jump + this.currentTime);
   //console.debug('seekTo', sec);
   this.currentTime = sec;
   //showNotification(`${HMS_digit(sec)} (${sec_jump})`);
   showNotification(HMS_digit(sec));
}

/*
// Problems are possible if there are several video players on the page
waitElement('video')
  .then(v => {
    doubleKeyPressListener(timeLeap.bind(v), 17);
    video = v;
});

function waitElement(selector) {
  return new Promise(resolve => {
    if (document.querySelector(selector)) {
        return resolve(document.querySelector(selector));
    }

    const observer = new MutationObserver(mutations => {
        if (document.querySelector(selector)) {
            resolve(document.querySelector(selector));
            observer.disconnect();
        }
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
  });
}*/

function HMS_digit(ts = required()) { // format out "h:mm:ss"
   const
      sec = Math.abs(+ts),
      d = Math.floor(sec / 86400),
      h = Math.floor((sec % 86400) / 3600),
      m = Math.floor((sec % 3600) / 60),
      s = Math.floor(sec % 60);

   return (d ? `${d}d ` : '')
      + (h ? (d ? h.toString().padStart(2, '0') : h) + ':' : '')
      + (h ? m.toString().padStart(2, '0') : m) + ':'
      + s.toString().padStart(2, '0');
}

function doubleKeyPressListener(callback, keyCodeFilter) {
 let
    pressed,
    isDoublePress,
    lastPressed = keyCodeFilter;

 const
    timeOut = () => setTimeout(() => isDoublePress = false, 500),
    handleDoublePresss = key => {
       // console.debug(key.key, 'pressed two times');
       if (callback && typeof callback === 'function') return callback(key);
    };

 function keyPress(evt) {
    if (['TEXTAREA', 'SELECT'].includes(evt.target.tagName)
       || (evt.target.tagName == 'INPUT' && ['email', 'text', 'password', 'search', 'url'].includes(evt.target.getAttribute('type')))
       || evt.target.isContentEditable
       ) return;

    pressed = evt.keyCode;
    // console.debug('doubleKeyPressListener %s=>%s=%s', lastPressed, pressed, isDoublePress);
    if (isDoublePress && pressed === lastPressed) {
       isDoublePress = false;
       handleDoublePresss(evt);
    }
   else {
       isDoublePress = true;
       timeOut();
    }

    if (!keyCodeFilter) lastPressed = pressed;
 }
 document.addEventListener('keyup', keyPress);
}

function showNotification(text) {
  if (typeof this.fate === 'number') clearTimeout(fate);

  this.notification = (this.notification || (function () {
      const el = document.createElement('div');
      Object.assign(el.style, {
          position: 'fixed',
          top: '15px',
          left: '10px',
          'z-index': 99999,
          'background-color': 'rgba(0,0,0,.5)',
          padding: '8px 10px',
          'border-radius': '3px',
          'font-family': 'arial',
          'font-size': '1.8em',
          'font-weight': 'bold',
          color: '#fff',
      });
      return document.body.appendChild(el);
    })());
    this.notification.textContent = text;
    this.notification.style.opacity = 1;
    // this.notification.style.visibility = 'visible';

  this.fate = setTimeout(() => {
     this.notification.style.transition = 'opacity 200ms ease-in';
     this.notification.style.opacity = 0;
     // hud.style.visibility = 'hidden';
  }, 800); //total 1s = 800ms + 200ms(hud.style.transition)
}
})();