// ==UserScript==
// @name Youtube Teater
// @namespace http://tampermonkey.net/
// @version 1.0
// @license MIT
// @description New Look For Youtube!
// @run-at document-idle
// @author You
// @match https://www.youtube.com/watch?*
// @grant none
// ==/UserScript==
class YoutubeVideo {
constructor(id, title, imgUrl) {
this.id = id;
this.title = title;
this.image = new Image();
this.image.src = imgUrl;
}
set id(value) {
this._id = value;
}
get id() {
return this._id;
}
set title(value) {
this._title = value;
}
get title() {
return this._title;
}
set image(value) {
if (value instanceof Image) this._image = value;
}
get image() {
return this._image;
}
}
//////////////////////////////////////////////////////////////////////////////
// Library
//////////////////////////////////////////////////////////////////////////////
function elem(tag, ...args) {
if (typeof tag !== 'string') return;
let [e, id, ...classes] = [document.createElement(tag), ...args];
if (id) e.id = id;
if (classes) e.setAttribute('class', classes.reduce((a, b) => a + " " + b, ""));
return e;
}
function div(...args) {
return elem('div', ...args);
}
function ul(...args) {
return elem('ul', ...args);
}
function li(...args) {
return elem('li', ...args);
}
function a(...args) {
return elem('a', ...args);
}
//////////////////////////////////////////////////////////////////////////////
// Stuff
//////////////////////////////////////////////////////////////////////////////
async function load(url) {
let res = await fetch(url);
return await res.text();
}
function getVideos(source) {
return Promise.all(source.match(/(?<="compactVideoRenderer":{"videoId":").*?(?="},"longBylineText")/g));
}
function getData(matches) {
let map = new Map;
matches.forEach((m, i) => {
m = m.replace(/\\u0026/g, "&");
let id = m.split("\",\"")[0];
let title = m.match(/(?<="simpleText":").+/g)[0];
let thumbnail = m.match(/(?<="url":")https.+?(?=")/g)[1];
// if(i===0) console.log(m);
map.set(id, new YoutubeVideo(id, title, thumbnail));
});
return Promise.resolve(map);
}
function renderSuggestedVideos(container) {
return function (videos) {
videos.forEach(video => {
let list = li(null, 'video-list');
container.appendChild(list);
// Clickable Link
let videoLink = a(null, 'video-link');
videoLink.href = `watch?v=${video.id}`;
list.appendChild(videoLink);
let holder = div(null, 'video-list-grid');
videoLink.appendChild(holder);
// Video Image
let image = video.image;
image.setAttribute('class', 'video-thumbnail');
holder.appendChild(image);
// Video Title
let divTitle = div(null, 'video-desc');
divTitle.innerText = video.title;
holder.appendChild(divTitle);
});
}
}
//////////////////////////////////////////////////////////////////////////////
// Main Stuff //
//////////////////////////////////////////////////////////////////////////////
let showControlsTimer;
let nextVideoTimer;
let frameHeight = 360 + 26;
let frameWidth = 640 + 26;
let style1 = `
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 18px 0px;
}
div.video-frame {
width: 680px;
height: 480px;
background-image: url(https://az414406.vo.msecnd.net/img2/tv-transparent.svg);
background-size: cover;
}
video {
position: relative;
top: 14px;
left: 13px;
width: 655px;
height: 409px;
background-color: #2C3F4F;
}
ul.video-list {
list-style: none;
display: inline-grid;
}
ul.video-list li {
line-height: 110px;
margin: 10px 0px;
}
a > *.video-list-grid {
display: grid;
grid-template-areas: "thumbnail desc";
}
img.video-thumbnail {
width: 196px;
height: 110px;
border-radius: 10px;
}
div.video-desc {
font-size: 22px;
padding-left: 20px;
padding: 10px;
}
form#vsearch {
width: 100%;
margin: 10px auto;
text-align: center;
}
form#vsearch input{
padding: 8px;
font-size: 16px;
border-radius: 8px;
}
form#vsearch > input[name=q]{
width: 60%;
}
div.toggle-button-container {
display: flex;
flex-direction: row;
align-items: center;
}
div.toggle-button {
width: 100px;
height: 30px;
border: 1px solid #9e9e9;
border-radius: 30px;
background-color: #dedede;
padding: 5px;
margin-left: 30px;
transition: all 0.4s;
}
div.toggle-button.slider {
width: 40px;
height: 40px;
background-color: gray;
position: relative;
top: -10px;
left: -10px;
margin: 0px;
}
div.toggle-button.slider[toggled] {
width: 40px;
height: 40px;
background-color: blue;
position: relative;
top: -10px;
left: 60px;
margin: 0px;
}
`;
(async function () {
'use strict';
let textDuration = document.body.innerHTML.substring(document.body.innerHTML.indexOf("ytp-time-duration") + 19).split("<")[0]; //document.body.innerHTML.substring(document.body.innerHTML.indexOf("duration=")).split(" ")[0].split("=")[1].replace(/\"/g,"");
for (let prop in window) {
if (typeof window[prop] === 'function') {
clearInterval(window[prop]);
}
}
let title = document.querySelector('title').innerText;
let video = document.querySelector('video');
video.removeAttribute('class');
video.removeAttribute('style');
video.controlsList.toggle('nodownload');
video.download = true;
let update = function () {
if (!video.webkitDisplayingFullscreen) {
video.controls = true;
video.removeAttribute('controlslist');
video.removeAttribute('tabindex');
video.removeAttribute('style');
}
requestAnimationFrame(update);
}
showControlsTimer = setTimeout(update, 100);
let source = await load(window.location);
document.querySelector('html').style = '';
document.head.innerHTML = `<title>${title}</title>`;
document.body.innerHTML = `<style>${style1}</style><div class="wrapper">
<form id="vsearch" action="results?">
<input name="q" type="text" placeholder="Search Youtube Videos"/>
<input type="submit" value="Search"/>
</form>
<div class="video-frame">
</div>
<div id="autoplay" class="toggle-button-container">
<span>Autoplay</span>
<div class="toggle-button">
<div class="toggle-button slider"></div>
</div>
</div>
<table class="list"><tbody></tbody></table></div>`;
let wrapper = document.querySelector('.wrapper');
let container = wrapper.querySelector('.video-frame');
container.appendChild(video);
video.play();
// Video List Stuff
const videoListHolder = div();
wrapper.appendChild(videoListHolder);
const videoList = ul(null, 'video-list');
videoListHolder.appendChild(videoList);
let nextVideo = null;
getVideos(source).then(getData).then(videos => {
renderSuggestedVideos(videoList)(videos);
nextVideo = videos.entries().next().value[1];
});
let time = textDuration.split(/:/g);
let s = time.map(t => parseInt(t)).reduce((a, b, i, arr) => a + b * Math.pow(60, arr.length - i - 1), 0);
let ignoredTime = isNaN(s);
console.log(`Text Time: ${textDuration}, Time: ${time.reduce((a,b)=>a+":"+b)}, Video Length: ${s} seconds`);
// Autoplay next video
let checkForNextVideo = function () {
let duration = video.getDuration() | 0 + 1;
if (ignoredTime || Math.abs(duration - s) > 1) return;
if (video.getDuration() - video.getCurrentTime() < 0.01) {
if (typeof nextVideo !== 'undefined') {
let a = document.createElement("a");
a.href = `watch?v=${nextVideo.id}`;
a.click();
}
}
}
document.querySelectorAll("div.toggle-button-container").forEach(container => {
let toggle_button = container.querySelector("div.toggle-button.slider");
container.addEventListener("click", function (event) {
if (toggle_button.hasAttribute("toggled")) {
toggle_button.removeAttribute("toggled");
localStorage.setItem("autoplay", "0");
try {
toggle_button.onuntoggled(event);
}
catch (e) {}
}
else {
toggle_button.setAttribute("toggled", "");
localStorage.setItem("autoplay", "1");
try {
toggle_button.ontoggled(event);
}
catch (e) {}
}
});
toggle_button.ontoggled = function (e) {
nextVideoTimer = setInterval(checkForNextVideo, 100);
}
toggle_button.onuntoggled = function (e) {
clearInterval(nextVideoTimer);
}
});
// Setup autoplay and its toggle button to match localStorage if it exists
let autoplay = localStorage.getItem("autoplay");
if (autoplay !== null) {
let toggle_button = document.querySelector("div#autoplay div.toggle-button.slider");
try {
if (autoplay === "1") {
toggle_button.setAttribute("toggled", "");
localStorage.setItem("autoplay", "1");
try {
toggle_button.ontoggled(event);
}
catch (e) {}
}
else if (autoplay === "0") {
toggle_button.removeAttribute("toggled");
localStorage.setItem("autoplay", "0");
try {
toggle_button.onuntoggled(event);
}
catch (e) {}
}
}
catch (e) {}
}
else {
localStorage.setItem("autoplay", "0");
}
})();
Donate for the site OpenUserJS
Are you sure you want to go to an external site to donate a monetary value?
WARNING: Some countries laws may supersede the payment processors policy such as the GDPR and PayPal. While it is highly appreciated to donate, please check with your countries privacy and identity laws regarding privacy of information first. Use at your utmost discretion.