// ==UserScript==
// @name YouTube Pro: Premium Logo + Downloader + AdBlock
// @version 2025.1.15
// @description Combines YouTube Premium Logo, Multi Downloader, and AdBlock features.
// @author Evreu1pro
// @match https://*.youtube.com/*
// @match https://www.youtube.com/*
// @icon https://www.google.com/s2/favicons?domain=youtube.com
// @grant GM_addStyle
// @run-at document-idle
// @license MIT
// @icon https://www.youtube.com/s/desktop/2731d6a3/img/favicon_48x48.png
// @namespace electroknight22_youhou_premium_logo_telegram_v13
// @downloadURL https://update.greasyfork.icu/scripts/556610/YouTube%20Pro%3A%20Premium%20Logo%20%2B%20Downloader%20%2B%20AdBlock.user.js
// @updateURL https://update.greasyfork.icu/scripts/556610/YouTube%20Pro%3A%20Premium%20Logo%20%2B%20Downloader%20%2B%20AdBlock.meta.js
// ==/UserScript==
// --- MODULE 1: YouTube Premium Logo ---
(function () {
'use strict';
// fix "TrustedError" on chrome[-ium], code snippet from zerodytrash/Simple-YouTube-Age-Restriction-Bypass@d2cbcc0
if (window.trustedTypes && trustedTypes.createPolicy) {
if (!trustedTypes.defaultPolicy) {
const passThroughFn = (x) => x;
trustedTypes.createPolicy('default', {
createHTML: passThroughFn,
createScriptURL: passThroughFn,
createScript: passThroughFn,
});
}
}
// Add load event listener to only spawn MutationObserver when the web actually loaded
window.addEventListener('load', () => {
// Function to be called when the target element is found
function modifyYtIcon(ytdLogos) {
ytdLogos.forEach(ytdLogo => {
const ytdLogoSvg = ytdLogo.querySelector("svg");
// Safety check
if (!ytdLogoSvg) return;
ytdLogoSvg.setAttribute('width', '101');
ytdLogoSvg.setAttribute('viewBox', '0 0 101 20');
ytdLogoSvg.closest('ytd-logo').setAttribute('is-red-logo', '');
ytdLogoSvg.innerHTML = '';
});
// Disconnect the observer once the element is found
observer.disconnect();
}
// Function to check if the target element exists and call the modification function
function checkYtIconExistence() {
let ytdLogos = document.querySelectorAll("ytd-logo > yt-icon > span > div");
const pfp = document.querySelector("#avatar-btn");
const signInBtn = document.querySelector("a[href^='https://accounts.google.com']");
if (pfp && ytdLogos.length == 4) {
// run in the next event cycle to make sure the logo is fully loaded
setTimeout(() => {
// grab it again just in case youtube swapped them
ytdLogos = document.querySelectorAll("ytd-logo > yt-icon > span > div");
modifyYtIcon(ytdLogos);
}, 50)
} else if (signInBtn) {
// dont apply the premium logo to non-logged in user
// and disconnect the observer
observer.disconnect();
};
}
// Observe changes in the DOM
const observer = new MutationObserver(checkYtIconExistence);
// Start observing the document
observer.observe(document.body, { childList: true, subtree: true });
// Call the function once at the beginning in case the element is already present
checkYtIconExistence();
});
})();
// --- MODULE 2: Multi Downloader ---
(function () {
var punisherYT = "//gotofreight.ca/convert/?id=";
var tubeID = "dwnldBtn";
var telegramID = "telegramBtn"; // New button ID
var currentButton = "#owner";
var addClick = `
#${tubeID}, #${telegramID} {
background-color: #F1F1F1;
color: #191919;
border: 1px solid;
border-color: rgba(255,255,255,0.2);
margin-left: 8px;
padding: 0 16px;
border-radius: 18px;
font-size: 14px;
font-family: Roboto, Noto, sans-serif;
font-weight: 500;
text-decoration: none;
display: inline-flex;
align-items: center;
height: 36px;
line-height: normal;
}
#${tubeID}:hover, #${telegramID}:hover {
background-color: #D9D9D9;
color: #191919;
border-color: #F1F1F1;
}
`;
// Polyfill for GM_addStyle if not available (e.g. testing in console)
if (typeof GM_addStyle !== "undefined") {
GM_addStyle(addClick);
} else {
const style = document.createElement('style');
style.textContent = addClick;
(document.head || document.documentElement).appendChild(style);
}
function inspectPg(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
var observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
});
}
function addBtn() {
inspectPg(currentButton).then((btnContainer) => {
if (!btnContainer) {
return;
}
if (document.querySelector(`#${tubeID}`)) {
} else {
var downloadBtn = document.createElement('a');
downloadBtn.href = `${punisherYT + decodeURIComponent(extractYT(window.location))}`;
downloadBtn.target = '_blank';
downloadBtn.id = tubeID;
downloadBtn.innerText = 'Download';
btnContainer.appendChild(downloadBtn);
// Add Telegram Button
var telegramBtn = document.createElement('a');
telegramBtn.href = 'https://t.me/gostibissi';
telegramBtn.target = '_blank';
telegramBtn.id = telegramID;
telegramBtn.innerText = 'More Scripts';
btnContainer.appendChild(telegramBtn);
}
});
}
function pageLoad() {
inspectPg(`#${tubeID}`).then((btn) => {
if (!btn) {
return;
}
btn.href = punisherYT + decodeURIComponent(extractYT(window.location));
});
}
var extractYT = function (url) {
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
var match = String(url).match(regExp);
return (match && match[7].length == 11) ? match[7] : false;
}
let buttonSet = false;
function checkButton() {
if (window.location.pathname === '/watch' && !buttonSet) {
addBtn();
buttonSet = true;
setTimeout(pageLoad, 2000);
}
}
window.addEventListener("yt-navigate-finish", () => {
buttonSet = false;
checkButton();
});
checkButton();
})();
// --- MODULE 3: AdBlocker (youtube-adb) ---
(function () {
`use strict`;
let video;
// Interface ad selector
const cssSelectorArr = [
`#masthead-ad`, // Homepage Masthead Ad
`ytd-rich-item-renderer.style-scope.ytd-rich-grid-row #content:has(.ytd-display-ad-renderer)`, // Homepage Video Feed Ad
`.video-ads.ytp-ad-module`, // Player Bottom Ad
`tp-yt-paper-dialog:has(yt-mealbar-promo-renderer)`, // Watch Page Member Promo Ad
`ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]`, // Watch Page Top Right Ad
`#related #player-ads`, // Watch Page Comment Section Right Ad
`#related ytd-ad-slot-renderer`, // Watch Page Comment Section Right Video Ad
`ytd-ad-slot-renderer`, // Search Page Ad
`yt-mealbar-promo-renderer`, // Watch Page Member Recommendation Ad
`ytd-popup-container:has(a[href="/premium"])`, // Member Interception Ad
`ad-slot-renderer`, // Mobile Watch Page Third Party Ad
`ytm-companion-ad-renderer`, // Mobile Skippable Video Ad Link
];
window.dev = false; // Development usage
/**
* Format standard time
* @param {Date} time Standard time
* @param {String} format Format
* @return {String}
*/
function moment(time) {
// Get YYYY-MM-DD HH:MM:SS
let y = time.getFullYear()
let m = (time.getMonth() + 1).toString().padStart(2, `0`)
let d = time.getDate().toString().padStart(2, `0`)
let h = time.getHours().toString().padStart(2, `0`)
let min = time.getMinutes().toString().padStart(2, `0`)
let s = time.getSeconds().toString().padStart(2, `0`)
return `${y}-${m}-${d} ${h}:${min}:${s}`
}
/**
* Output message
* @param {String} msg Message
* @return {undefined}
*/
function log(msg) {
if (!window.dev) {
return false;
}
console.log(window.location.href);
console.log(`${moment(new Date())} ${msg}`);
}
/**
* Set run flag
* @param {String} name
* @return {undefined}
*/
function setRunFlag(name) {
let style = document.createElement(`style`);
style.id = name;
(document.head || document.body).appendChild(style); // Append node to HTML
}
/**
* Get run flag
* @param {String} name
* @return {undefined|Element}
*/
function getRunFlag(name) {
return document.getElementById(name);
}
/**
* Check if run flag is set
* @param {String} name
* @return {Boolean}
*/
function checkRunFlag(name) {
if (getRunFlag(name)) {
return true;
} else {
setRunFlag(name)
return false;
}
}
/**
* Generate CSS style element to remove ads and append to HTML
* @param {String} styles Style text
* @return {undefined}
*/
function generateRemoveADHTMLElement(id) {
// If already set, exit
if (checkRunFlag(id)) {
log(`Ad removal node generated`);
return false
}
// Set remove ad styles
let style = document.createElement(`style`); // Create style element
(document.head || document.body).appendChild(style); // Append node to HTML
style.appendChild(document.createTextNode(generateRemoveADCssText(cssSelectorArr))); // Append style text to element
log(`Successfully generated ad removal node`);
}
/**
* Generate CSS text to remove ads
* @param {Array} cssSelectorArr Array of CSS selectors
* @return {String}
*/
function generateRemoveADCssText(cssSelectorArr) {
cssSelectorArr.forEach((selector, index) => {
cssSelectorArr[index] = `${selector}{display:none!important}`; // Iterate and set styles
});
return cssSelectorArr.join(` `); // Join into string
}
/**
* Touch event
* @return {undefined}
*/
function nativeTouch() {
// Create Touch Object
let touch = new Touch({
identifier: Date.now(),
target: this,
clientX: 12,
clientY: 34,
radiusX: 56,
radiusY: 78,
rotationAngle: 0,
force: 1
});
// Create TouchEvent Object
let touchStartEvent = new TouchEvent(`touchstart`, {
bubbles: true,
cancelable: true,
view: window,
touches: [touch],
targetTouches: [touch],
changedTouches: [touch]
});
// Dispatch touchstart event to target
this.dispatchEvent(touchStartEvent);
// Create TouchEvent Object
let touchEndEvent = new TouchEvent(`touchend`, {
bubbles: true,
cancelable: true,
view: window,
touches: [],
targetTouches: [],
changedTouches: [touch]
});
// Dispatch touchend event to target
this.dispatchEvent(touchEndEvent);
}
/**
* Get DOM
* @return {undefined}
*/
function getVideoDom() {
video = document.querySelector(`.ad-showing video`) || document.querySelector(`video`);
}
/**
* Auto play
* @return {undefined}
*/
function playAfterAd() {
if (!video) return;
if (video.paused && video.currentTime < 1) {
video.play();
log(`Auto playing video`);
}
}
/**
* Remove YT ad interception popup and close overlay backdrop
* @return {undefined}
*/
function closeOverlay() {
// Remove YT ad interception popup
const premiumContainers = [...document.querySelectorAll(`ytd-popup-container`)];
const matchingContainers = premiumContainers.filter(container => container.querySelector(`a[href="/premium"]`));
if (matchingContainers.length > 0) {
matchingContainers.forEach(container => container.remove());
log(`Removed YT interceptor`);
}
// Get all elements with specified tag
const backdrops = document.querySelectorAll(`tp-yt-iron-overlay-backdrop`);
// Find element with specific style
const targetBackdrop = Array.from(backdrops).find(
(backdrop) => backdrop.style.zIndex === `2201`
);
// If found, clear class and remove open attribute
if (targetBackdrop) {
targetBackdrop.className = ``; // Clear all classes
targetBackdrop.removeAttribute(`opened`); // Remove open attribute
log(`Closed overlay backdrop`);
}
}
/**
* Skip ad
* @return {undefined}
*/
function skipAd(mutationsList, observer) {
const skipButton = document.querySelector(`.ytp-ad-skip-button`) || document.querySelector(`.ytp-skip-ad-button`) || document.querySelector(`.ytp-ad-skip-button-modern`);
const shortAdMsg = document.querySelector(`.video-ads.ytp-ad-module .ytp-ad-player-overlay`) || document.querySelector(`.ytp-ad-button-icon`);
if ((skipButton || shortAdMsg) && window.location.href.indexOf(`https://m.youtube.com/`) === -1) { // Mobile mute bug
if (video) video.muted = true;
}
if (skipButton) {
const delayTime = 0.5;
setTimeout(skipAd, delayTime * 1000); // If click and call didn't skip, change ad time directly
if (video && video.currentTime > delayTime) {
video.currentTime = video.duration; // Force
log(`Special account skipped button ad`);
return;
}
skipButton.click(); // PC
nativeTouch.call(skipButton); // Phone
log(`Button skipped ad`);
} else if (shortAdMsg) {
if (video) video.currentTime = video.duration; // Force
log(`Forced ad end`);
}
}
/**
* Remove playing ads
* @return {undefined}
*/
function removePlayerAD(id) {
// If already running, exit
if (checkRunFlag(id)) {
log(`Remove playing ads function already running`);
return false
}
// Monitor and handle ads in video
const targetNode = document.body; // Directly observe body changes
const config = { childList: true, subtree: true }; // Observe target node and subtree changes
const observer = new MutationObserver(() => { getVideoDom(); closeOverlay(); skipAd(); playAfterAd(); }); // Handle video ad related
observer.observe(targetNode, config); // Start observing ad nodes with config
log(`Successfully started remove playing ads function`);
}
/**
* Main function
*/
function main() {
generateRemoveADHTMLElement(`removeADHTMLElement`); // Remove interface ads
removePlayerAD(`removePlayerAD`); // Remove playing ads
}
if (document.readyState === `loading`) {
document.addEventListener(`DOMContentLoaded`, main); // Loading not yet complete
log(`YouTube AdBlock script about to call:`);
} else {
main(); // DOMContentLoaded already triggered
log(`YouTube AdBlock script quick call:`);
}
let resumeVideo = () => {
const videoelem = document.body.querySelector('video.html5-main-video')
if (videoelem && videoelem.paused) {
console.log('resume video')
videoelem.play()
}
}
let removePop = node => {
const elpopup = node.querySelector('.ytd-popup-container > .ytd-popup-container > .ytd-enforcement-message-view-model')
if (elpopup) {
elpopup.parentNode.remove()
console.log('remove popup', elpopup)
const bdelems = document
.getElementsByTagName('tp-yt-iron-overlay-backdrop')
for (var x = (bdelems || []).length; x--;)
bdelems[x].remove()
resumeVideo()
}
if (node.tagName.toLowerCase() === 'tp-yt-iron-overlay-backdrop') {
node.remove()
resumeVideo()
console.log('remove backdrop', node)
}
}
let obs = new MutationObserver(mutations => mutations.forEach(mutation => {
if (mutation.type === 'childList') {
Array.from(mutation.addedNodes)
.filter(node => node.nodeType === 1)
.map(node => removePop(node))
}
}))
// have the observer observe foo for changes in children
obs.observe(document.body, {
childList: true,
subtree: true
})
})();