Блокировка рекламы, скрытие Shorts, авто-пропуск, запоминание скорости, панель настроек.
// ==UserScript==
// @name YouTube Enhancer
// @namespace https://gitlab.com/about-group/About-project
// @version 1.2.0
// @description Блокировка рекламы, скрытие Shorts, авто-пропуск, запоминание скорости, панель настроек.
// @author About-project
// @match *://www.youtube.com/*
// @match *://youtube.com/*
// @match *://m.youtube.com/*
// @icon https://www.youtube.com/favicon.ico
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @run-at document-start
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const DEFAULT_SETTINGS = {
blockAds: true,
blockShorts: false,
autoSkipAds: true,
rememberSpeed: true,
preferredSpeed: 1.0,
hideEndCards: false,
hideComments: false,
confirmClose: false,
};
function loadSettings() {
try {
const raw = GM_getValue('yt_enhancer_settings', null);
return raw ? Object.assign({}, DEFAULT_SETTINGS, JSON.parse(raw)) : { ...DEFAULT_SETTINGS };
} catch {
return { ...DEFAULT_SETTINGS };
}
}
function saveSettings(s) {
GM_setValue('yt_enhancer_settings', JSON.stringify(s));
}
let settings = loadSettings();
const AD_CSS = `
.ad-showing .video-ads,
.ad-showing .ytp-ad-module,
.ytp-ad-overlay-container,
.ytp-ad-text-overlay,
.ytp-ad-overlay-slot,
.ytp-ad-image-overlay,
#player-ads,
#masthead-ad,
#panels > ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"],
ytd-ad-slot-renderer,
ytd-banner-promo-renderer,
ytd-statement-banner-renderer,
ytd-in-feed-ad-layout-renderer,
ytd-promoted-sparkles-web-renderer,
ytd-promoted-video-renderer,
ytd-display-ad-renderer,
ytd-companion-slot-renderer,
ytd-action-companion-ad-renderer,
tp-yt-paper-dialog:has(#dismiss-button),
.ytd-mealbar-promo-renderer,
ytd-popup-container:has(.ytd-enforcement-message-view-model),
ytd-rich-item-renderer:has(.ytd-ad-slot-renderer),
#related ytd-promoted-sparkles-web-renderer,
#related ytd-promoted-video-renderer,
ytd-popup-container:has(a[href*="/premium"]),
tp-yt-paper-dialog:has(yt-upsell-dialog-renderer),
yt-mealbar-promo-renderer {
display: none !important;
}
`;
const SHORTS_CSS = `
ytd-rich-shelf-renderer[is-shorts],
ytd-reel-shelf-renderer,
ytd-mini-guide-entry-renderer[aria-label="Shorts"],
ytd-guide-entry-renderer:has(a[title="Shorts"]),
ytd-guide-entry-renderer:has(a[href*="/shorts"]),
a[title="Shorts"],
ytd-video-renderer:has(a[href*="/shorts/"]),
ytd-grid-video-renderer:has(a[href*="/shorts/"]) {
display: none !important;
}
`;
const END_CARDS_CSS = `
.ytp-ce-element,
.ytp-cards-teaser,
.ytp-ce-covering-overlay,
.ytp-ce-element-shadow,
.ytp-ce-covering-image,
.ytp-ce-expanding-image,
.ytp-ce-element.ytp-ce-video,
.ytp-ce-element.ytp-ce-channel,
.ytp-ce-element.ytp-ce-playlist {
display: none !important;
}
`;
const COMMENTS_CSS = `
#comments, ytd-comments {
display: none !important;
}
`;
function injectStyle(id, css) {
if (document.getElementById(id)) return;
const el = document.createElement('style');
el.id = id;
el.textContent = css;
(document.head || document.documentElement).appendChild(el);
}
function removeStyle(id) {
document.getElementById(id)?.remove();
}
function applyStyles() {
['yt-enh-ads', 'yt-enh-shorts', 'yt-enh-endcards', 'yt-enh-comments'].forEach(removeStyle);
if (settings.blockAds) injectStyle('yt-enh-ads', AD_CSS);
if (settings.blockShorts) injectStyle('yt-enh-shorts', SHORTS_CSS);
if (settings.hideEndCards) injectStyle('yt-enh-endcards', END_CARDS_CSS);
if (settings.hideComments) injectStyle('yt-enh-comments', COMMENTS_CSS);
}
function el(tag, styles, text) {
const node = document.createElement(tag);
if (styles) node.setAttribute('style', styles);
if (text != null) node.textContent = text;
return node;
}
function showWelcome() {
if (GM_getValue('yt_enhancer_welcome_seen', false)) return;
function create() {
if (!document.body) return;
const overlay = el('div',
'position:fixed!important;top:0!important;left:0!important;' +
'width:100vw!important;height:100vh!important;z-index:2147483646!important;' +
'background:rgba(0,0,0,.6)!important;display:flex!important;' +
'align-items:center!important;justify-content:center!important;'
);
overlay.id = 'yt-enh-welcome-overlay';
const box = el('div',
'background:#1e1e2e!important;color:#cdd6f4!important;border-radius:18px!important;' +
'padding:32px 36px!important;width:400px!important;max-width:90vw!important;' +
'font-family:Segoe UI,Roboto,sans-serif!important;text-align:center!important;' +
'box-shadow:0 12px 48px rgba(0,0,0,.6)!important;border:1px solid #45475a!important;' +
'box-sizing:border-box!important;'
);
box.appendChild(el('div', 'font-size:48px!important;margin-bottom:12px!important;', '👋 Привет!'));
box.appendChild(el('h2',
'margin:0 0 8px!important;font-size:20px!important;color:#f38ba8!important;font-weight:600!important;',
'Привет! Спасибо, что установили YouTube Enhancer'
));
box.appendChild(el('p',
'margin:0 0 6px!important;font-size:14px!important;line-height:1.5!important;color:#a6adc8!important;',
'Присоединяйтесь к нашему Discord-серверу:'
));
const features = el('div',
'text-align:left!important;margin:14px 0 18px!important;padding:12px 16px!important;' +
'background:#313244!important;border-radius:10px!important;' +
'font-size:13px!important;line-height:1.7!important;color:#cdd6f4!important;'
);
[
'Обновления и новые функции первыми',
'Помощь и поддержка от сообщества',
'Предлагайте свои идеи для скрипта',
'Общайтесь с другими пользователями',
].forEach(line => features.appendChild(el('div', null, line)));
box.appendChild(features);
const btns = el('div', 'display:flex!important;gap:12px!important;justify-content:center!important;');
const join = el('a',
'padding:10px 24px!important;border-radius:10px!important;font-size:14px!important;' +
'font-weight:600!important;cursor:pointer!important;text-decoration:none!important;' +
'background:#5865F2!important;color:#fff!important;display:inline-block!important;',
'Вступить в Discord'
);
join.href = 'https://discord.gg/UvsnYm2msa';
join.target = '_blank';
join.rel = 'noopener';
join.addEventListener('click', () => dismiss());
const later = el('button',
'padding:10px 24px!important;border-radius:10px!important;font-size:14px!important;' +
'font-weight:600!important;cursor:pointer!important;border:none!important;' +
'background:#45475a!important;color:#cdd6f4!important;',
'Позже'
);
later.addEventListener('click', () => dismiss());
btns.appendChild(join);
btns.appendChild(later);
box.appendChild(btns);
overlay.appendChild(box);
document.documentElement.appendChild(overlay);
function dismiss() {
GM_setValue('yt_enhancer_welcome_seen', true);
overlay.remove();
}
overlay.addEventListener('click', e => { if (e.target === overlay) dismiss(); });
}
if (document.body) create();
else document.addEventListener('DOMContentLoaded', create);
}
function trySkipAd() {
if (!settings.autoSkipAds) return;
const skipBtns = document.querySelectorAll(
'.ytp-ad-skip-button, .ytp-ad-skip-button-modern, .ytp-skip-ad-button, ' +
'button.ytp-ad-skip-button-modern, .ytp-ad-skip-button-container button'
);
skipBtns.forEach(b => { if (b.offsetParent !== null) b.click(); });
const player = document.querySelector('.ad-showing video.html5-main-video');
if (player && player.duration && isFinite(player.duration)) {
player.currentTime = player.duration;
}
const closeOverlay = document.querySelector('.ytp-ad-overlay-close-button');
if (closeOverlay) closeOverlay.click();
}
function applyPlaybackSpeed() {
if (!settings.rememberSpeed) return;
const video = document.querySelector('video.html5-main-video');
if (video && video.playbackRate !== settings.preferredSpeed) {
video.playbackRate = settings.preferredSpeed;
}
}
function watchSpeedChange() {
const video = document.querySelector('video.html5-main-video');
if (!video || video.__ytEnhSpeedWatcher) return;
video.__ytEnhSpeedWatcher = true;
video.addEventListener('ratechange', () => {
if (!document.querySelector('.ad-showing') && settings.rememberSpeed) {
settings.preferredSpeed = video.playbackRate;
saveSettings(settings);
}
});
}
window.addEventListener('beforeunload', e => {
if (!settings.confirmClose) return;
const video = document.querySelector('video.html5-main-video');
if (video && !video.paused) {
e.preventDefault();
e.returnValue = '';
}
});
function openSettingsPanel() {
if (document.getElementById('yt-enh-panel')) return;
const overlay = el('div',
'position:fixed!important;top:0!important;left:0!important;' +
'width:100vw!important;height:100vh!important;z-index:2147483646!important;' +
'background:rgba(0,0,0,.5)!important;display:block!important;'
);
overlay.id = 'yt-enh-overlay';
overlay.addEventListener('click', closeSettingsPanel);
const panel = el('div',
'position:fixed!important;top:50%!important;left:50%!important;' +
'transform:translate(-50%,-50%)!important;z-index:2147483647!important;' +
'background:#1e1e2e!important;color:#cdd6f4!important;' +
'border-radius:16px!important;padding:24px 28px!important;' +
'width:380px!important;max-height:80vh!important;overflow-y:auto!important;' +
'font-family:Segoe UI,Roboto,sans-serif!important;font-size:14px!important;' +
'box-shadow:0 8px 32px rgba(0,0,0,.55)!important;' +
'border:1px solid #45475a!important;box-sizing:border-box!important;' +
'display:block!important;visibility:visible!important;opacity:1!important;'
);
panel.id = 'yt-enh-panel';
panel.appendChild(el('h2',
'margin:0 0 18px!important;font-size:18px!important;color:#f38ba8!important;text-align:center!important;font-weight:600!important;',
'YouTube Enhancer'
));
const toggles = [
['blockAds', 'Блокировать рекламу'],
['autoSkipAds', 'Авто-пропуск рекламы'],
['blockShorts', 'Скрыть Shorts'],
['hideEndCards', 'Скрыть подсказки в конце видео'],
['hideComments', 'Скрыть комментарии'],
['rememberSpeed', 'Запоминать скорость'],
['confirmClose', 'Подтверждение закрытия вкладки'],
];
toggles.forEach(([key, text]) => {
const row = el('label',
'display:flex!important;align-items:center!important;justify-content:space-between!important;' +
'padding:8px 0!important;border-bottom:1px solid #313244!important;cursor:pointer!important;color:#cdd6f4!important;'
);
row.appendChild(el('span', 'color:#cdd6f4!important;', text));
const cb = el('input', 'width:18px!important;height:18px!important;accent-color:#f38ba8!important;cursor:pointer!important;margin:0!important;');
cb.type = 'checkbox';
cb.checked = !!settings[key];
cb.addEventListener('change', () => { settings[key] = cb.checked; });
row.appendChild(cb);
panel.appendChild(row);
});
const speedRow = el('div',
'display:flex!important;align-items:center!important;justify-content:space-between!important;' +
'padding:10px 0!important;border-bottom:1px solid #313244!important;color:#cdd6f4!important;'
);
speedRow.appendChild(el('span', 'color:#cdd6f4!important;', 'Скорость по умолчанию'));
const sel = el('select',
'background:#313244!important;color:#cdd6f4!important;border:none!important;' +
'border-radius:6px!important;padding:4px 8px!important;font-size:14px!important;'
);
[0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3].forEach(s => {
const opt = el('option', null, s + 'x');
opt.value = s;
if (settings.preferredSpeed === s) opt.selected = true;
sel.appendChild(opt);
});
sel.addEventListener('change', () => { settings.preferredSpeed = parseFloat(sel.value); });
speedRow.appendChild(sel);
panel.appendChild(speedRow);
const save = el('button',
'display:block!important;margin:18px auto 0!important;background:#f38ba8!important;' +
'color:#1e1e2e!important;border:none!important;border-radius:8px!important;' +
'padding:8px 28px!important;font-size:14px!important;font-weight:600!important;cursor:pointer!important;',
'Сохранить и закрыть'
);
save.addEventListener('click', () => {
saveSettings(settings);
closeSettingsPanel();
applyStyles();
applyPlaybackSpeed();
});
panel.appendChild(save);
document.documentElement.appendChild(overlay);
document.documentElement.appendChild(panel);
}
function closeSettingsPanel() {
document.getElementById('yt-enh-panel')?.remove();
document.getElementById('yt-enh-overlay')?.remove();
}
if (typeof GM_registerMenuCommand === 'function') {
GM_registerMenuCommand('Настройки YouTube Enhancer', openSettingsPanel);
}
window.ytEnhOpenSettings = openSettingsPanel;
document.addEventListener('keydown', e => {
if (e.altKey && (e.code === 'KeyS' || e.key === 's' || e.key === 'S' || e.key === 'ы' || e.key === 'Ы')) {
e.preventDefault();
e.stopPropagation();
openSettingsPanel();
}
}, true);
function tick() {
trySkipAd();
applyPlaybackSpeed();
watchSpeedChange();
}
applyStyles();
showWelcome();
const observer = new MutationObserver(tick);
function startObserver() {
observer.observe(document.body || document.documentElement, { childList: true, subtree: true });
}
if (document.body) startObserver();
else document.addEventListener('DOMContentLoaded', startObserver);
setInterval(tick, 1000);
document.addEventListener('yt-navigate-finish', () => {
applyStyles();
tick();
});
})();