Combines Premium Logo, HD quality lock, Native Downloader, Settings Menu, and replaces "Thanks" with a Telegram link. Fixed freezing issues.
// ==UserScript==
// @name YouTube All-in-One: Premium Logo, HD, Downloader & Telegram (Stable)
// @name:ru YouTube Всё-в-одном: Premium Лого, HD, Скачивание и Телеграм (Стабильный)
// @namespace electroknight22_youhou_premium_logo_telegram_v13
// @version 2025.1.13
// @description Combines Premium Logo, HD quality lock, Native Downloader, Settings Menu, and replaces "Thanks" with a Telegram link. Fixed freezing issues.
// @description:ru Исправлены фризы и ошибки 500. Меняет лого на Premium, фиксирует HD (без спама), добавляет скачивание и ссылку на Telegram.
// @author Evreu1pro
// @match *://www.youtube.com/*
// @match *://m.youtube.com/*
// @match *://www.youtube-nocookie.com/*
// @exclude *://www.youtube.com/live_chat*
// @grant GM_addStyle
// @run-at document-idle
// @license MIT
// @icon https://www.youtube.com/s/desktop/2731d6a3/img/favicon_48x48.png
// ==/UserScript==
(function () {
'use strict';
// ==========================================
// ЧАСТЬ 1: ПРЕМИУМ ЛОГОТИП (CSS)
// ==========================================
const premiumLogoCSS = `
#logo-container .logo, .footer-logo-icon, #logo-icon, #logo-icon-container {
width: 98px !important; margin-left: 5px; margin-right: 5px;
content: url("data:image/svg+xml,%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' id='SVGRoot' version='1.1' viewBox='0 0 846 174' height='80px' width='391px'%3E%3Cdefs id='defs855'%3E%3Cstyle id='style2' /%3E%3C/defs%3E%3Cg id='layer1'%3E%3Cg transform='translate(0,0.36)' data-name='Layer 2' id='Layer_2'%3E%3Cg data-name='Layer 1' id='Layer_1-2'%3E%3Cpath style='fill:%23ff0000' id='path6' d='M 242.88,27.11 A 31.07,31.07 0 0 0 220.95,5.18 C 201.6,0 124,0 124,0 124,0 46.46,0 27.11,5.18 A 31.07,31.07 0 0 0 5.18,27.11 C 0,46.46 0,86.82 0,86.82 c 0,0 0,40.36 5.18,59.71 a 31.07,31.07 0 0 0 21.93,21.93 c 19.35,5.18 96.92,5.18 96.92,5.18 0,0 77.57,0 96.92,-5.18 a 31.07,31.07 0 0 0 21.93,-21.93 c 5.18,-19.35 5.18,-59.71 5.18,-59.71 0,0 0,-40.36 -5.18,-59.71 z' /%3E%3Cpath style='fill:%23ffffff' id='path8' d='M 99.22,124.03 163.67,86.82 99.22,49.61 Z' /%3E%3Cpath style='fill:%23282828' id='path10' d='m 358.29,55.1 v 6 c 0,30 -13.3,47.53 -42.39,47.53 h -4.43 v 52.5 H 287.71 V 12.36 H 318 c 27.7,0 40.29,11.71 40.29,42.74 z m -25,2.13 c 0,-21.64 -3.9,-26.78 -17.38,-26.78 h -4.43 v 60.48 h 4.08 c 12.77,0 17.74,-9.22 17.74,-29.26 z m 81.22,-6.56 -1.24,28.2 c -10.11,-2.13 -18.45,-0.53 -22.17,6 v 76.26 H 367.52 V 52.44 h 18.8 L 388.45,76 h 0.89 c 2.48,-17.2 10.46,-25.89 20.75,-25.89 a 22.84,22.84 0 0 1 4.42,0.56 z M 441.64,115 v 5.5 c 0,19.16 1.06,25.72 9.22,25.72 7.8,0 9.58,-6 9.75,-18.44 l 21.1,1.24 c 1.6,23.41 -10.64,33.87 -31.39,33.87 -25.18,0 -32.63,-16.49 -32.63,-46.46 v -19 c 0,-31.57 8.34,-47 33.34,-47 25.18,0 31.57,13.12 31.57,45.93 V 115 Z m 0,-22.35 v 7.8 h 17.91 V 92.7 c 0,-20 -1.42,-25.72 -9,-25.72 -7.58,0 -8.91,5.86 -8.91,25.72 z M 604.45,79 v 82.11 H 580 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8.16,2.48 -10.82,7.09 a 35.59,35.59 0 0 1 0.18,4.43 v 82.11 H 537.24 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8,2.48 -10.64,6.92 v 86.72 H 494.5 V 52.44 h 19.33 L 516,66.28 h 0.35 c 5.5,-10.46 14.37,-16.14 24.83,-16.14 10.29,0 16.14,5.14 18.8,14.37 5.68,-9.4 14.19,-14.37 23.94,-14.37 14.86,0 20.53,10.64 20.53,28.86 z m 12.24,-54.4 c 0,-11.71 4.26,-15.07 13.3,-15.07 9.22,0 13.3,3.9 13.3,15.07 0,12.06 -4.08,15.08 -13.3,15.08 -9.04,-0.01 -13.3,-3.02 -13.3,-15.08 z m 1.42,27.84 h 23.41 v 108.72 h -23.41 z m 103.39,0 v 108.72 h -19.15 l -2.13,-13.3 h -0.53 c -5.5,10.64 -13.48,15.07 -23.41,15.07 -14.54,0 -21.11,-9.22 -21.11,-29.26 V 52.44 h 24.47 v 79.81 c 0,9.58 2,13.48 6.92,13.48 A 12.09,12.09 0 0 0 697,138.81 V 52.44 Z M 845.64,79 v 82.11 H 821.17 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8.16,2.48 -10.82,7.09 A 35.59,35.59 0 0 1 802.9,79 v 82.11 H 778.43 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8,2.48 -10.64,6.92 v 86.72 H 735.69 V 52.44 H 755 l 2.13,13.83 h 0.35 c 5.5,-10.46 14.37,-16.14 24.83,-16.14 10.29,0 16.14,5.14 18.8,14.37 5.68,-9.4 14.19,-14.37 23.94,-14.37 14.95,0.01 20.59,10.65 20.59,28.87 z' /%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E") !important;
}
html[dark] #logo-icon, html[dark] #logo-icon-container {
width: 98px !important;
content: url("data:image/svg+xml,%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' id='SVGRoot' version='1.1' viewBox='0 0 846 174' height='24px' width='98px'%3E%3Cdefs id='defs855'%3E%3Cstyle id='style2' /%3E%3C/defs%3E%3Cg id='layer1'%3E%3Cg transform='translate(0,0.36)' data-name='Layer 2' id='Layer_2'%3E%3Cg data-name='Layer 1' id='Layer_1-2'%3E%3Cpath style='fill:%23ff0000' id='path6' d='M 242.88,27.11 A 31.07,31.07 0 0 0 220.95,5.18 C 201.6,0 124,0 124,0 124,0 46.46,0 27.11,5.18 A 31.07,31.07 0 0 0 5.18,27.11 C 0,46.46 0,86.82 0,86.82 c 0,0 0,40.36 5.18,59.71 a 31.07,31.07 0 0 0 21.93,21.93 c 19.35,5.18 96.92,5.18 96.92,5.18 0,0 77.57,0 96.92,-5.18 a 31.07,31.07 0 0 0 21.93,-21.93 c 5.18,-19.35 5.18,-59.71 5.18,-59.71 0,0 0,-40.36 -5.18,-59.71 z' /%3E%3Cpath style='fill:%23ffffff' id='path8' d='M 99.22,124.03 163.67,86.82 99.22,49.61 Z' /%3E%3Cpath style='fill:%23ffffff' id='path10' d='m 358.29,55.1 v 6 c 0,30 -13.3,47.53 -42.39,47.53 h -4.43 v 52.5 H 287.71 V 12.36 H 318 c 27.7,0 40.29,11.71 40.29,42.74 z m -25,2.13 c 0,-21.64 -3.9,-26.78 -17.38,-26.78 h -4.43 v 60.48 h 4.08 c 12.77,0 17.74,-9.22 17.74,-29.26 z m 81.22,-6.56 -1.24,28.2 c -10.11,-2.13 -18.45,-0.53 -22.17,6 v 76.26 H 367.52 V 52.44 h 18.8 L 388.45,76 h 0.89 c 2.48,-17.2 10.46,-25.89 20.75,-25.89 a 22.84,22.84 0 0 1 4.42,0.56 z M 441.64,115 v 5.5 c 0,19.16 1.06,25.72 9.22,25.72 7.8,0 9.58,-6 9.75,-18.44 l 21.1,1.24 c 1.6,23.41 -10.64,33.87 -31.39,33.87 -25.18,0 -32.63,-16.49 -32.63,-46.46 v -19 c 0,-31.57 8.34,-47 33.34,-47 25.18,0 31.57,13.12 31.57,45.93 V 115 Z m 0,-22.35 v 7.8 h 17.91 V 92.7 c 0,-20 -1.42,-25.72 -9,-25.72 -7.58,0 -8.91,5.86 -8.91,25.72 z M 604.45,79 v 82.11 H 580 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8.16,2.48 -10.82,7.09 a 35.59,35.59 0 0 1 0.18,4.43 v 82.11 H 537.24 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8,2.48 -10.64,6.92 v 86.72 H 494.5 V 52.44 h 19.33 L 516,66.28 h 0.35 c 5.5,-10.46 14.37,-16.14 24.83,-16.14 10.29,0 16.14,5.14 18.8,14.37 5.68,-9.4 14.19,-14.37 23.94,-14.37 14.86,0 20.53,10.64 20.53,28.86 z m 12.24,-54.4 c 0,-11.71 4.26,-15.07 13.3,-15.07 9.22,0 13.3,3.9 13.3,15.07 0,12.06 -4.08,15.08 -13.3,15.08 -9.04,-0.01 -13.3,-3.02 -13.3,-15.08 z m 1.42,27.84 h 23.41 v 108.72 h -23.41 z m 103.39,0 v 108.72 h -19.15 l -2.13,-13.3 h -0.53 c -5.5,10.64 -13.48,15.07 -23.41,15.07 -14.54,0 -21.11,-9.22 -21.11,-29.26 V 52.44 h 24.47 v 79.81 c 0,9.58 2,13.48 6.92,13.48 A 12.09,12.09 0 0 0 697,138.81 V 52.44 Z M 845.64,79 v 82.11 H 821.17 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8.16,2.48 -10.82,7.09 A 35.59,35.59 0 0 1 802.9,79 v 82.11 H 778.43 V 80.82 c 0,-8.87 -2.31,-13.3 -7.63,-13.3 -4.26,0 -8,2.48 -10.64,6.92 v 86.72 H 735.69 V 52.44 H 755 l 2.13,13.83 h 0.35 c 5.5,-10.46 14.37,-16.14 24.83,-16.14 10.29,0 16.14,5.14 18.8,14.37 5.68,-9.4 14.19,-14.37 23.94,-14.37 14.95,0.01 20.59,10.65 20.59,28.87 z' /%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E") !important;
}
`;
if (typeof GM_addStyle === 'function') {
GM_addStyle(premiumLogoCSS);
} else {
const style = document.createElement('style');
style.textContent = premiumLogoCSS;
document.head.append(style);
}
// ==========================================
// ЧАСТЬ 2: ХРАНИЛИЩЕ И УТИЛИТЫ
// ==========================================
const PREF_KEY = 'yt_target_quality_v13';
const Storage = {
get: (key, def) => localStorage.getItem(key) || def,
set: (key, val) => localStorage.setItem(key, val)
};
const safeEmpty = (element) => {
while (element.firstChild) element.removeChild(element.firstChild);
};
const createSVG = (dPath) => {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("height", "24");
svg.setAttribute("width", "24");
svg.setAttribute("viewBox", "0 0 24 24");
svg.setAttribute("fill", "currentColor");
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", dPath);
svg.appendChild(path);
return svg;
};
const createElem = (tag, className, text = null) => {
const el = document.createElement(tag);
if (className) el.className = className;
if (text) el.textContent = text;
return el;
};
const ICONS_PATHS = {
pin: "M16,12V4H17V2H7V4H8V12L6,14V16H11.5V22H12.5V16H18V14L16,12Z",
check: "M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z",
back: "M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z",
download: "M17 18v1H6v-1h11zm-.5-6.6-.7-.7-3.8 3.7V4h-1v10.4l-3.8-3.8-.7.7 5 5 5-4.9z",
telegram: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69.01-.03.01-.14-.07-.2-.08-.06-.19-.04-.27-.02-.12.02-1.96 1.25-5.54 3.69-.52.36-1 .53-1.42.52-.47-.01-1.37-.26-2.03-.48-.82-.27-1.47-.42-1.42-.88.03-.24.29-.48.79-.74 3.08-1.34 5.15-2.23 6.21-2.66 2.95-1.23 3.56-1.43 3.97-1.43.09 0 .28.02.41.12.13.1.16.23.17.38z",
thanks: "M16.25 2"
};
const I18N = {
'en': { download: 'Download', quality: 'Preferred Quality', scripts: 'Scripts' },
'ru': { download: 'Скачать', quality: 'Качество видео', scripts: 'Скрипты' },
'de': { download: 'Herunterladen', quality: 'Videoqualität', scripts: 'Skripte' },
'es': { download: 'Descargar', quality: 'Calidad preferida', scripts: 'Scripts' },
'fr': { download: 'Télécharger', quality: 'Qualité préférée', scripts: 'Scripts' },
'ja': { download: 'ダウンロード', quality: '希望する画質', scripts: 'スクリプト' },
'zh': { download: '下载', quality: '首选画质', scripts: '脚本' },
'uk': { download: 'Завантажити', quality: 'Бажана якість', scripts: 'Скрипти' }
};
function getLang() {
const code = document.documentElement.lang || navigator.language || 'en';
return I18N[code.split('-')[0]] || I18N['en'];
}
const QUALITY_LEVELS = {
'highres': 'Max (4K/8K)',
'hd2160': '2160p (4K)',
'hd1440': '1440p (2K)',
'hd1080': '1080p (HD)',
'hd720': '720p',
'large': '480p',
'medium': '360p'
};
// ==========================================
// ЧАСТЬ 3: МОДУЛЬ HD (БЕЗ ФРИЗОВ)
// ==========================================
let hasQualityBeenSet = false; // Флаг: ставили ли уже качество для этого видео
function forceVideoQuality(isManual = false) {
const player = document.getElementById('movie_player');
if (!player || typeof player.setPlaybackQualityRange !== 'function') return;
// Если автоматика уже сработала один раз, не трогаем плеер, чтобы не сбивать буфер
if (!isManual && hasQualityBeenSet) return;
try {
const target = Storage.get(PREF_KEY, 'highres');
const available = player.getAvailableQualityLevels();
if (!available || !available.length) return;
let targetQualityVal = (target === 'highres') ? available[0] : target;
if (!available.includes(targetQualityVal)) targetQualityVal = available[0];
const currentQuality = player.getPlaybackQuality();
// Применяем только если отличается
if (currentQuality !== targetQualityVal || isManual) {
console.log(`[YouTube Script] Setting quality to: ${targetQualityVal}`);
player.setPlaybackQualityRange(targetQualityVal, targetQualityVal);
player.setPlaybackQuality(targetQualityVal);
hasQualityBeenSet = true;
}
} catch (e) {
console.warn('[YouTube Script] Error setting quality', e);
}
}
function initHDLogic() {
// Сбрасываем флаг при смене видео
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
hasQualityBeenSet = false; // Новое видео - можно один раз поставить качество
}
}).observe(document, {subtree: true, childList: true});
const observer = new MutationObserver(() => {
const player = document.getElementById('movie_player');
if (player) {
if (!player.dataset.qualityLocked) {
player.addEventListener('onStateChange', (state) => {
// 1 = playing. Мы больше НЕ слушаем state === 3 (buffering), чтобы не вызывать петлю.
if (state === 1) {
setTimeout(() => forceVideoQuality(), 500);
}
});
player.dataset.qualityLocked = "true";
}
// Первая попытка при загрузке
setTimeout(() => forceVideoQuality(), 1500);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// ==========================================
// ЧАСТЬ 4: ИНТЕГРАЦИЯ В МЕНЮ
// ==========================================
function injectSettingsMenu() {
document.addEventListener('click', (e) => {
const settingsBtn = e.target.closest('.ytp-settings-button');
if (settingsBtn) {
setTimeout(addMenuItem, 50);
setTimeout(addMenuItem, 500);
}
}, true);
}
function addMenuItem() {
const menu = document.querySelector('.ytp-settings-menu .ytp-panel-menu');
if (!menu || document.getElementById('yt-pref-quality-item')) return;
const lang = getLang();
const currentVal = Storage.get(PREF_KEY, 'highres');
const currentLabel = QUALITY_LEVELS[currentVal] || currentVal;
const menuItem = createElem('div', 'ytp-menuitem');
menuItem.id = 'yt-pref-quality-item';
menuItem.setAttribute('role', 'menuitem');
menuItem.setAttribute('tabindex', '0');
const iconDiv = createElem('div', 'ytp-menuitem-icon');
iconDiv.appendChild(createSVG(ICONS_PATHS.pin));
const labelDiv = createElem('div', 'ytp-menuitem-label', lang.quality);
const contentDiv = createElem('div', 'ytp-menuitem-content');
const valueDiv = createElem('div', 'ytp-menuitem-value', currentLabel);
contentDiv.appendChild(valueDiv);
menuItem.appendChild(iconDiv);
menuItem.appendChild(labelDiv);
menuItem.appendChild(contentDiv);
menuItem.onclick = () => openSubMenu(menu);
if (menu.firstChild) menu.insertBefore(menuItem, menu.children[1] || menu.firstChild);
else menu.appendChild(menuItem);
const panel = menu.closest('.ytp-panel');
if (panel) panel.style.height = '';
}
function openSubMenu(mainMenu) {
const panel = mainMenu.closest('.ytp-panel');
if (!panel) return;
mainMenu.style.display = 'none';
let subMenu = document.getElementById('yt-pref-quality-submenu');
if (subMenu) safeEmpty(subMenu);
else {
subMenu = createElem('div', 'ytp-panel-menu');
subMenu.id = 'yt-pref-quality-submenu';
panel.appendChild(subMenu);
}
subMenu.style.display = 'block';
const header = createElem('div', 'ytp-panel-header');
header.style.cssText = 'padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,0.1); display: flex; align-items: center; cursor: pointer;';
const titleDiv = createElem('div', 'ytp-panel-title');
titleDiv.style.display = 'flex'; titleDiv.style.alignItems = 'center';
const backIconSpan = createElem('span');
backIconSpan.style.marginRight = '10px';
backIconSpan.appendChild(createSVG(ICONS_PATHS.back));
titleDiv.appendChild(backIconSpan);
titleDiv.appendChild(document.createTextNode(getLang().quality));
header.appendChild(titleDiv);
header.onclick = () => {
subMenu.style.display = 'none'; mainMenu.style.display = 'block'; subMenu.remove();
const currentVal = Storage.get(PREF_KEY, 'highres');
const itemValue = document.querySelector('#yt-pref-quality-item .ytp-menuitem-value');
if (itemValue) itemValue.textContent = QUALITY_LEVELS[currentVal];
};
subMenu.appendChild(header);
const currentVal = Storage.get(PREF_KEY, 'highres');
Object.keys(QUALITY_LEVELS).forEach(key => {
const option = createElem('div', 'ytp-menuitem');
option.setAttribute('role', 'menuitemradio'); option.setAttribute('tabindex', '0');
const isChecked = currentVal === key;
option.setAttribute('aria-checked', isChecked);
const label = createElem('div', 'ytp-menuitem-label', QUALITY_LEVELS[key]);
label.style.paddingLeft = '15px';
const content = createElem('div', 'ytp-menuitem-content');
if (isChecked) content.appendChild(createSVG(ICONS_PATHS.check));
option.appendChild(label); option.appendChild(content);
option.onclick = () => {
Storage.set(PREF_KEY, key);
forceVideoQuality(true); // Manual override
header.click();
};
subMenu.appendChild(option);
});
panel.style.height = `${subMenu.scrollHeight}px`;
}
// ==========================================
// ЧАСТЬ 5: МОДУЛЬ КНОПОК (СКАЧАТЬ И TELEGRAM)
// ==========================================
function getDownloadUrl() { return window.location.href.replace('youtube.com', 'addyoutube.com'); }
function modifyButton(buttonElement, type) {
const lang = getLang();
buttonElement.onclick = (e) => {
e.preventDefault(); e.stopPropagation();
if (type === 'download') window.open(getDownloadUrl(), '_blank');
if (type === 'telegram') window.open('https://t.me/gostibissi', '_blank');
};
const svg = buttonElement.querySelector('svg');
if (svg) {
safeEmpty(svg);
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", type === 'download' ? ICONS_PATHS.download : ICONS_PATHS.telegram);
path.setAttribute("fill", "currentColor");
svg.appendChild(path);
}
const textSpan = buttonElement.querySelector('yt-formatted-string') ||
buttonElement.querySelector('.yt-spec-button-shape-next__button-text-content span');
if (textSpan) textSpan.textContent = type === 'download' ? lang.download : lang.scripts;
const tooltip = buttonElement.closest(type === 'download' ? 'ytd-download-button-renderer' : 'ytd-button-renderer, yt-button-view-model')?.querySelector('tp-yt-paper-tooltip');
if (tooltip && tooltip.textContent) tooltip.textContent = type === 'download' ? lang.download : lang.scripts;
const anchor = buttonElement.querySelector('a');
if (anchor) { anchor.removeAttribute('href'); anchor.removeAttribute('target'); }
}
function processButtons() {
// 1. Download Button
const nativeDownload = document.querySelector('ytd-download-button-renderer');
if (nativeDownload) {
if (nativeDownload.dataset.replaced !== "true") {
const originalButton = nativeDownload.querySelector('button');
if (originalButton) {
const newButton = originalButton.cloneNode(true);
modifyButton(newButton, 'download');
originalButton.parentNode.replaceChild(newButton, originalButton);
nativeDownload.dataset.replaced = "true";
}
}
} else {
if (!document.getElementById('custom-download-btn')) createCustomButton('download');
}
// 2. Telegram Button (Replace Thanks or Add New)
const buttonsContainer = document.querySelector('#top-level-buttons-computed');
if (!buttonsContainer) return;
let thanksButton = null;
// ПОИСК: Ищем среди всех возможных контейнеров кнопок (включая новые view-model)
const candidates = buttonsContainer.querySelectorAll('ytd-button-renderer, yt-button-view-model');
for (const btn of candidates) {
// Проверка по иконке
const path = btn.querySelector('path');
if (path && path.getAttribute('d') && path.getAttribute('d').startsWith(ICONS_PATHS.thanks)) {
thanksButton = btn;
break;
}
}
if (thanksButton && thanksButton.dataset.replaced !== "true") {
// Замена
const newTelegram = thanksButton.cloneNode(true);
const innerBtn = newTelegram.querySelector('button');
if (innerBtn) modifyButton(innerBtn, 'telegram');
thanksButton.parentNode.replaceChild(newTelegram, thanksButton);
newTelegram.dataset.replaced = "true";
} else if (!thanksButton && !document.getElementById('custom-telegram-btn')) {
// Если кнопки Спасибо нет вообще, добавляем свою
createCustomButton('telegram');
}
}
function createCustomButton(type) {
const id = type === 'download' ? 'custom-download-btn' : 'custom-telegram-btn';
if (document.getElementById(id)) return;
const menuRenderer = document.querySelector('ytd-menu-renderer');
if (!menuRenderer) return;
const baseButton = menuRenderer.querySelector('ytd-button-renderer button') ||
menuRenderer.querySelector('yt-button-view-model button');
if (!baseButton) return;
const buttonRenderer = baseButton.closest('ytd-button-renderer') || baseButton.closest('yt-button-view-model');
const newRenderer = buttonRenderer.cloneNode(true);
newRenderer.id = id;
const innerBtn = newRenderer.querySelector('button');
if(innerBtn) modifyButton(innerBtn, type);
const buttonsContainer = menuRenderer.querySelector('#top-level-buttons-computed');
if (buttonsContainer) {
buttonsContainer.appendChild(newRenderer);
}
}
function initButtons() {
const observer = new MutationObserver(() => {
if (window.location.pathname.includes('/watch')) {
processButtons();
}
});
observer.observe(document.body, { childList: true, subtree: true });
if (window.location.pathname.includes('/watch')) {
setTimeout(processButtons, 1000); setTimeout(processButtons, 3000);
}
}
// --- ЗАПУСК ---
initHDLogic();
initButtons();
injectSettingsMenu();
})();