// ==UserScript==
// @name YouTube Web Tweaks
// @version 4.1.8
// @description This script optimizes YouTube's performance by modified configs, shorts redirect and much more!
// @author Magma_Craft
// @license MIT
// @match *://www.youtube.com/*
// @namespace https://greasyfork.org/en/users/933798
// @icon https://www.youtube.com/favicon.ico
// @unwrap
// @run-at document-end
// @unwrap
// @grant none
// @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
// ==/UserScript==
// Enable strict mode to catch common coding mistakes
"use strict";
// Define the flags to assign to the EXPERIMENT_FLAGS object
const flagsToAssign = {
// Standard tweaks (YT config editor + Disable animations)
IS_TABLET: true,
DISABLE_YT_IMG_DELAY_LOADING: true,
polymer_verifiy_app_state: false,
desktop_delay_player_resizing: false,
web_animated_actions: false,
web_animated_like: false,
web_animated_like_lazy_load: false,
render_unicode_emojis_as_small_images: true,
smartimation_background: false,
kevlar_refresh_on_theme_change: false,
// Disable cinematics (aka ambient lighting)
kevlar_measure_ambient_mode_idle: false,
kevlar_watch_cinematics_invisible: false,
web_cinematic_theater_mode: false,
web_cinematic_fullscreen: false,
enable_cinematic_blur_desktop_loading: false,
kevlar_watch_cinematics: false,
web_cinematic_masthead: false,
web_watch_cinematics_preferred_reduced_motion_default_disabled: false
};
const updateFlags = () => {
// Check if the EXPERIMENT_FLAGS object exists in the window.yt.config_ property chain
const expFlags = window?.yt?.config_?.EXPERIMENT_FLAGS;
// If EXPERIMENT_FLAGS is not found, exit the function
if (!expFlags) return;
// Assign the defined flags to the EXPERIMENT_FLAGS object
Object.assign(expFlags, flagsToAssign);
};
// Create a MutationObserver that calls the updateFlags function when changes occur in the document's subtree
const mutationObserver = new MutationObserver(updateFlags);
mutationObserver.observe(document, { subtree: true, childList: true });
// Other adjustments to be tweaked (Re-adding Explore tab, redirecting shorts to watch, wtc...)
function waitForElm(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
function restoreTrending() {
var trendingData = {
"navigationEndpoint": {
"clickTrackingParams": "CBwQtSwYASITCNqYh-qO_fACFcoRrQYdP44D9Q==",
"commandMetadata": {
"webCommandMetadata": {
"url": "/feed/explore",
"webPageType": "WEB_PAGE_TYPE_BROWSE",
"rootVe": 6827,
"apiUrl": "/youtubei/v1/browse"
}
},
"browseEndpoint": {
"browseId": "FEtrending"
}
},
"icon": {
"iconType": "EXPLORE"
},
"trackingParams": "CBwQtSwYASITCNqYh-qO_fACFcoRrQYdP44D9Q==",
"formattedTitle": {
"simpleText": "Explore"
},
"accessibility": {
"accessibilityData": {
"label": "Explore"
}
},
"isPrimary": true
};
var guidetemplate = `<ytd-guide-entry-renderer class="style-scope ytd-guide-section-renderer" is-primary="" line-end-style="none"><!--css-build:shady--><a id="endpoint" class="yt-simple-endpoint style-scope ytd-guide-entry-renderer" tabindex="-1" role="tablist"><tp-yt-paper-item role="tab" class="style-scope ytd-guide-entry-renderer" tabindex="0" aria-disabled="false"><!--css-build:shady--><yt-icon class="guide-icon style-scope ytd-guide-entry-renderer" disable-upgrade=""></yt-icon><yt-img-shadow height="24" width="24" class="style-scope ytd-guide-entry-renderer" disable-upgrade=""></yt-img-shadow><yt-formatted-string class="title style-scope ytd-guide-entry-renderer"><!--css-build:shady--></yt-formatted-string><span class="guide-entry-count style-scope ytd-guide-entry-renderer"></span><yt-icon class="guide-entry-badge style-scope ytd-guide-entry-renderer" disable-upgrade=""></yt-icon><div id="newness-dot" class="style-scope ytd-guide-entry-renderer"></div></tp-yt-paper-item></a><yt-interaction class="style-scope ytd-guide-entry-renderer"><!--css-build:shady--><div class="stroke style-scope yt-interaction"></div><div class="fill style-scope yt-interaction"></div></yt-interaction></ytd-guide-entry-renderer>`;
document.querySelector(`#items > ytd-guide-entry-renderer:nth-child(2)`).data = trendingData;
var miniguidetemplate = `<ytd-mini-guide-entry-renderer class="style-scope ytd-mini-guide-section-renderer" is-primary="" line-end-style="none"><!--css-build:shady--><a id="endpoint" class="yt-simple-endpoint style-scope ytd-guide-entry-renderer" tabindex="-1" role="tablist"><tp-yt-paper-item role="tab" class="style-scope ytd-guide-entry-renderer" tabindex="0" aria-disabled="false"><!--css-build:shady--><yt-icon class="guide-icon style-scope ytd-guide-entry-renderer" disable-upgrade=""></yt-icon><yt-img-shadow height="24" width="24" class="style-scope ytd-guide-entry-renderer" disable-upgrade=""></yt-img-shadow><yt-formatted-string class="title style-scope ytd-guide-entry-renderer"><!--css-build:shady--></yt-formatted-string><span class="guide-entry-count style-scope ytd-guide-entry-renderer"></span><yt-icon class="guide-entry-badge style-scope ytd-guide-entry-renderer" disable-upgrade=""></yt-icon><div id="newness-dot" class="style-scope ytd-guide-entry-renderer"></div></tp-yt-paper-item></a><yt-interaction class="style-scope ytd-guide-entry-renderer"><!--css-build:shady--><div class="stroke style-scope yt-interaction"></div><div class="fill style-scope yt-interaction"></div></yt-interaction></ytd-guide-entry-renderer>`;
document.querySelector(`#items > ytd-mini-guide-entry-renderer:nth-child(2)`).data = trendingData;
}
waitForElm("#items.ytd-guide-section-renderer").then((elm) => {
restoreTrending();
});
waitForElm("#items.ytd-mini-guide-section-renderer").then((elm) => {
restoreTrending();
});
(function() {
let css = `
/* Remove Shorts, Trending, Podcasts and Shopping buttons to make the sidebar less almost prior to late 2022 */
#endpoint.yt-simple-endpoint.ytd-guide-entry-renderer.style-scope[title="Shorts"],
a.yt-simple-endpoint.style-scope.ytd-mini-guide-entry-renderer[title="Shorts"] {
display: none !important;
}
#endpoint.yt-simple-endpoint.ytd-guide-entry-renderer.style-scope[title="Trending"] {
display: none !important;
}
#endpoint.yt-simple-endpoint.ytd-guide-entry-renderer.style-scope[title="Podcasts"],
ytd-guide-entry-renderer > a[href*="/feed/podcasts"] {
display: none !important
}
ytd-guide-entry-renderer > a[href*="/channel/UCkYQyvc_i9hXEo4xic9Hh2g"] {
display: none !important;
}
/* Remove filter categories on search results and playlists to make the UI less usable on low-entry machines */
ytd-item-section-renderer.style-scope.ytd-section-list-renderer[page-subtype="playlist"] > #header.ytd-item-section-renderer > ytd-feed-filter-chip-bar-renderer {
display: none !important;
}
div#chip-bar.style-scope.ytd-search-header-renderer > yt-chip-cloud-renderer.style-scope.ytd-search-header-renderer > div#container.style-scope.yt-chip-cloud-renderer {
display: none !important;
}
/* Remove (almost) all annoyances (excludes 'YT TV and Premium' banners) */
ytd-action-companion-ad-renderer, ytd-display-ad-renderer, ytd-video-masthead-ad-advertiser-info-renderer, ytd-video-masthead-ad-primary-video-renderer, ytd-in-feed-ad-layout-renderer, ytd-ad-slot-renderer, yt-about-this-ad-renderer, yt-mealbar-promo-renderer, ytd-ad-slot-renderer, ytd-in-feed-ad-layout-renderer, .ytd-video-masthead-ad-v3-renderer, div#root.style-scope.ytd-display-ad-renderer.yt-simple-endpoint, div#sparkles-container.style-scope.ytd-promoted-sparkles-web-renderer, div#main-container.style-scope.ytd-promoted-video-renderer, div#player-ads.style-scope.ytd-watch-flexy, ad-slot-renderer, ytm-promoted-sparkles-web-renderer, masthead-ad, #masthead-ad, ytd-video-quality-promo-renderer {
display: none !important
}`;
if (typeof GM_addStyle !== "undefined") {
GM_addStyle(css);
} else {
let styleNode = document.createElement("style");
styleNode.appendChild(document.createTextNode(css));
(document.querySelector("head") || document.documentElement).appendChild(styleNode);
}
})();
var oldHref = document.location.href;
if (window.location.href.indexOf('youtube.com/shorts') > -1) {
window.location.replace(window.location.toString().replace('/shorts/', '/watch?v='));
}
window.onload = function() {
var bodyList = document.querySelector("body")
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (oldHref != document.location.href) {
oldHref = document.location.href;
console.log('location changed!');
if (window.location.href.indexOf('youtube.com/shorts') > -1) {
window.location.replace(window.location.toString().replace('/shorts/', '/watch?v='));
}
}
});
});
var config = {
childList: true,
subtree: true
};
observer.observe(bodyList, config);
};
// Fully replace shorts links with regular videos
/**
* Shorts URL redirect.
*
* This is called on initial visit only. Successive navigations
* are managed by modifying the YouTube Desktop application.
*/
(function(){
/** @type {string} */
var path = window.location.pathname;
if (0 == path.search("/shorts"))
{
// Extract the video ID from the shorts link and redirect.
/** @type {string} */
var id = path.replace(/\/|shorts|\?.*/g, "");
window.location.replace("https://www.youtube.com/watch?v=" + id);
}
})();
/**
* YouTube Desktop Shorts remover.
*
* If the initial URL was not a shorts link, traditional redirection
* will not work. This instead modifies video elements to replace them with
* regular links.
*/
(function(){
/**
* @param {string} selector (CSS-style) of the element
* @return {Promise<Element>}
*/
async function querySelectorAsync(selector)
{
while (null == document.querySelector(selector))
{
// Pause for a frame and let other code go on.
await new Promise(r => requestAnimationFrame(r));
}
return document.querySelector(selector);
}
/**
* Small toolset for interacting with the Polymer
* YouTube Desktop application.
*
* @author Taniko Yamamoto <kirasicecreamm@gmail.com>
* @version 1.0
*/
class YtdTools
{
/** @type {string} Page data updated event */
static EVT_DATA_UPDATE = "yt-page-data-updated";
/** @type {Element} Main YT Polymer manager */
static YtdApp;
/** @type {bool} */
static hasInitialLoaded = false;
/** @return {Promise<bool>} */
static async isPolymer()
{
/** @return {Promise<void>} */
function waitForBody() // nice hack lazy ass
{
return new Promise(r => {
document.addEventListener("DOMContentLoaded", function a(){
document.removeEventListener("DOMContentLoaded", a);
r();
});
});
}
await waitForBody();
if ("undefined" != typeof document.querySelector("ytd-app"))
{
this.YtdApp = document.querySelector("ytd-app");
return true;
}
return false;
}
/** @async @return {Promise<void|string>} */
static waitForInitialLoad()
{
var updateEvent = this.EVT_DATA_UPDATE;
return new Promise((resolve, reject) => {
if (!this.isPolymer())
{
reject("Not Polymer :(");
}
function _listenerCb()
{
document.removeEventListener(updateEvent, _listenerCb);
resolve();
}
document.addEventListener(updateEvent, _listenerCb);
});
}
/** @return {string} */
static getPageType()
{
return this.YtdApp.data.page;
}
}
class ShortsTools
{
/** @type {MutationObserver} */
static mo = new MutationObserver(muts => {
muts.forEach(mut => {
Array.from(mut.addedNodes).forEach(node => {
if (node instanceof HTMLElement) {
this.onMutation(node);
}
});
});
});
/** @return {void} */
static watchForShorts()
{
/*
this.mo.observe(YtdTools.YtdApp, {
childList: true,
subtree: true
});
*/
var me = this;
YtdTools.YtdApp.arrive("ytd-video-renderer, ytd-grid-video-renderer", function() {
me.onMutation(this);
// This is literally the worst hack I ever wrote, but it works ig...
(new MutationObserver(function(){
if (me.isShortsRenderer(this))
{
me.onMutation(this);
}
}.bind(this))).observe(this, {"subtree": true, "childList": true, "characterData": "true"});
});
}
/** @return {void} */
static stopWatchingForShorts()
{
this.mo.disconnect();
}
/**
* @param {HTMLElement} node
* @return {void}
*/
static onMutation(node)
{
if (node.tagName.search("VIDEO-RENDERER") > -1 && this.isShortsRenderer(node))
{
this.transformShortsRenderer(node);
}
}
/** @return {bool} */
static isShortsRenderer(videoRenderer)
{
return "WEB_PAGE_TYPE_SHORTS" == videoRenderer?.data?.navigationEndpoint?.commandMetadata?.webCommandMetadata?.webPageType;
}
/** @return {string} */
static extractLengthFromA11y(videoData)
{
// A11y = {title} by {creator} {date} {*length*} {viewCount} - play Short
// tho hopefully this works in more than just English
var a11yTitle = videoData.title.accessibility.accessibilityData.label;
var publishedTimeText = videoData.publishedTimeText.simpleText;
var viewCountText = videoData.viewCountText.simpleText;
var isolatedLengthStr = a11yTitle.split(publishedTimeText)[1].split(viewCountText)[0]
.replace(/\s/g, "");
var numbers = isolatedLengthStr.split(/\D/g);
var string = "";
// Remove all empties before iterating it
for (var i = 0; i < numbers.length; i++)
{
if ("" === numbers[i])
{
numbers.splice(i, 1);
i--;
}
}
for (var i = 0; i < numbers.length; i++)
{
// Lazy 0 handling idc im tired
if (1 == numbers.length)
{
string += "0:";
if (1 == numbers[i].length)
{
string += "0" + numbers[i];
}
else
{
string += numbers[i];
}
break;
}
if (0 != i) string += ":";
if (0 != i && 1 == numbers[i].length) string += "0";
string += numbers[i];
}
return string;
}
/**
* @param {HTMLElement} videoRenderer
* @return {void}
*/
static transformShortsRenderer(videoRenderer)
{
/** @type {string} */
var originalOuterHTML = videoRenderer.outerHTML;
/** @type {string} */
var lengthText = videoRenderer.data?.lengthText?.simpleText ?? this.extractLengthFromA11y(videoRenderer.data);
/** @type {string} */
var lengthA11y = videoRenderer.data?.lengthText?.accessibility?.accessibilityData?.label ?? "";
/** @type {string} */
var originalHref = videoRenderer.data.navigationEndpoint.commandMetadata.webCommandMetadata.url;
var href = "/watch?v=" + originalHref.replace(/\/|shorts|\?.*/g, "");
var reelWatchEndpoint = videoRenderer.data.navigationEndpoint.reelWatchEndpoint;
var i;
videoRenderer.data.thumbnailOverlays.forEach((a, index) =>{
if ("thumbnailOverlayTimeStatusRenderer" in a)
{
i = index;
}
});
// Set the thumbnail overlay style
videoRenderer.data.thumbnailOverlays[i].thumbnailOverlayTimeStatusRenderer.style = "DEFAULT";
delete videoRenderer.data.thumbnailOverlays[i].thumbnailOverlayTimeStatusRenderer.icon;
// Set the thumbnail overlay text
videoRenderer.data.thumbnailOverlays[i].thumbnailOverlayTimeStatusRenderer.text.simpleText = lengthText;
// Set the thumbnail overlay accessibility label
videoRenderer.data.thumbnailOverlays[i].thumbnailOverlayTimeStatusRenderer.text.accessibility.accessibilityData.label = lengthA11y;
// Set the navigation endpoint metadata (used for middle click)
videoRenderer.data.navigationEndpoint.commandMetadata.webCommandMetadata.webPageType = "WEB_PAGE_TYPE_WATCH";
videoRenderer.data.navigationEndpoint.commandMetadata.webCommandMetadata.url = href;
videoRenderer.data.navigationEndpoint.watchEndpoint = {
"videoId": reelWatchEndpoint.videoId,
"playerParams": reelWatchEndpoint.playerParams,
"params": reelWatchEndpoint.params
};
delete videoRenderer.data.navigationEndpoint.reelWatchEndpoint;
//var _ = videoRenderer.data; videoRenderer.data = {}; videoRenderer.data = _;
// Sometimes the old school data cycle trick fails,
// however this always works.
var _ = videoRenderer.cloneNode();
_.data = videoRenderer.data;
for (var i in videoRenderer.properties)
{
_[i] = videoRenderer[i];
}
videoRenderer.insertAdjacentElement("afterend", _);
videoRenderer.remove();
}
}
/**
* Sometimes elements are reused on page updates, so fix that
*
* @return {void}
*/
function onDataUpdate()
{
var videos = document.querySelectorAll("ytd-video-renderer, ytd-grid-video-renderer");
for (var i = 0, l = videos.length; i < l; i++) if (ShortsTools.isShortsRenderer(videos[i]))
{
ShortsTools.transformShortsRenderer(videos[i]);
}
}
/**
* I hope she makes lotsa spaghetti :D
* @async @return {Promise<void>}
*/
async function main()
{
// If not Polymer, nothing happens
if (await YtdTools.isPolymer())
{
ShortsTools.watchForShorts();
document.addEventListener("yt-page-data-updated", onDataUpdate);
}
}
main();
})();
// Auto skip ads and force disable autopause (special thanks to CY Fung for the ads skip script code
(() => {
let popupState = 0;
let popupElement = null;
const rate = 1;
const Promise = (async () => { })().constructor;
const PromiseExternal = ((resolve_, reject_) => {
const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
return class PromiseExternal extends Promise {
constructor(cb = h) {
super(cb);
if (cb === h) {
/** @type {(value: any) => void} */
this.resolve = resolve_;
/** @type {(reason?: any) => void} */
this.reject = reject_;
}
}
};
})();
const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
let vload = null;
const fastSeekFn = HTMLVideoElement.prototype.fastSeek || null;
const addEventListenerFn = HTMLElement.prototype.addEventListener;
if (!addEventListenerFn) return;
const removeEventListenerFn = HTMLElement.prototype.removeEventListener;
if (!removeEventListenerFn) return;
const ytPremiumPopupSelector = 'yt-mealbar-promo-renderer.style-scope.ytd-popup-container:not([hidden])';
const DEBUG = 0;
const rand = (a, b) => a + Math.random() * (b - a);
const log = DEBUG ? console.log.bind(console) : () => 0;
//$0.$['dismiss-button'].click()
const ytPremiumPopupClose = function () {
const popup = document.querySelector(ytPremiumPopupSelector);
if (popup instanceof HTMLElement) {
if (HTMLElement.prototype.closest.call(popup, '[hidden]')) return;
const cnt = insp(popup);
const btn = cnt.$ ? cnt.$['dismiss-button'] : 0;
if (btn instanceof HTMLElement && HTMLElement.prototype.closest.call(btn, '[hidden]')) return;
btn && btn.click();
}
}
//div.video-ads.ytp-ad-module
const clickSkip = function () {
// ytp-ad-skip-button
const isAdsContainerContainsButton = document.querySelector('.video-ads.ytp-ad-module button');
if (isAdsContainerContainsButton) {
const btnFilter = e => HTMLElement.prototype.matches.call(e, ".ytp-ad-overlay-close-button, .ytp-ad-skip-button-modern, .ytp-ad-skip-button") && !HTMLElement.prototype.closest.call(e, '[hidden]');
const btns = [...document.querySelectorAll('.video-ads.ytp-ad-module button[class*="ytp-ad-"]')].filter(btnFilter);
console.log('# of ads skip btns', btns.length);
if (btns.length !== 1) return;
const btn = btns[0];
if (btn instanceof HTMLElement) {
btn.click();
}
}
};
const adsEndHandlerHolder = function (evt) {
adsEndHandler && adsEndHandler(evt);
}
let adsEndHandler = null;
const videoPlayingHandler = async function (evt) {
try {
if (!evt || !evt.target || !evt.isTrusted || !(evt instanceof Event)) return;
const video = evt.target;
const checkPopup = popupState === 1;
popupState = 0;
const popupElementValue = popupElement;
popupElement = null;
if (video.duration < 0.8) return;
await vload.then();
if (!video.isConnected) return;
const ytplayer = HTMLElement.prototype.closest.call(video, 'ytd-player, ytmusic-player');
if (!ytplayer || !ytplayer.is) return;
const ytplayerCnt = insp(ytplayer);
const player_ = await (ytplayerCnt.player_ || ytplayer.player_ || ytplayerCnt.playerApi || ytplayer.playerApi || 0);
if (!player_) return;
if (typeof ytplayerCnt.getPlayer === 'function' && !ytplayerCnt.getPlayer()) {
await new Promise(r => setTimeout(r, 40));
}
const playerController = await ytplayerCnt.getPlayer() || player_;
if (!video.isConnected) return;
if ('getPresentingPlayerType' in playerController && 'getDuration' in playerController) {
const ppType = await playerController.getPresentingPlayerType();
log('m02a', ppType);
if (ppType === 1 || typeof ppType !== 'number') return; // ads shall be ppType === 2
// const progressState = player_.getProgressState();
// log('m02b', progressState);
// if(!progressState) return;
// const q = progressState.duration;
// if (popupState === 1) console.debug('m05b:ytPremiumPopup', document.querySelector(ytPremiumPopupSelector))
const q = video.duration;
const ytDuration = await playerController.getDuration();
log('m02c', q, ytDuration, Math.abs(ytDuration - q));
if (q > 0.8 && ytDuration > 2.5 && Math.abs(ytDuration - q) > 1.4) {
try {
log('m02s', 'fastSeek', q);
video.muted = true;
const w = Math.round(rand(582, 637) * rate);
const sq = q - w / 1000;
adsEndHandler = null;
const expired = Date.now() + 968;
removeEventListenerFn.call(video, 'ended', adsEndHandlerHolder, false);
removeEventListenerFn.call(video, 'suspend', adsEndHandlerHolder, false);
removeEventListenerFn.call(video, 'durationchange', adsEndHandlerHolder, false);
addEventListenerFn.call(video, 'ended', adsEndHandlerHolder, false);
addEventListenerFn.call(video, 'suspend', adsEndHandlerHolder, false);
addEventListenerFn.call(video, 'durationchange', adsEndHandlerHolder, false);
adsEndHandler = async function (evt) {
adsEndHandler = null;
removeEventListenerFn.call(video, 'ended', adsEndHandlerHolder, false);
removeEventListenerFn.call(video, 'suspend', adsEndHandlerHolder, false);
removeEventListenerFn.call(video, 'durationchange', adsEndHandlerHolder, false);
if (Date.now() < expired) {
const delay = Math.round(rand(92, 117));
await new Promise(r => setTimeout(r, delay));
Promise.resolve().then(() => {
clickSkip();
}).catch(console.warn);
checkPopup && Promise.resolve().then(() => {
const currentPopup = document.querySelector(ytPremiumPopupSelector);
if (popupElementValue ? currentPopup === popupElementValue : currentPopup) {
ytPremiumPopupClose();
}
}).catch(console.warn);
}
};
if (fastSeekFn) fastSeekFn.call(video, sq);
else video.currentTime = sq;
} catch (e) {
console.warn(e);
}
}
}
} catch (e) {
console.warn(e);
}
};
document.addEventListener('loadedmetadata', async function (evt) {
try {
if (!evt || !evt.target || !evt.isTrusted || !(evt instanceof Event)) return;
const video = evt.target;
if (video.nodeName !== "VIDEO") return;
if (video.duration < 0.8) return;
if (!video.matches('.video-stream.html5-main-video')) return;
popupState = 0;
vload = new PromiseExternal();
popupElement = document.querySelector(ytPremiumPopupSelector);
removeEventListenerFn.call(video, 'playing', videoPlayingHandler, { passive: true, capture: false });
addEventListenerFn.call(video, 'playing', videoPlayingHandler, { passive: true, capture: false });
popupState = 1;
let trial = 6;
await new Promise(resolve => {
let io = new IntersectionObserver(entries => {
if (trial-- <= 0 || (entries && entries.length >= 1 && video.matches('ytd-player video, ytmusic-player video'))) {
resolve();
io.disconnect();
io = null;
}
});
io.observe(video);
});
vload.resolve();
} catch (e) {
console.warn(e);
}
}, true);
})();
Object.defineProperties(document, { /*'hidden': {value: false},*/ 'webkitHidden': {value: false}, 'visibilityState': {value: 'visible'}, 'webkitVisibilityState': {value: 'visible'} });
setInterval(function(){
document.dispatchEvent( new KeyboardEvent( 'keyup', { bubbles: true, cancelable: true, keyCode: 143, which: 143 } ) );
}, 60000);