NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==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(); } } })();