// ==UserScript==
// @name ViewXtend
// @description Youtube with extra features
// @icon None
// @version 1.0.2
// @author Fate (https://github.com/FateNotAvailable)
// @namespace https://github.com/FateNotAvailable/ViewXtend
// @supportURL https://github.com/FateNotAvailable/ViewXtend/issues
// @license GPL-3
// @icon https://i.ibb.co/cwvhZQN/View-Xtend.png
// @match https://www.youtube.com/*
// @match https://www.youtube-nocookie.com/*
// @match https://m.youtube.com/*
// @grant none
// @run-at document-start
// @compatible chrome
// @compatible firefox
// @compatible opera
// @compatible edge
// @compatible safari
// @downloadURL https://update.greasyfork.icu/scripts/474406/ViewXtend.user.js
// @updateURL https://update.greasyfork.icu/scripts/474406/ViewXtend.meta.js
// ==/UserScript==
/******/ (() => { // webpackBootstrap
/******/ "use strict";
var __webpack_exports__ = {};
;// CONCATENATED MODULE: ./src/api/ViewXtend.js
class ViewXtendAPI {
constructor () {
}
waitForElementBy(by, selector, timeout) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
function checkElement() {
let element;
if (by == "q") {
element = document.querySelector(selector);
}
else if (by == "t") {
element = document.getElementsByTagName(selector);
}
if (element) {
resolve(element);
} else if (Date.now() - startTime >= timeout) {
reject(new Error(`Element '${selector}' not found within ${timeout}ms`));
} else {
setTimeout(checkElement, 100); // Check again in 100ms
}
}
checkElement();
});
}
waitForElementNotHidden(selector, timeout) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
function checkElement() {
let element = document.querySelector(selector);
if (element) {
if (element.style.display != 'none') {
resolve(element);
}
else {
setTimeout(checkElement, 100); // Check again in 100ms
}
} else if (Date.now() - startTime >= timeout) {
reject(new Error(`Element '${selector}' not found within ${timeout}ms`));
} else {
setTimeout(checkElement, 100); // Check again in 100ms
}
}
checkElement();
});
}
get_player() {
/**
* Gets video player element
*/
return this.waitForElementBy("q", "#movie_player > div.html5-video-container > video", 25000);
}
get_logo() {
/**
* Gets youtube logo
*/
return this.waitForElementBy("q", "#logo-icon > yt-icon-shape > icon-shape > div > svg", 25000)
}
get_videos() {
/**
* Gets videos as html tags
*/
//return this.waitForElementBy("t", "ytd-rich-grid-media", 25000);
return document.getElementsByTagName("ytd-rich-grid-media");
}
get_fake_videos() {
/**
* Get ads that look like videos
*/
//return this.waitForElementBy("t", "ytd-ad-slot-renderer", 25000);
return document.getElementsByTagName("ytd-ad-slot-renderer");
}
set_title(title) {
/**
* Set page title
*/
document.title = title
}
get_title() {
/**
* Get page title
*/
return document.title
}
get_video_download_button() {
return this.waitForElementBy("q", "#action-button > yt-button-shape > button > div > span", 25000)
}
get_download_dialog() {
return this.waitForElementNotHidden("body > ytd-app > ytd-popup-container > tp-yt-paper-dialog", 25000)
}
get_download_options() {
return new Promise((resolve, reject) => {
const startTime = Date.now();
function checkElement() {
let element = document.querySelector("#premium-options");
if (element) {
return resolve(element.childNodes);
} else if (Date.now() - startTime >= timeout) {
reject(new Error(`Element '${selector}' not found within ${timeout}ms`));
} else {
setTimeout(checkElement, 100); // Check again in 100ms
}
}
checkElement();
});
}
get_checked_download() {
let pr = document.querySelectorAll('paper-ripple');
for (let i = 0; i < pr.length; i++) {
if (pr[i].getAttributeNames().includes("checked")) {
return pr[i]
}
}
return null;
}
create_plugins_button() {
const f = document.createElement("ytd-compact-link-renderer");
f.setAttribute("injected", "true")
f.className = "style-scope yt-multi-page-menu-section-renderer"
f.setAttribute("compact-link-style", "")
f.setAttribute("hide-secondary-string", "")
f.onclick = () => {
window.location.href = '/plugins';
}
f.innerHTML = `