// ==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 }) })();