select / pr0-tv

// ==UserScript==
// @name         pr0-tv
// @namespace    http://github.com/select
// @version      0.3
// @description  Like TV but better
// @author       You
// @match        http*://pr0gramm.com/*
// @grant        none
// ==/UserScript==
const pr0tvLogoSVG = `
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   version="1.1"
   viewBox="0 0 186.73372 151.99557"
   height="151.99557"
   width="186.73372"
   id="pr0tv-logo">
  <metadata
     id="metadata4200">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <defs
     id="defs4198" />
  <g
     transform="matrix(4.4109743,0,0,4.4109743,0,69.114189)"
     id="g5061">
    <rect
       style="fill:#d23c22;fill-opacity:1"
       id="rect4192"
       rx="1.8545129"
       height="3.7090259"
       width="12.98159"
       y="2.1346347"
       x="13.908847" />
    <path
       style="fill:#d23c22;fill-opacity:1"
       id="path4194"
       d="M 2.7817694,1.5782802 C 3.5235746,0.83647504 4.450831,0.28012116 5.1926362,-0.46168401 6.1198927,-1.2034892 6.8616978,-1.9452944 7.7889543,-2.5016482 8.5307595,-3.2434534 9.2725646,-3.7998073 9.8289185,-4.3561612 9.2725646,-4.7270637 8.7162108,-5.2834176 7.7889543,-6.0252228 7.0471491,-6.767028 6.305344,-7.5088331 5.3780875,-8.2506383 4.450831,-8.9924435 3.7090259,-9.5487974 2.7817694,-10.290603 c -0.7418052,-0.741805 -1.4836103,-1.298159 -1.85451294,-1.669061 -0.55635387,-0.556354 -0.74180517,-1.112708 -0.74180517,-1.669062 0,-0.556354 0.1854513,-1.112708 0.55635388,-1.48361 0.37090263,-0.370903 0.74180513,-0.556354 1.29815903,-0.556354 0.3709026,0 0.5563539,0.185451 1.1127078,0.370903 0,0 0.3709026,0.370902 0.9272564,0.741805 0.5563539,0.556354 1.2981591,1.112707 2.0399643,1.854513 0.7418051,0.556354 1.4836103,1.298159 2.4108668,2.039964 0.9272564,0.741805 1.6690615,1.4836102 2.4108665,2.0399641 0.741805,0.5563539 1.483611,1.1127078 2.039965,1.6690616 0.556353,0.5563539 0.927256,0.7418052 1.112707,0.9272565 0.556354,0.5563539 0.741805,1.1127078 0.741805,1.8545129 0,0.5563539 -0.185451,1.1127078 -0.741805,1.6690617 -0.741805,0.5563538 -1.669061,1.298159 -2.596318,2.03996419 C 10.570724,0.28012116 9.6434672,1.2073776 8.5307595,1.9491828 7.603503,2.690988 6.6762465,3.6182444 5.5635388,4.3600496 4.6362823,5.1018548 3.8944772,5.84366 2.9672207,6.4000138 2.5963181,6.5854651 2.2254155,6.7709164 1.8545129,6.7709164 1.2981591,6.7709164 0.92725646,6.5854651 0.55635388,6.2145625 0.18545129,5.84366 0,5.4727574 0,4.9164035 0,4.3600496 0.18545129,3.8036957 0.55635388,3.2473419 1.1127078,2.690988 1.8545129,2.1346341 2.7817694,1.5782802 Z" />
    <path
       id="path4254"
       d="m 19.567825,6.9423124 a 1.038776,1.038776 0 0 0 -1.03612,1.0393469 l 0,9.3153927 a 1.038776,1.038776 0 0 0 1.03612,1.039347 l 1.817244,0 a 1.038776,1.038776 0 0 0 1.03612,-1.039347 l 0,-9.3153927 a 1.038776,1.038776 0 0 0 -1.03612,-1.0393469 l -1.817244,0 z"
       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:1000%;font-family:Roboto;-inkscape-font-specification:'Roboto Semi-Light';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:27.11286163px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d23c22;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25699532;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
    <path
       id="path4256"
       d="m 29.225362,2.2039204 c -0.710783,2.414e-4 -1.204241,0.7080291 -0.958652,1.375038 l 5.216104,14.0892876 c 0.148138,0.401463 0.530728,0.668112 0.958651,0.668153 l 1.646172,0 c 0.427925,-4.1e-5 0.810509,-0.26669 0.958653,-0.668153 L 42.268851,3.5821853 C 42.516895,2.9154471 42.024806,2.2055766 41.313426,2.2039204 l -2.033507,0 C 38.844624,2.2041602 38.457257,2.4801102 38.31481,2.8914386 L 35.258096,11.719436 32.214293,2.8914386 C 32.071846,2.4801108 31.684481,2.2041607 31.249186,2.2039204 Z"
       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:1000%;font-family:Roboto;-inkscape-font-specification:'Roboto Semi-Light';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:27.11286163px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d23c22;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.23662114;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
  </g>
</svg>

`;
(function() {
  'use strict';
  let nextVideoTimout;
  let isRunning = false;

  // prepare HTML Elements
  const overlayEl = document.createElement('div'); // overlay in which we place the videos
  overlayEl.className = 'tv-overlay';
  overlayEl.style.display = 'none';
  const overlayCountDownEl = document.createElement('div');
  overlayCountDownEl.className = 'loading';
  overlayCountDownEl.innerHTML = '... warten';
  overlayEl.appendChild(overlayCountDownEl);
  const controlEl = document.createElement('div');
  controlEl.className = 'tv-control';
  controlEl.innerHTML = `${pr0tvLogoSVG}`;
  controlEl.addEventListener('click', toggle);
  const styleEl = document.createElement('style');
  document.querySelector('head').appendChild(styleEl);
  const bodyEl = document.querySelector('body');
  bodyEl.insertBefore(overlayEl, bodyEl.firstChild);
  bodyEl.insertBefore(controlEl, bodyEl.firstChild);

  // set the CSS for the modal overlay in which we will move each video
  setCSS();
  // show the pr0-tv button? if no video is selected hide it
  testShowControl();
  // set the CSS again if the window resizes (going to fullscree, debugger, ...)
  window.onresize = setCSS;

  document.querySelector('body').addEventListener('click', testShowControl, true)
  document.addEventListener("keydown", (event) => {
    if (event.keyCode === 32 /*Space*/ ) {
      togglePauseVideo();
      event.preventDefault();
    }
    if (event.keyCode === 27 && isRunning/*Esc*/ ) {
      event.preventDefault();
      event.stopPropagation();
      exit();
      testShowControl();
    }
    if (event.keyCode === 80 /*P*/ ) {
      toggle();
    }
    if (isRunning && (event.keyCode === 37 /*left*/ || event.keyCode === 39 /*right*/ )) {
      console.log('left or right');
      nextOnFinish();
    }
  }, false);

  function testShowControl() {
    // since it's not possible to get the hash change event we need a timeout and then check the current URL
    setTimeout(() => {
      console.log('testShowControl!', window.location.pathname);
      if(/^\/top/.test(window.location.pathname)) controlEl.hidden = false;
      else controlEl.hidden = true;
    }, 250)
  }

  /**
   * ##exit
   * Stop pr0-tv and exit the fullscreen mode, move the video back into it's old parent
   */
  function exit() {
    exitFullscreen();
    clearTimeout(nextVideoTimout);
    var itemEl = document.querySelector('.item-container-content');
    const videoEl = document.querySelector('video');
    itemEl.insertBefore(videoEl.parentElement, itemEl.firstChild);
    // videoEl.pause();
    overlayEl.style.display = 'none';
    bodyEl.style.overflowY = '';
  }

  /**
   * ##toggle
   * Start or stop pr0-tv depending on it's previous state
   */
  function toggle() {
    if(/^\/top/.test(window.location.pathname)){
      if (!isRunning) {
        launchFullscreen(document.documentElement);
        nextOnFinish();
        overlayEl.style.display = '';
        bodyEl.style.overflowY = 'hidden'; // make scrollbar disappear
      } else {
        exit();
      }
      isRunning = !isRunning;
    }
    console.log('Pr0 TV running: ', isRunning);
  }

  /**
   * ##setCSS
   * Calculate values needed for and set the CSS for pr0-tv.
   * The size of the overlay modal has to be calculated.
   */
  function setCSS() {
    const viewportSize = getViewportSize();
    styleEl.innerHTML = `
    .icon-pr0-tv {
      font-size: 80px;
      display: flex;
      justify-content: center;
      align-items: center;
    }


    body { position: relative; }
    .tv-overlay {
      position: fixed;
      background-color: rgba(0,0,0,0.9);
      width: ${viewportSize.x}px;
      height: ${viewportSize.y}px;
      z-index: 99999990;
      display: flex;
      align-items: center;
      justify-content: center;
      top: 0;
      left: 0;
    }
    .tv-overlay video {
      width: ${viewportSize.x}px;
      height: ${viewportSize.y-3}px; /*so we can still see the progress bar*/
      pointer-events: none;
    }
    .tv-overlay .video-controls {
      width: 100%;
    }
    .tv-overlay h1 {
      font-size: 120px;
    }
    .tv-overlay div.video-controls {
      cursor: pointer;
    }
    .tv-overlay div.video-controls:hover div.video-position-bar-background {
      height: 8px;
      opacity: 0.8;
      transition: height 0.2s ease;
    }
    .tv-overlay div.video-controls:hover div.audio-controls, .tv-overlay div.video-controls:hover div.audio-volume-controls {
      opacity: 1;
      transition: opacity 0.2s ease;
    }
    .tv-overlay .loading {
      position: absolute;
      left: 50%;
      right: 50%;
      top: 50%;
      bottom: 50%;
      font-size: 22px;
      color: #d23c22;
      white-space: nowrap;
    }
    .tv-control {
      position: fixed;
      z-index: 99999991;
      top: 5px;
      right: 5px;
      border: 3px solid #d23c22;
      color: #CA4343;
      border-radius: 5px;
      width: 80px;
      height: 80px;
      background: rgba(0,0,0,0.3);
      padding: 3px 5px;
      cursor: pointer;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    #pr0tv-logo {
      width: 60px;
    }
    `;
  }

  /**
   * ##launchFullscreen
   * Code from https://davidwalsh.name/fullscreen
   * @param {HTMLElement} element ??
   */
  function launchFullscreen(element) {
    if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen();
    }
  }

  /**
   * ##exitFullscreen
   * Code from https://davidwalsh.name/fullscreen
   */
  function exitFullscreen() {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    } else if (document.mozCancelFullScreen) {
      document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen();
    }
  }

  /**
   * ##eventFire
   * Fire an event like click
   * Code from http://stackoverflow.com/a/2706236/1436151
   * @param {HTMLElement} el element on which the event should be triggered
   * @param {String} etype event type e.g. 'click'
   */
  function eventFire(el, etype) {
    if (el.fireEvent) {
      el.fireEvent('on' + etype);
    } else {
      const evObj = document.createEvent('Events');
      evObj.initEvent(etype, true, false);
      el.dispatchEvent(evObj);
    }
  }

  /**
   * ##clickNext
   * Trigger a click on the next item in stream button.
   * If there would be an open API we would not need this :P
   * Also start the checks and video ended event listening so we can start
   * the next video immediately.
   */
  function clickNext() {
    if (isRunning) {
      eventFire(document.querySelector('.stream-next'), 'click');
      nextOnFinish();
    }
  }

  /**
   * ##getViewportSize
   * Get the size of the current visible area.
   * Code from https://stackoverflow.com/a/11744120/1436151
   * @return {Object} viewport dimensions `{x: Number, y: Number}`
   */
  function getViewportSize() {
    var w = window,
      d = document,
      e = d.documentElement,
      g = d.getElementsByTagName('body')[0],
      x = w.innerWidth || e.clientWidth || g.clientWidth,
      y = w.innerHeight || e.clientHeight || g.clientHeight;
    return {x, y};
  }

  function nextOnFinish() {
    clearTimeout(nextVideoTimout);
    if ((overlayEl.children.length > 1) && isRunning) overlayEl.removeChild(overlayEl.lastChild);
    const videoEl = document.querySelector('video');
    if (videoEl) {
      overlayEl.appendChild(videoEl.parentElement);
      videoEl.removeAttribute('loop');
      videoEl.removeAttribute('style');
      videoEl.parentElement.querySelector('.video-controls').style.width = '';
      videoEl.addEventListener('ended', (event) => {
        nextVideoTimout = setTimeout(clickNext, 1000);
      }, false);
      videoEl.play();
    } else {
      // nextVideoTimout = setTimeout(clickNext, 3000);
      // countDown(3000);
      nextVideoTimout = setTimeout(clickNext, 10);
    }
  }

  function togglePauseVideo() {
    const videoEl = document.querySelector('video');
    if(videoEl) {
      if (videoEl.paused) videoEl.play();
      else videoEl.pause();
    }
  }


})();