// ==UserScript==
// @name 7ktTube | 2016 REDUX
// @namespace STILL_ALIVE
// @version 4.4.57
// @description Old YouTube 2016 Layout | Old watchpage | Change thumbnail & video player size | grayscale seen video thumbnails | Hide suggestion blocks, category/filter bars | Square profile-pictures | Disable hover thumbnail previews | and much more!
// @author 7KT-SWE
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAACnVBMVEUAAAD////////94+PX19f+8fH/////////+fn83Nz////////////////////////////////////////////////////////////829vS0tL////////////////////////////////////////////////y8vLp6en95+f////////////sKCgAAADpCQnqDg7pBgbqCwvsHh7sICDsIyPtKirsJibrGhr1kZHyaGjrGBjnAAD81tbrHBz3oqLsJSXxX1/qEBDp6enxZGSysrIVFRX2k5PxWVnqEhK0tLT1gYHtLCzqFBTybW3wUlLtMDDtMjLz8/PuOzvqFxcHBwf95eX0iIjxYGDvQEDpAQF/f3/wU1PuNTX+7e394+PuODgfHx///f3+9PT6xMT4qKilpaX1i4v82dnvR0f/+vr+8vLj5OT2nJzzcnLzcHDwS0vvRETrFRXx8fH7z8/5urrsk5N2dnbxVlbwT08iIiL83d380dH7ycmqqqr1jo70fHx0dHT7JSX6+vr39/f/9vb+8/P+6ur83Nz71NTR0dH5tLT3paX2mZn1iIj1hYXxXFwFBQXNzc33r6/3n5+JiYmFhYV6enrzeHhJSUkiPDzpDw8LDAz95+f7zc36vr68vLyUlJTzdXVra2vyamo0NDTrJib8ICD5Hh4dHR0RERHf39/Y2Nj7zs7Gxsb6v7+2trbvra2Xl5eQkJDybGxeXl5XV1dMTExHR0c7OzsdNjYuLi4SLS38KiopKSn9/Pzv+vr839+8yMj5wMDxuLi4uLj4qqruqqqgoKB8fHwGICDyFxfsFhbV4uL7y8vyx8f6wMCvvb3tt7e3t7eur6+Yr6+OpaXuoKA2U1NRUVE0UVEYMTETMDDyKSkMJye13jY6AAAALHRSTlMAavLy8vJi9PLy4vru2L6UhGs1JRAI5VEb8vLo3qyqfHpIRUA/Eg/y8vJTHBug3AoAAAhOSURBVGjevZqF39JAGIDt7u5uD7fBSoeIM1GwwADBDmzB7u7u7u7u7u7Ov8WLsaAUnD4/f+x27rvnu727947vlkOlTL6qRYvkzxWjQaU8eirVz/WH5C9StFq+ejniKVsiPzDQu8ma7hpNmnQAmZC/RFlj+6UKgTg2NTHSBmRG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
// @icon64 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAACNFBMVEUAAAD////////4rKyYmJj////3pqb7zMz4trb////////////////////////819f5wMD////////////83d36xMT5urqOjo7/////////////+Pj+8vL96+v95+f95eX84+O6urr4r6+qqqr3qKj////////////////sKCgAAADsJCTsKSnrICDpCgrrHh7qERHsIiLpBQX+8PDrGxvrGBjqDg7pBwfrFRURERH/+fn82Nh7e3vtLS3809PwXFztLi7pAADs7e381tb7zs7uMzPqDAz96urvR0f82trtMDD+8/PwUVHwS0v95+f3o6P4qan3oKDyamr/+/v+7u7zbW3xV1fvQ0M5OTnqCgrmAADn5+f7yMj6wcH6vLz2mZn2kZHzdHRhYWFaWlruPj7uOzvuODguLi7+9/f/9fXx8fH95ub95eX84OD7y8vExMT7w8O6urr3nJz0gIDwVFT/NDQJCwv94uL83t7V1dX70NC+vr62trb4rq6ZmZn2lZWKiopqampoaGjyZGTxXFxPT0//QUHuQEDtFhbe3t73trb1s7Nzi4v1iYmIiIj0g4N5eXmjc3PzcnJCQkL/OTkpKSkdHR39///t///u7u7q6urf39/IyMj6vr7NpaWkpKSQkJCBgYHzd3ewcnJubm7xZWWiZGTxYWFXV1cAGRkYGBjd+fn19fXh4eGsrKzQl5fHlpatgoKkfHy0dnaqa2tiYmJdXV3/RkYjPDwXMzP/MDD+KSmHIHNsAAAAKHRSTlMAv/Dw8Ljw8PDj05JnMQbw8NxdR/Dw8PC5Q0Lw8PDw8PDw8PDw3V5JgcnJaAAABWxJREFUWMOl14dX00AcB3D33nvvcZdc1tE0EUQboQXBKqVIbQUBBVRERMC999577733+uf8XdKkDa/aoN/3SJMr9+nl7jKum5khg3r372Fl+theVsbO7PGX9O89aEg3JyOHIyeXODsv0d8zfKRdf0R68REHWIuyZYRVfzD6VwANNoEBrrIdu3ft2rXpIAArsgMDWP0JKEMeA3AAZc94AAaiDLkCwF4PwEAAemcoX8lBdqADzw80odtrjmw+sWa1meebkDvjAOieAdgM9eeha7BtQis47sRuLpn7yJ3ufwD2m334eh4oizjuCLpnA/c8Amvgfw+iRQx4wHG30Y0dtw5Aya0dTR6BtawPGXBl5dXkcJ7luLPwkRVI9eEmBlw6y3ZY5nPcfM8A68OtNxhw9SqchXfA3YcMgHhvgbsPvzjAg64Da9mIO8ClLgMrt0K1XRaw4gq3tckj4O7DmxZwAi6r3V0F9ls3A2si7eW4896BVB9+tYE3cBregVQf7k8CUfSS4256BlLzcHMSaGLteds1wLx2VyaBRawTDsLBeegLj8BpqP8dQa6/4F5cR6+2cj+umaWnswLrSis2bNx+9+OHC+9bq6vvnHr09NGpVXc+Pf18srr63YULdxcUbN/YXJSzLjNwanm4viEYIPjyt6NHt6i6qh/fcnnLcdnc6vqvo0d/SgomgWBjQ/GhSG5nYHGYUllXVZ9PkgRBYeHTYhYIgiRJPlXVZc0IrnIDO30GT7DnEBynZelAEdas6t4JXWxJAx4aAcUv2/HrhKR+S/bL9rFLoMUpoIhX+WC42E74GI/t8KQ4bB+7w8dbHWBPHPuXoFRadAUnowZLEcqTBJyhCeccoEbD/nAasCAdgAHbngnAYrkD1Go43pEGNKcDOQgVZAYOOUC7htX6SKT2JFSuaKtZdk7iPQChSge4qOF8RdMSMdZ8w9BkNnEwUSAWIEi6jmEkoEyX1eSMkcMOsFy02rQQgDxBwsQH883a6gzIo7S+URRgMDW1IRb0+wkj9FjUBp7EXYAi7NlZWB2Qy3YWVmEegNZAWXR9rczztLwwF1WcjGkmUL/OBg6HXIDgK4KdErqNbSUAlkYR5KFGLyIz0ZgIgtqYYwOV/k7AAoRyAmIhQrn5Qo4zuEYJgmyAvwJZYf1bYQNLsgDrKw/DbNhmtMP3dWIZsmr4Soq8AgsSWjNc8XQZjLKUYHN2Of0rILkBaDG/AQANfnsjb3QwQCNdBJaaLQBATMSyA74/A6Vlbav+B7Bzkf4zUMqSWy66gErvwIbG/CDPJ6+zitRM9AxsUzUfD4J7Jh4SPQPNxKhcX7qOnYLeUGoD5RmAihJa5Uwkv9KcmgeVbD5SAI7l2kBdJ0AqgBaEEgU2kJegRQDQCPShkmBAOXXdD9q1TkAe7OwrQzYQPVOL2LVQB9tIfRVsYzLG/g4HqHUDvGY9txzASpXB24/VVRoMRPxZ+l2ZhZYjuPIkiYTCCHJmO2wCEiurQpCOkNhhPVN3KjpJ3ZV7w3NBtAa2uGZfzTk2RuKzlpYnRl2kbR/h97VF6uT2wqpDcUK0+pqWgtYzkpzPngvt1oJjIMwOxceAfIlSKhKCCQmpqohlSjVMNEplicIxgchUlWTqg/qYF+FEByYXXcsNknwSWp/sjpzccx8TrAi8tacdi8KiK7nsWyqFAO1KiEqrYdnnLDxbZQq658C5GG1s4Zla+hY2GJpuv57wfwh7S5EkeFyIBr8HKs1xLb4jhxtK8jEvwPc6e0lgCZkxd6FI11WfBF0QaFxSCzNz9lyrdmr5P3Hy1FFDh/btO3rYmH79ZvSEzOrD0pOlX78xw4aN7tt36KhpUyalLf9/A5nj/LZRV7kLAAAAAElFTkSuQmCC
// @license GPL-3.0-only
// @homepageURL https://7kt.se/
// @downloadURL https://7kt.se/install/7ktTube.user.js
// @updateURL https://7kt.se/install/7ktTube.user.js
// @supportURL https://discord.com/invite/7WRjXHMfXJ
// @contributionURL https://www.paypal.com/donate/?hosted_button_id=2EJR4DLTR4Y7Q
// BEGIN MODULES
// @require https://7kt.se/resources/modules/445/tempcssfix.js?v=4457
// @require https://7kt.se/resources/modules/445/flags.js?v=4451
// @require https://7kt.se/resources/modules/445/home.js?v=4451
// @require https://7kt.se/resources/modules/445/settings.js?v=4451
// @require https://7kt.se/resources/modules/445/styles.js?v=4451
// @require https://7kt.se/resources/modules/445/watch.js?v=4451
// @require https://greasyfork.org/scripts/28536-gm-config/code/GM_config.js?version=184529
// END MODULES
// @match *://*.youtube.com/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM.getValue
// @grant GM.setValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
/*jshint esversion: 6 */
// fix GM_addStyle
if (typeof GM_addStyle !== "function") {
function GM_addStyle(css) {
let style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(css));
const head = document.documentElement ?? document.getElementsByTagName("head")[0];
head.appendChild(style);
}
}
function removePlayerElements() {
document.querySelectorAll("#masthead-ad,#root").forEach(e => e.remove());
document.querySelector("ytd-miniplayer")?.remove();
document.querySelector("ytd-miniplayer-ui")?.remove();
document.querySelector(".ytp-miniplayer-button")?.remove();
if (window.location.pathname != "/watch") document.querySelector("#movie_player video")?.remove();
}
function gen_aspect_fix() {
"use strict";
var vidfix = {
inject: function(is_user_script) {
var modules;
var vidfix_api;
var user_settings;
var default_language;
var send_settings_to_page;
var receive_settings_from_page;
modules = [];
vidfix_api = {
initializeBypasses: function() {
var ytd_watch;
var sizeBypass;
if (ytd_watch = document.querySelector("ytd-watch, ytd-watch-flexy")) {
sizeBypass = function() {
var width;
var height;
var movie_player;
if (!ytd_watch.theater && !document.querySelector(".iri-full-browser") && (movie_player = document.querySelector("#movie_player"))) {
width = movie_player.offsetWidth;
height = Math.round(movie_player.offsetWidth / (16 / 9));
if (ytd_watch.updateStyles) {
ytd_watch.updateStyles({
"--ytd-watch-flexy-width-ratio": 1,
"--ytd-watch-flexy-height-ratio": 0.5625
});
ytd_watch.updateStyles({
"--ytd-watch-width-ratio": 1,
"--ytd-watch-height-ratio": 0.5625
});
}
}
else {
width = window.NaN;
height = window.NaN;
}
return {
width: width,
height: height
};
};
if (ytd_watch.calculateCurrentPlayerSize_) {
if (!ytd_watch.calculateCurrentPlayerSize_.bypassed) {
ytd_watch.calculateCurrentPlayerSize_ = sizeBypass;
ytd_watch.calculateCurrentPlayerSize_.bypassed = true;
}
if (!ytd_watch.calculateNormalPlayerSize_.bypassed) {
ytd_watch.calculateNormalPlayerSize_ = sizeBypass;
ytd_watch.calculateNormalPlayerSize_.bypassed = true;
}
}
}
},
initializeSettings: function(new_settings) {
var i;
var j;
var option;
var options;
var loaded_settings;
var vidfix_settings;
if (vidfix_settings = document.getElementById("vidfix-settings")) {
loaded_settings = JSON.parse(vidfix_settings.textContent || "null");
receive_settings_from_page = vidfix_settings.getAttribute("settings-beacon-from");
send_settings_to_page = vidfix_settings.getAttribute("settings-beacon-to");
vidfix_settings.remove();
}
user_settings = new_settings || loaded_settings || user_settings || {};
for (i = 0; i < modules.length; i++) {
for (options in modules[i].options) {
if (modules[i].options.hasOwnProperty(options)) {
option = modules[i].options[options];
if (!(option.id in user_settings) && "value" in option) {
user_settings[option.id] = option.value;
}
}
}
}
},
initializeModulesUpdate: function() {
var i;
for (i = 0; i < modules.length; i++) {
if (modules[i].onSettingsUpdated) {
modules[i].onSettingsUpdated();
}
}
},
initializeModules: function() {
var i;
for (i = 0; i < modules.length; i++) {
if (modules[i].ini) {
modules[i].ini();
}
}
},
initializeOption: function() {
var key;
if (this.started) {
return true;
}
this.started = true;
for (key in this.options) {
if (this.options.hasOwnProperty(key)) {
if (!(key in user_settings) && this.options[key].value) {
user_settings[key] = this.options[key].value;
}
}
}
return false;
},
initializeBroadcast: function(event) {
if (event.data) {
if (event.data.type === "settings") {
if (event.data.payload) {
if (event.data.payload.broadcast_id === this.broadcast_channel.name) {
this.initializeSettings(event.data.payload);
this.initializeModulesUpdate();
}
}
}
}
},
ini: function() {
this.initializeSettings();
this.broadcast_channel = new BroadcastChannel(user_settings.broadcast_id);
this.broadcast_channel.addEventListener("message", this.initializeBroadcast.bind(this));
document.documentElement.addEventListener("load", this.initializeSettingsButton, true);
document.documentElement.addEventListener("load", this.initializeBypasses, true);
if (this.isSettingsPage) {
this.initializeModules();
}
}
};
vidfix_api.ini();
},
isAllowedPage: function() {
var current_page;
if (current_page = window.location.pathname.match(/\/[a-z-]+/)) {
current_page = current_page[0];
}
else {
current_page = window.location.pathname;
}
return ["/tv", "/embed", "/live_chat", "/account", "/account_notifications", "/create_channel", "/dashboard", "/upload", "/webcam"].indexOf(current_page) < 0;
},
generateUUID: function() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11)
.replace(/[018]/g, function(point) {
return (point ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> point / 4)
.toString(16);
});
},
saveSettings: function() {
if (this.is_user_script) {
this.GM.setValue(this.id, JSON.stringify(this.user_settings));
}
else {
chrome.storage.local.set({
vidfixSettings: this.user_settings
});
}
},
updateSettingsOnOpenWindows: function() {
this.broadcast_channel.postMessage({
type: "settings",
payload: this.user_settings
});
},
settingsUpdatedFromOtherWindow: function(event) {
if (event.data && event.data.broadcast_id === this.broadcast_channel.name) {
this.user_settings = event.data;
this.saveSettings();
}
},
contentScriptMessages: function(custom_event) {
var updated_settings;
if ((updated_settings = custom_event.detail.settings) !== undefined) {
this.saveSettings();
}
},
initializeScript: function(event) {
var holder;
this.user_settings = event[this.id] || event;
if (!this.user_settings.broadcast_id) {
this.user_settings.broadcast_id = this.generateUUID();
this.saveSettings();
}
this.broadcast_channel = new BroadcastChannel(this.user_settings.broadcast_id);
this.broadcast_channel.addEventListener("message", this.settingsUpdatedFromOtherWindow.bind(this));
event = JSON.stringify(this.user_settings);
holder = document.createElement("vidfix-settings");
holder.id = "vidfix-settings";
holder.textContent = event;
holder.setAttribute("style", "display: none");
holder.setAttribute("settings-beacon-from", this.receive_settings_from_page);
holder.setAttribute("settings-beacon-to", this.send_settings_to_page);
document.documentElement.appendChild(holder);
holder = document.createElement("script");
holder.textContent = "(" + this.inject + "(" + this.is_user_script.toString() + "))";
document.documentElement.appendChild(holder);
holder.remove();
this.inject = null;
delete this.inject;
},
main: function(event) {
var now;
var context;
now = Date.now();
this.receive_settings_from_page = now + "-" + this.generateUUID();
this.send_settings_to_page = now + 1 + "-" + this.generateUUID();
window.addEventListener(this.receive_settings_from_page, this.contentScriptMessages.bind(this), false);
if (!event) {
if (this.is_user_script) {
context = this;
// javascript promises are horrible
this.GM.getValue(this.id, "{}")
.then(function(value) {
event = JSON.parse(value);
context.initializeScript(event);
});
}
}
else {
this.initializeScript(event);
}
},
ini: function() {
if (this.isAllowedPage()) {
this.is_settings_page = window.location.pathname === "/vidfix-settings";
this.id = "vidfixSettings";
if (typeof GM === "object" || typeof GM_info === "object") {
this.is_user_script = true;
// GreaseMonkey 4 polly fill
// https://arantius.com/misc/greasemonkey/imports/greasemonkey4-polyfill.js
if (typeof GM === "undefined") {
this.GM = {
setValue: GM_setValue,
info: GM_info,
getValue: function() {
return new Promise((resolve, reject) => {
try {
resolve(GM_getValue.apply(this, arguments));
}
catch (e) {
reject(e);
}
});
}
};
}
else {
this.GM = GM;
}
this.main();
}
else {
this.is_user_script = false;
chrome.storage.local.get(this.id, this.main.bind(this));
}
}
}
};
vidfix.ini();
}
function waitForElement(selector) {
return new Promise(resolve => {
const query = document.querySelector(selector);
if (query) return resolve(query);
const observer = new MutationObserver(mutations => {
const query = document.querySelector(selector);
if (query) {
resolve(query);
observer.disconnect();
}
});
observer.observe(document, {
childList: true,
subtree: true
});
});
}
function gen_history() {
/*
- Grey out watched video thumbnails info:
- Use ALT+LeftClick or ALT+RightClick on a video list item to manually toggle the watched marker. The mouse button is defined in the script and can be changed.
- For restoring/merging history, source file can also be a YouTube's history data JSON (downloadable from https://support.google.com/accounts/answer/3024190?hl=en). Or a list of YouTube video URLs (using current time as timestamps).
*/
//=== config start ===
var maxWatchedVideoAge = 5 * 365; //number of days. set to zero to disable (not recommended)
var contentLoadMarkDelay = 600; //number of milliseconds to wait before marking video items on content load phase (increase if slow network/browser)
var markerMouseButtons = [0, 1]; //one or more mouse buttons to use for manual marker toggle. 0=left, 1=right, 2=middle. e.g.:
//if `[0]`, only left button is used, which is ALT+LeftClick.
//if `[1]`, only right button is used, which is ALT+RightClick.
//if `[0,1]`, any left or right button can be used, which is: ALT+LeftClick or ALT+RightClick.
//=== config end ===
var watchedVideos, ageMultiplier = 24 * 60 * 60 * 1000, xu = /\/watch(?:\?|.*?&)v=([^&]+)|\/shorts\/([^\/\?]+)/,
querySelector = Element.prototype.querySelector, querySelectorAll = Element.prototype.querySelectorAll;
function getVideoId(url) {
var vid = url.match(xu);
if (vid) vid = vid[1] || vid[2];
return vid;
}
function watched(vid) {
return !!watchedVideos.entries[vid];
}
function processVideoItems(selector) {
var items = document.querySelectorAll(selector), i, link;
for (i = items.length-1; i >= 0; i--) {
if (link = querySelector.call(items[i], "A")) {
if (watched(getVideoId(link.href))) {
items[i].classList.add("watched");
} else items[i].classList.remove("watched");
}
}
}
function processAllVideoItems() {
//home page
processVideoItems(`.yt-uix-shelfslider-list>.yt-shelf-grid-item`);
processVideoItems(`#contents.ytd-rich-grid-renderer>ytd-rich-item-renderer, #contents.ytd-rich-shelf-renderer ytd-rich-item-renderer.ytd-rich-shelf-renderer, #contents.ytd-rich-grid-renderer>ytd-rich-grid-row ytd-rich-grid-media`);
//subscriptions page
processVideoItems(`.multirow-shelf>.shelf-content>.yt-shelf-grid-item`);
//history:watch page
processVideoItems(`ytd-section-list-renderer[page-subtype="history"] .ytd-item-section-renderer>ytd-video-renderer`);
//channel/user home page
processVideoItems(`#contents>.ytd-item-section-renderer>.ytd-newspaper-renderer, #items>.yt-horizontal-list-renderer`); //old
processVideoItems(`#contents>.ytd-channel-featured-content-renderer, #contents>.ytd-shelf-renderer>#grid-container>.ytd-expanded-shelf-contents-renderer`); //new
//channel/user video page
processVideoItems(`.yt-uix-slider-list>.featured-content-item, .channels-browse-content-grid>.channels-content-item, #items>.ytd-grid-renderer`);
//channel/user shorts page
processVideoItems(`ytd-rich-item-renderer ytd-rich-grid-slim-media`);
//channel/user playlist page
processVideoItems(`.expanded-shelf>.expanded-shelf-content-list>.expanded-shelf-content-item-wrapper, .ytd-playlist-video-renderer`);
//channel/user playlist item page
processVideoItems(`.pl-video-list .pl-video-table .pl-video, ytd-playlist-panel-video-renderer`);
//channel/user search page
if (/^\/(?:(?:c|channel|user)\/)?.*?\/search/.test(location.pathname)) {
processVideoItems(`.ytd-browse #contents>.ytd-item-section-renderer`); //new
}
//search page
processVideoItems(`#results>.section-list .item-section>li, #browse-items-primary>.browse-list-item-container`); //old
processVideoItems(`.ytd-search #contents>ytd-video-renderer, .ytd-search #contents>ytd-playlist-renderer, .ytd-search #items>ytd-video-renderer`); //new
//video page
processVideoItems(`.watch-sidebar-body>.video-list>.video-list-item, .playlist-videos-container>.playlist-videos-list>li`); //old
processVideoItems(`.ytd-compact-video-renderer, .ytd-compact-radio-renderer`); //new
}
function addHistory(vid, time, noSave, i) {
if (!watchedVideos.entries[vid]) {
watchedVideos.index.push(vid);
} else {
i = watchedVideos.index.indexOf(vid);
if (i >= 0) watchedVideos.index.push(watchedVideos.index.splice(i, 1)[0])
}
watchedVideos.entries[vid] = time;
if (!noSave) GM_setValue("watchedVideos", JSON.stringify(watchedVideos));
}
function delHistory(index, noSave) {
delete watchedVideos.entries[watchedVideos.index[index]];
watchedVideos.index.splice(index, 1);
if (!noSave) GM_setValue("watchedVideos", JSON.stringify(watchedVideos));
}
var dc, ut;
function parseData(s, a, i, j, z) {
try {
dc = false;
s = JSON.parse(s);
//convert to new format if old format.
//old: [{id:<strVID>, timestamp:<numDate>}, ...]
//new: {entries:{<stdVID>:<numDate>, ...}, index:[<strVID>, ...]}
if (Array.isArray(s) && (!s.length || (("object" === typeof s[0]) && s[0].id && s[0].timestamp))) {
a = s;
s = {entries: {}, index: []};
a.forEach(o => {
s.entries[o.id] = o.timestamp;
s.index.push(o.id);
});
} else if (("object" !== typeof s) || ("object" !== typeof s.entries) || !Array.isArray(s.index)) return null;
//reconstruct index if broken
if (s.index.length !== (a = Object.keys(s.entries)).length) {
s.index = a.map(k => [k, s.entries[k]]).sort((x, y) => x[1] - y[1]).map(v => v[0]);
dc = true;
}
return s;
} catch(z) {
return null;
}
}
function parseYouTubeData(s, a) {
try {
s = JSON.parse(s);
//convert to native format if YouTube format.
//old: [{titleUrl:<strUrl>, time:<strIsoDate>}, ...] (excludes irrelevant properties)
//new: {entries:{<stdVID>:<numDate>, ...}, index:[<strVID>, ...]}
if (Array.isArray(s) && (!s.length || (("object" === typeof s[0]) && s[0].titleUrl && s[0].time))) {
a = s;
s = {entries: {}, index: []};
a.forEach((o, m, t) => {
if (o.titleUrl && (m = o.titleUrl.match(xu))) {
if (isNaN(t = (new Date(o.time)).getTime())) t = (new Date()).getTime();
s.entries[m[1] || m[2]] = t;
s.index.push(m[1] || m[2]);
}
});
s.index.reverse();
return s;
} else return null;
} catch(a) {
return null;
}
}
function mergeData(o, a) {
o.index.forEach(i => {
if (watchedVideos.entries[i]) {
if (watchedVideos.entries[i] < o.entries[i]) watchedVideos.entries[i] = o.entries[i];
} else watchedVideos.entries[i] = o.entries[i];
});
a = Object.keys(watchedVideos.entries);
watchedVideos.index = a.map(k => [k, watchedVideos.entries[k]]).sort((x, y) => x[1] - y[1]).map(v => v[0]);
}
function getHistory(a, b) {
a = GM_getValue("watchedVideos");
if (a === undefined) {
a = '{"entries": {}, "index": []}';
} else if ("object" === typeof a) a = JSON.stringify(a);
if (b = parseData(a)) {
watchedVideos = b;
if (dc) b = JSON.stringify(b);
} else b = JSON.stringify(watchedVideos = {entries: {}, index: []});
GM_setValue("watchedVideos", b);
}
function doProcessPage() {
//get list of watched videos
getHistory();
//remove old watched video history
var now = (new Date()).valueOf(), changed, vid;
if (maxWatchedVideoAge > 0) {
while (watchedVideos.index.length) {
if (((now - watchedVideos.entries[watchedVideos.index[0]]) / ageMultiplier) > maxWatchedVideoAge) {
delHistory(0, false);
changed = true;
} else break;
}
if (changed) GM_setValue("watchedVideos", JSON.stringify(watchedVideos));
}
//check and remember current video
if ((vid = getVideoId(location.href)) && !watched(vid)) addHistory(vid, now);
//mark watched videos
processAllVideoItems();
}
function processPage() {
setTimeout(doProcessPage, Math.floor(contentLoadMarkDelay / 2));
}
function delayedProcessPage() {
setTimeout(doProcessPage, contentLoadMarkDelay);
}
function toggleMarker(ele, i) {
if (ele) {
if (!ele.href && (i = ele.closest('a'))) ele = i;
if (ele.href) {
i = getVideoId(ele.href);
} else {
while (ele) {
while (ele && (!ele.__data || !ele.__data.data || !ele.__data.data.videoId)) ele = ele.__dataHost || ele.parentNode;
if (ele) {
i = ele.__data.data.videoId;
break
}
}
}
if (i) {
if ((ele = watchedVideos.index.indexOf(i)) >= 0) {
delHistory(ele);
} else addHistory(i, (new Date()).valueOf());
processAllVideoItems();
}
}
}
var rxListUrl = /\/\w+_ajax\?|\/results\?search_query|\/v1\/(browse|next|search)\?/;
var xhropen = XMLHttpRequest.prototype.open, xhrsend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url) {
this.url_mwyv = url;
return xhropen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(method, url) {
if (rxListUrl.test(this.url_mwyv) && !this.listened_mwyv) {
this.listened_mwyv = 1;
this.addEventListener("load", delayedProcessPage);
}
return xhrsend.apply(this, arguments);
};
var fetch_ = unsafeWindow.fetch;
unsafeWindow.fetch = function(opt) {
let url = opt.url || opt;
if (rxListUrl.test(opt.url || opt)) {
return fetch_.apply(this, arguments).finally(delayedProcessPage);
} else return fetch_.apply(this, arguments);
};
addEventListener("DOMContentLoaded", sty => {
sty = document.createElement("STYLE");
sty.innerHTML = `
`;
document.head.appendChild(sty);
var nde = Node.prototype.dispatchEvent;
Node.prototype.dispatchEvent = function(ev) {
if (ev.type === "yt-service-request-completed") {
clearTimeout(ut);
ut = setTimeout(doProcessPage, contentLoadMarkDelay / 2)
}
return nde.apply(this, arguments)
};
});
var lastFocusState = document.hasFocus();
addEventListener("blur", () => {
lastFocusState = false;
});
addEventListener("focus", () => {
if (!lastFocusState) processPage();
lastFocusState = true;
});
addEventListener("click", (ev) => {
if ((markerMouseButtons.indexOf(ev.button) >= 0) && ev.altKey) {
ev.stopImmediatePropagation();
ev.stopPropagation();
ev.preventDefault();
toggleMarker(ev.target);
}
}, true);
if (markerMouseButtons.indexOf(1) >= 0) {
addEventListener("contextmenu", (ev) => {
if (ev.altKey) toggleMarker(ev.target);
});
}
if (window["body-container"]) { //old
addEventListener("spfdone", processPage);
processPage();
} else { //new
var t = 0;
function pl() {
clearTimeout(t);
t = setTimeout(processPage, 300);
}
(function init(vm) {
if (vm = document.getElementById("visibility-monitor")) {
vm.addEventListener("viewport-load", pl);
} else setTimeout(init, 100);
})();
(function init2(mh) {
if (mh = document.getElementById("masthead")) {
mh.addEventListener("yt-rendererstamper-finished", pl);
} else setTimeout(init2, 100);
})();
addEventListener("load", delayedProcessPage);
addEventListener("spfprocess", delayedProcessPage);
}
GM_registerMenuCommand("Display History Statistics", () => {
function sum(r, v) {
return r + v;
}
function avg(arr) {
return arr && arr.length ? Math.round(arr.reduce(sum, 0) / arr.length) : "(n/a)";
}
var pd, pm, py, ld = [], lm = [], ly = [];
getHistory();
Object.keys(watchedVideos.entries).forEach((k, t) => {
t = new Date(watchedVideos.entries[k]);
if (!pd || (pd !== t.getDate())) {
ld.push(1);
pd = t.getDate();
} else ld[ld.length - 1]++;
if (!pm || (pm !== (t.getMonth() + 1))) {
lm.push(1);
pm = t.getMonth() + 1;
} else lm[lm.length - 1]++;
if (!py || (py !== t.getFullYear())) {
ly.push(1);
py = t.getFullYear();
} else ly[ly.length - 1]++;
});
if (watchedVideos.index.length) {
pd = (new Date(watchedVideos.entries[watchedVideos.index[0]])).toLocaleString();
pm = (new Date(watchedVideos.entries[watchedVideos.index[watchedVideos.index.length - 1]])).toLocaleString();
} else {
pd = "(n/a)";
pm = "(n/a)";
}
alert(`\
Number of entries: ${watchedVideos.index.length}
Oldest entry: ${pd}
Newest entry: ${pm}
Average viewed videos per day: ${avg(ld)}
Average viewed videos per month: ${avg(lm)}
Average viewed videos per year: ${avg(ly)}
History data size: ${JSON.stringify(watchedVideos).length} bytes\
`);
});
GM_registerMenuCommand("Backup History Data", (a, b) => {
document.body.appendChild(a = document.createElement("A")).href = URL.createObjectURL(new Blob([JSON.stringify(watchedVideos)], {type: "application/json"}));
a.download = `MarkWatchedYouTubeVideos_${(new Date()).toISOString()}.json`;
a.click();
a.remove();
URL.revokeObjectURL(a.href);
});
GM_registerMenuCommand("Restore History Data", (a, b) => {
function askRestore(o) {
if (confirm(`Selected history data file contains ${o.index.length} entries.\n\nRestore from this data?`)) {
if (mwyvrhm_ujs.checked) {
mergeData(o);
} else watchedVideos = o;
GM_setValue("watchedVideos", JSON.stringify(watchedVideos));
a.remove();
doProcessPage();
}
}
if (window.mwyvrh_ujs) return;
(a = document.createElement("DIV")).id = "mwyvrh_ujs";
a.innerHTML = `<style>
#mwyvrh_ujs {display:flex;position:fixed;z-index:99999;left:0;top:0;right:0;bottom:0;margin:0;border:none;padding:0;background:rgb(0,0,0,0.5);color:#000;font-family:sans-serif;font-size:12pt;line-height:12pt;font-weight:normal;cursor:pointer}
#mwyvrhb_ujs {margin:auto;border:.3rem solid #007;border-radius:.3rem;padding:.5rem .5em;background-color:#fff;cursor:auto}
#mwyvrht_ujs {margin-bottom:1rem;font-size:14pt;line-height:14pt;font-weight:bold}
#mwyvrhmc_ujs {margin:.5em 0 1em 0;text-align:center}
#mwyvrhi_ujs {display:block;margin:1rem auto .5rem auto;overflow:hidden}
</style>
<div id="mwyvrhb_ujs">
<div id="mwyvrht_ujs">Mark Watched YouTube Videos</div>
Please select a file to restore history data from.
<div id="mwyvrhmc_ujs"><label><input id="mwyvrhm_ujs" type="checkbox" checked /> Merge history data instead of replace.</label></div>
<input id="mwyvrhi_ujs" type="file" multiple />
</div>`;
a.onclick = e => {
(e.target === a) && a.remove();
};
(b = a.querySelector("#mwyvrhi_ujs")).onchange = r => {
r = new FileReader();
r.onload = (o, t) => {
if (o = parseData(r = r.result)) { //parse as native format
if (o.index.length) {
askRestore(o);
} else alert("File doesn't contain any history entry.");
} else if (o = parseYouTubeData(r)) { //parse as YouTube format
if (o.index.length) {
askRestore(o);
} else alert("File doesn't contain any history entry.");
} else { //parse as URL list
o = {entries: {}, index: []};
t = (new Date()).getTime();
r = r.replace(/\r/g, "").split("\n");
while (r.length && !r[0].trim()) r.shift();
if (r.length && xu.test(r[0])) {
r.forEach(s => {
if (s = s.match(xu)) {
o.entries[s[1] || s[2]] = t;
o.index.push(s[1] || s[2]);
}
});
if (o.index.length) {
askRestore(o);
} else alert("File doesn't contain any history entry.");
} else alert("Invalid history data file.");
}
};
r.readAsText(b.files[0]);
};
document.documentElement.appendChild(a);
b.click();
});
}
function counterstuff() {
function replaceCountersText(elm) {
const renderer = elm.parentNode.renderer;
const count = renderer?.data?.viewCountText?.simpleText ?? renderer?.data?.content?.videoRenderer?.viewCountText?.simpleText;
if (count && elm.textContent != count)
elm.textContent = count;
}
const counterObserver = new MutationObserver(mutations => mutations.filter(m => m.type == "characterData").forEach(m => replaceCountersText(m.target)));
// this observer disables the like count updating while watching a live stream because it messes with a bunch of things and we can't get full like count from it either
const likeObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
while (mutation.target.childNodes.length > 1) {
mutation.target.removeChild(mutation.target.lastChild);
}
});
});
function replaceCountersEach(elm) {
elm.setAttribute("patched7kt", "");
const counters = elm.querySelectorAll("#metadata-line span");
if (counters.length != 2)
return;
counters[0].renderer = elm;
replaceCountersText(counters[0].firstChild);
counterObserver.observe(counters[0], { subtree: true, characterData: true });
}
function replaceCommentCounter(elm) {
elm.setAttribute("patched7kt", "");
const voteCount = elm.querySelector("#vote-count-middle");
if (!isNaN(voteCount.innerText))
return;
const fullCount = parseInt(elm.querySelector("#like-button button").getAttribute("aria-label").match(/\d/g).join(""));
voteCount.innerText = fullCount;
}
setInterval (function() {
document.querySelectorAll('ytd-compact-video-renderer:not([patched7kt])').forEach(replaceCountersEach);
document.querySelectorAll('ytd-grid-video-renderer:not([patched7kt])').forEach(replaceCountersEach);
document.querySelectorAll('ytd-rich-item-renderer:not([patched7kt])').forEach(replaceCountersEach);
document.querySelectorAll('ytd-video-renderer:not([patched7kt])').forEach(replaceCountersEach);
document.querySelectorAll('ytd-comment-renderer:not([patched7kt])').forEach(replaceCommentCounter);
}, 1000);
waitForElement("#info #segmented-like-button #text").then(elm => likeObserver.observe(elm, { childList: true, subtree: true }));
}
waitForElement('ytd-compact-link-renderer').then(function(elm) {
const link = document.querySelector('#container yt-multi-page-menu-section-renderer:nth-child(2) ytd-compact-link-renderer:nth-child(4)');
if (link !== null)
document.querySelector('#container yt-multi-page-menu-section-renderer:nth-child(2) ytd-compact-link-renderer:nth-child(4)').style.left = document.querySelector('[menu-style="multi-page-menu-style-type-system"] #container yt-multi-page-menu-section-renderer:first-child ytd-compact-link-renderer:nth-child(3) a').offsetWidth+"px";
});
function restoreDropdown(iconLabel, firstChild, dropdownChildren) {
const iconLabelSel = document.querySelector(iconLabel);
if (!window.location.search.includes("sort")) // channel sort dropdown fix
iconLabelSel.innerHTML = document.querySelector(firstChild)?.innerHTML;
for (const x of document.querySelectorAll(dropdownChildren)) {
x.addEventListener("click", function() {
iconLabelSel.innerHTML = this.innerHTML;
}, false);
}
}
async function setupUpdateDependentElements(e) {
if (e.detail.pageType == "watch") {
waitForElement('#top-row.ytd-video-secondary-info-renderer').then(setupSecondaryInfoRenderer);
waitForElement('#messages').then((elm) => viewCount(elm));
//waitForElement('yt-formatted-string#info.style-scope.ytd-watch-info-text').then((elm) => setUploadedText(elm));
// classic description
var description;
waitForElement('tp-yt-paper-button[id="more"]').then((elm) => elm.addEventListener("click", () => description.removeAttribute("collapsed")));
waitForElement('ytd-expander.ytd-video-secondary-info-renderer').then((elm) => { description = elm });
waitForElement('ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-structured-description"]').then((elm) => elm?.remove());
waitForElement("ytd-menu-popup-renderer tp-yt-paper-listbox").then(function(elm) {
const saveBtn = [...elm.children].find(item => item.__data.icon == "yt-icons:playlist_add");
saveBtn.classList.add("addto-btn");
});
}
if (/home|trending|subscriptions/.test(e.detail.pageType)) {
waitForElement("#endpoint.ytd-guide-entry-renderer[href^='/feed/trending'] yt-formatted-string").then(createNavBar);
document.querySelector("[hidden] .ytcp-main-appbar")?.remove();
}
waitForElement("ytd-comments-header-renderer yt-dropdown-menu:last-of-type").then(function() {
restoreDropdown("ytd-comments-header-renderer #icon-label.yt-dropdown-menu",
"ytd-comments-header-renderer a.yt-dropdown-menu:first-child > tp-yt-paper-item:first-child > tp-yt-paper-item-body:first-child > div:first-child",
"ytd-comments-header-renderer a.yt-dropdown-menu > tp-yt-paper-item:first-child > tp-yt-paper-item-body:first-child > div:first-child");
});
waitForElement("yt-sort-filter-sub-menu-renderer yt-dropdown-menu:last-of-type").then(function() {
restoreDropdown("yt-sort-filter-sub-menu-renderer #icon-label.yt-dropdown-menu",
"yt-sort-filter-sub-menu-renderer a.yt-dropdown-menu:nth-child(3) > tp-yt-paper-item:first-child > tp-yt-paper-item-body:first-child > div:first-child",
"yt-sort-filter-sub-menu-renderer a.yt-dropdown-menu > tp-yt-paper-item:first-child > tp-yt-paper-item-body:first-child > div:first-child");
});
// remove ambient mode player menu item
waitForElement("path[d='M21 7v10H3V7h18m1-1H2v12h20V6zM11.5 2v3h1V2h-1zm1 17h-1v3h1v-3zM3.79 3 6 5.21l.71-.71L4.5 2.29 3.79 3zm2.92 16.5L6 18.79 3.79 21l.71.71 2.21-2.21zM19.5 2.29 17.29 4.5l.71.71L20.21 3l-.71-.71zm0 19.42.71-.71L18 18.79l-.71.71 2.21 2.21z']")
.then(elm => elm.closest(".ytp-menuitem").remove());
}
window.addEventListener("yt-page-data-updated", removePlayerElements, false);
window.addEventListener("yt-page-data-updated", setupUpdateDependentElements, false);
// init functions
genSettings();
patch_css();
gen_history();
gen_aspect_fix();
//subbutton();
counterstuff();
tempcssfix();
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.