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();
}
}
})();