// ==UserScript== // @name YouTube Fix for Yandex // @namespace https://github.com/Xanixsl/YouTube-Fix-for-Yandex // @version 4.4.4 // @description Оптимизация и исправления YouTube: сетка, производительность, интерфейс, фикс карточки канала и чипсов, мультиязычность, современные темы // @author Xanix // @match https://www.youtube.com/* // @match https://m.youtube.com/* // @icon https://i.postimg.cc/CxVhyKXz/You-Tube-Fix.png // @icon64 https://i.postimg.cc/CxVhyKXz/You-Tube-Fix.png // @grant none // @homepage https://github.com/Xanixsl // @supportURL https://github.com/Xanixsl/YouTube-Fix-for-Yandex/issues // @updateURL https://raw.githubusercontent.com/Xanixsl/YouTube-Fix-for-Yandex/main/youtube-fix-yandex.user.js // @downloadURL https://raw.githubusercontent.com/Xanixsl/YouTube-Fix-for-Yandex/main/youtube-fix-yandex.user.js // @run-at document-start // @license MIT // @licenseURL https://opensource.org/licenses/MIT // @contributionURL https://github.com/Xanixsl/YouTube-Fix-for-Yandex/discussions // ==/UserScript== (function() { 'use strict'; // --- Константы для режима плейлистов --- const PLAYLIST_MODE_CLASS = 'yt-enhancer-playlist-mode'; const PLAYLIST_URL_REGEX = /^\/@[^/]+\/playlists\/?$/; let isPlaylistModeActive = false; let playlistModeNotification = null; // --- Автоматический редирект на /featured для каналов --- (function autoRedirectToFeatured() { const channelRegex = /^\/@[^/]+\/?$/; if (channelRegex.test(location.pathname)) { if (!location.pathname.endsWith('/featured')) { const newUrl = location.pathname.endsWith('/') ? location.pathname + 'featured' : location.pathname + '/featured'; location.replace(newUrl + location.search + location.hash); } } })(); // --- Мультиязычность --- const LANGS = { en: { title: "YouTube Fix for Yandex", version: "v4.4.4", tabs: ["Main", "Yandex Fixes", "Appearance"], tabsNoYandex: ["Main", "Appearance"], save: "Save settings", reset: "Reset settings", saved: "Settings saved! Page will reload...", reseted: "Settings reset! Page will reload...", confirmReset: "Are you sure you want to reset all settings to default?", mainSection: "Main settings", mainDesc: "General options for all browsers", hideChips: "Hide chips (filters)", hideChipsDesc: "Hides the filter bar on the main page and in sections", compactMode: "Compact mode", compactModeDesc: "Reduces spacing between videos for denser layout", hideShorts: "Hide Shorts", hideShortsDesc: "Removes Shorts section and recommendations", hideRFSlowWarning: "Hide slowdown warning", hideRFSlowWarningDesc: "Removes notification about possible slowdowns in Russia", fixChannelCard: "Fix channel card on channel tabs", fixChannelCardDesc: "Fixes the channel card position on all channel tabs", restoreChips: "Restore quick filters (chips) on Videos tab", restoreChipsDesc: "Ensures chips are always visible on the channel's Videos tab", playlistModeFeature: "Playlists on channels", playlistModeFeatureDesc: "Returns playlists to channels (disables yandex browser optimization)", playlistModeWarning: "Warning: Playlist page may display incorrectly. Enable 'Playlists on channels' feature in settings to fix.", langSection: "Interface language", langDesc: "Choose the extension interface language", langAuto: "Auto (browser)", yandexSection: "Yandex grid settings", yandexDesc: "Optimize video grid for Yandex Browser", yandexVideoCount: "Videos per row", yandexChipbarMargin: "Chipbar shift (px)", yandexVideoMargin: "Video block shift (px)", yandexExpSection: "Experimental features", yandexExpDesc: "Use with caution, may be unstable", yandexGridFix: "Fix video grid", yandexGridFixDesc: "Fixes 3-videos-per-row bug", yandexPerf: "Performance mode", yandexPerfDesc: "Improves performance in Yandex Browser", yandexExpFix: "Experimental shift fix", yandexExpFixDesc: "Alternative UI fix method", yandexSiteShift: "Shift amount (px)", appearanceSection: "Dark mode", appearanceDesc: "Interface appearance settings", darkModeSupport: "Dark mode support", darkModeSupportDesc: "Auto switch between light and dark themes", thumbSection: "Video thumbnail size", thumbDesc: "Change video preview size and aspect", thumbDefault: "Default (16:9)", thumbSmall: "Small (16:9)", thumbMedium: "Medium (4:3)", thumbLarge: "Large (1:1)", themeSection: "Settings window theme", themeDesc: "Appearance of this settings window", fontSize: "Font size:", warning: `Full version available only in Yandex Browser.`, languageButton: "Language", ru: "Russian", en: "English", newMark: "new", expMark: "exp", themeModernDarkPink: "Dark Pink", themeModernMidnight: "Midnight", themeModernFrost: "Frost", themeModernSky: "Sky", themeModernClassic: "Classic", themeModernDark: "YouTube Dark", playlistModeNotification: "Playlists on Channels feature is enabled, browser optimization is disabled!", exitPlaylistModeNotification: "Extension will reload in {seconds} seconds to restore functionality" }, ru: { title: "YouTube Fix for Yandex", version: "v4.4.4", tabs: ["Основные", "Яндекс-фиксы", "Внешний вид"], tabsNoYandex: ["Основные", "Внешний вид"], save: "Сохранить настройки", reset: "Сбросить настройки", saved: "Настройки сохранены! Страница будет перезагружена...", reseted: "Настройки сброшены! Страница будет перезагружена...", confirmReset: "Вы уверены, что хотите сбросить все настройки к значениям по умолчанию?", mainSection: "Основные настройки", mainDesc: "Общие параметры для всех браузеров", hideChips: "Скрыть чипсы (фильтры)", hideChipsDesc: "Скрывает полосу с фильтрами на главной странице и в разделах", compactMode: "Компактный режим", compactModeDesc: "Уменьшает отступы между видео для более плотного расположения", hideShorts: "Скрыть Shorts", hideShortsDesc: "Убирает раздел Shorts и рекомендации коротких видео", hideRFSlowWarning: "Скрыть предупреждение о замедлении", hideRFSlowWarningDesc: "Убирает уведомление о возможных замедлениях работы YouTube в РФ", fixChannelCard: "Фикс карточки канала на вкладках", fixChannelCardDesc: "Исправляет \"съезжающую\" карточку канала на всех вкладках канала", restoreChips: "Восстановить быстрые сортировки (чипсы) на вкладке Videos", restoreChipsDesc: "Гарантирует отображение чипсов сортировки видео на странице канала", playlistModeFeature: "Плейлисты на каналах", playlistModeFeatureDesc: "Возвращает плейлисты на каналы (отключает оптимизацию яндекс браузера)", playlistModeWarning: "Внимание: Страница плейлистов может отображаться некорректно. Включите функцию 'Плейлисты на каналах' в настройках, чтобы исправить.", langSection: "Язык интерфейса", langDesc: "Выберите язык интерфейса расширения", langAuto: "Автоматически (по браузеру)", yandexSection: "Настройки сетки видео", yandexDesc: "Оптимизация отображения видео в Яндекс Браузере", yandexVideoCount: "Количество видео в строке", yandexChipbarMargin: "Сдвиг Chipbar (px)", yandexVideoMargin: "Сдвиг блока видео (px)", yandexExpSection: "Экспериментальные функции", yandexExpDesc: "Используйте с осторожностью, могут быть нестабильными", yandexGridFix: "Исправить сетку видео", yandexGridFixDesc: "Фиксит проблему с отображением 3 видео в строке", yandexPerf: "Режим оптимизации", yandexPerfDesc: "Улучшает производительность в Яндекс Браузере", yandexExpFix: "Экспериментальный фикс сдвига", yandexExpFixDesc: "Альтернативный метод исправления интерфейса", yandexSiteShift: "Величина сдвига (px)", appearanceSection: "Темный режим", appearanceDesc: "Настройки внешнего вида интерфейса", darkModeSupport: "Поддержка темной темы", darkModeSupportDesc: "Автоматическое переключение между светлой и темной темой", thumbSection: "Размер миниатюр видео", thumbDesc: "Изменение размера и пропорций превью видео", thumbDefault: "По умолчанию (16:9)", thumbSmall: "Маленькие (16:9)", thumbMedium: "Средние (4:3)", thumbLarge: "Большие (1:1)", themeSection: "Тема окна настроек", themeDesc: "Внешний вид этого окна с настройками", fontSize: "Размер шрифта:", warning: `Полная версия расширения доступна только в Яндекс Браузере.`, languageButton: "Язык", ru: "Русский", en: "Английский", newMark: "новое", expMark: "эксп", themeModernDarkPink: "Тёмно-розовая", themeModernMidnight: "Полночь", themeModernFrost: "Мороз", themeModernSky: "Небо", themeModernClassic: "Классика", themeModernDark: "YouTube", playlistModeNotification: "Включена функция Плейлисты на каналах, оптимизация браузера отключена! ", exitPlaylistModeNotification: "Расширение перезагрузится через {seconds} секунды для восстановления функций" } }; // --- Язык интерфейса --- function getBrowserLang() { const navLang = (navigator.language || navigator.userLanguage || '').toLowerCase(); if (navLang.startsWith('ru')) return 'ru'; return 'en'; } function getSavedUILang() { try { if (typeof localStorage !== 'undefined') { const val = localStorage.getItem('ytEnhancer_uiLang'); if (val && (val === 'ru' || val === 'en' || val === 'auto')) return val; } } catch {} return 'auto'; } function setSavedUILang(lang) { try { if (typeof localStorage !== 'undefined') { localStorage.setItem('ytEnhancer_uiLang', lang); } } catch {} } function getCurrentUILang() { const saved = getSavedUILang(); if (saved === 'auto') return getBrowserLang(); return saved; } let uiLang = getCurrentUILang(); let L = LANGS[uiLang]; // --- Trusted Types Policy --- window.ytEnhancerTrustedTypesPolicy = window.trustedTypes ? window.trustedTypes.createPolicy('yt-enhancer', { createHTML: (input) => input }) : null; function setInnerHTML(element, htmlString) { element.innerHTML = window.ytEnhancerTrustedTypesPolicy ? window.ytEnhancerTrustedTypesPolicy.createHTML(htmlString) : htmlString; } // --- Расширенное определение Яндекс.Браузера --- function isYandexBrowser() { const ua = navigator.userAgent; if (/YaBrowser/i.test(ua)) return true; if (window.yandex) return true; if (navigator.vendor && navigator.vendor.toLowerCase().includes('yandex')) return true; if (window.chrome && chrome.runtime && chrome.runtime.id && chrome.runtime.id.startsWith('bhchdcejhohfmigjafbampogmaanbfkg')) return true; return false; } // --- Проверка ОС --- function getOS() { const userAgent = window.navigator.userAgent; const platform = window.navigator.platform; if (/Windows/.test(userAgent)) return 'Windows'; if (/Mac/.test(platform)) return 'MacOS'; if (/Linux/.test(platform)) return 'Linux'; if (/Android/.test(userAgent)) return 'Android'; if (/iOS|iPhone|iPad|iPod/.test(userAgent)) return 'iOS'; return 'Unknown'; } // --- Конфигурация по умолчанию --- const defaultConfig = { hideChips: false, compactMode: false, hideShorts: true, hideRFSlowWarning: true, fixChannelCard: true, restoreChips: true, playlistModeFeature: false, yandexBrowserFix: true, yandexGridFix: true, yandexVideoCount: 4, yandexChipbarMargin: -70, yandexVideoMargin: 100, yandexLanguage: 'auto', yandexPerformanceMode: true, yandexExperimentalFix: false, yandexSiteShift: 0, darkModeSupport: true, customThumbnailSize: 'default', enhancerTheme: 'darkpink', enhancerFontSize: 14 }; // --- Безопасное хранилище для настроек --- const storage = { get: (key) => { try { if (typeof localStorage !== 'undefined') { const value = localStorage.getItem(`ytEnhancer_${key}`); return value ? JSON.parse(value) : null; } return null; } catch (e) { return null; } }, set: (key, value) => { try { if (typeof localStorage !== 'undefined') { localStorage.setItem(`ytEnhancer_${key}`, JSON.stringify(value)); return true; } return false; } catch (e) { return false; } } }; // --- Загрузка конфигурации --- let config = (function() { try { const saved = storage.get('ytEnhancerConfig'); return saved ? {...defaultConfig, ...saved} : {...defaultConfig}; } catch (e) { return {...defaultConfig}; } })(); // --- Фиксы для Яндекс Браузера --- function applyYandexFixes() { if (!isYandexBrowser() || !config.yandexBrowserFix || (isPlaylistModeActive && config.playlistModeFeature)) return; if (config.yandexLanguage === 'en') { document.cookie = 'PREF=hl=en; domain=.youtube.com; path=/; secure'; document.cookie = 'CONSENT=YES+; domain=.youtube.com; path=/; secure'; } else if (config.yandexLanguage === 'ru') { document.cookie = 'PREF=hl=ru; domain=.youtube.com; path=/; secure'; document.cookie = 'CONSENT=YES+; domain=.youtube.com; path=/; secure'; } if (config.yandexGridFix) { const fixGrid = () => { const grids = document.querySelectorAll('ytd-rich-grid-renderer'); grids.forEach(grid => { grid.style.setProperty('--ytd-rich-grid-items-per-row', config.yandexVideoCount, 'important'); grid.style.setProperty('--ytd-rich-grid-posts-per-row', config.yandexVideoCount, 'important'); }); }; fixGrid(); if (!window.__ytEnhancerYandexGridInterval) { window.__ytEnhancerYandexGridInterval = setInterval(fixGrid, 3000); } } if (config.yandexPerformanceMode) { addStyles(` ytd-rich-grid-renderer, ytd-rich-item-renderer { will-change: unset !important; contain: unset !important; } #items.ytd-grid-renderer { contain: strict !important; } ytd-video-renderer, ytd-grid-video-renderer { transform: translateZ(0); } `); } if (config.yandexExperimentalFix) { const channelPageRegex = /^\/@[^/]+(\/(videos|featured|shorts|playlists|community|about|streams|search)?)?\/?$/; if (!channelPageRegex.test(location.pathname)) { addStyles(` ytd-page-manager, ytd-browse { transform: translateY(${config.yandexSiteShift}px) !important; } ytd-masthead, #header.ytd-rich-grid-renderer, ytd-feed-filter-chip-bar-renderer { transform: none !important; } `); } else { addStyles(` ytd-page-manager, ytd-browse { transform: none !important; } `); } } } // --- Скрытие уведомления о замедлении YouTube в РФ --- function hideRFSlowWarning() { if (!config.hideRFSlowWarning || (isPlaylistModeActive && config.playlistModeFeature)) return; const style = document.createElement('style'); style.textContent = ` .sf-notification-btn { display: none !important; } ytd-mealbar-promo-renderer { display: none !important; } #clarify-box { display: none !important; } `; document.head.appendChild(style); } // --- Основные функции --- function applyMainFeatures() { if (isPlaylistModeActive && config.playlistModeFeature) { // В режиме плейлистов отключаем все основные функции return; } // Скрывать чипсы только на главной странице и в разделах, но не на вкладке Videos if (config.hideChips && /^\/$/.test(location.pathname)) { addStyles(` ytd-feed-filter-chip-bar-renderer, yt-chip-cloud-renderer, yt-related-chip-cloud-renderer, #chips-wrapper.ytd-rich-grid-renderer { display: none !important; } `); } // Принудительно показываем чипсы на вкладке Videos if (/\/@[^/]+\/videos/.test(location.pathname)) { addStyles(` #chips, ytd-feed-filter-chip-bar-renderer, yt-chip-cloud-renderer, yt-related-chip-cloud-renderer, #chips-wrapper.ytd-rich-grid-renderer { display: flex !important; visibility: visible !important; opacity: 1 !important; } `); } if (config.compactMode) { addStyles(` ytd-rich-item-renderer { margin-bottom: 8px !important; } `); } if (config.fixChannelCard) { fixChannelCardOnChannelTabs(); } if (config.restoreChips) { restoreChipsOnVideosTab(); } if (config.hideShorts) { addStyles(` ytd-rich-section-renderer[section-identifier="shorts-shelf"], ytd-reel-shelf-renderer, ytd-guide-entry-renderer[title="Shorts"], a[title="Shorts"], ytd-mini-guide-entry-renderer[title="Shorts"], ytd-rich-shelf-renderer[is-shorts], ytd-rich-section-renderer[section-identifier="shorts-shelf"] { display: none !important; } `); } } // --- Фикс карточки канала на всех вкладках --- function fixChannelCardOnChannelTabs() { if ((isPlaylistModeActive && config.playlistModeFeature)) return; const channelUrlRegex = /^\/@[^\/]+(\/(videos|featured|shorts|playlists|community|about|streams))?\/?$/; const mainTabRegex = /^\/@[^\/]+\/?$/; if (!channelUrlRegex.test(location.pathname)) return; addStyles(` /* Универсальный фикс для шапки канала */ ytd-c4-tabbed-header-renderer, ytd-channel-header-renderer, #channel-header-container { position: sticky !important; top: 56px !important; z-index: 1002 !important; background: var(--yt-spec-base-background, #fff) !important; margin-bottom: 0 !important; box-shadow: 0 2px 8px rgba(0,0,0,0.04) !important; transition: box-shadow 0.2s !important; border-radius: 18px !important; } @media (max-width: 900px) { ytd-c4-tabbed-header-renderer, ytd-channel-header-renderer, #channel-header-container { top: 48px !important; } } #primary.ytd-two-column-browse-results-renderer { margin-top: 0 !important; } /* Дополнительные стили для мобильной версии */ ytd-page-manager[page-subtype="channels"] #header.ytd-rich-grid-renderer { position: sticky !important; top: 48px !important; z-index: 1002 !important; } /* Усиленный фикс для главной вкладки канала */ ytd-browse[page-subtype="channels"] #primary.ytd-two-column-browse-results-renderer { margin-top: 0 !important; padding-top: 0 !important; } ytd-browse[page-subtype="channels"] #header.ytd-c4-tabbed-header-renderer { margin-bottom: 0 !important; padding-bottom: 0 !important; } `); function findChannelHeader() { return ( document.querySelector('ytd-c4-tabbed-header-renderer') || document.querySelector('ytd-channel-header-renderer') || document.querySelector('#channel-header-container') || (document.querySelector('#header') && document.querySelector('#header').querySelector('ytd-c4-tabbed-header-renderer')) || null ); } function applyStyles() { const header = findChannelHeader(); if (header) { header.style.position = 'sticky'; header.style.top = window.innerWidth < 900 ? '48px' : '56px'; header.style.zIndex = '1002'; header.style.background = 'var(--yt-spec-base-background, #fff)'; header.style.marginBottom = '0'; header.style.boxShadow = '0 2px 8px rgba(0,0,0,0.04)'; header.style.borderRadius = '18px'; header.style.paddingBottom = '0'; } const primary = document.querySelector('#primary.ytd-two-column-browse-results-renderer'); if (primary) { primary.style.marginTop = '0'; primary.style.paddingTop = '0'; } if (mainTabRegex.test(location.pathname)) { const headerWrapper = document.querySelector('#header.ytd-c4-tabbed-header-renderer'); if (headerWrapper) { headerWrapper.style.marginBottom = '0'; headerWrapper.style.paddingBottom = '0'; } const browse = document.querySelector('ytd-browse[page-subtype="channels"]'); if (browse) { browse.style.marginTop = '0'; browse.style.paddingTop = '0'; } } } function waitForHeaderAndApply() { let tries = 0; function tryApply() { applyStyles(); tries++; if (!findChannelHeader() && tries < 20) { setTimeout(tryApply, 200); } } tryApply(); } waitForHeaderAndApply(); setTimeout(applyStyles, 1000); const observer = new MutationObserver(applyStyles); observer.observe(document.body, { childList: true, subtree: true }); let lastPath = location.pathname; setInterval(() => { if (location.pathname !== lastPath) { lastPath = location.pathname; if (channelUrlRegex.test(location.pathname)) { waitForHeaderAndApply(); } } }, 500); } // --- Принудительно восстанавливаем чипсы на videos --- function restoreChipsOnVideosTab() { if ((isPlaylistModeActive && config.playlistModeFeature)) return; if (!/^\/@[^\/]+\/videos\/?$/.test(location.pathname)) return; let chipsRestored = false; const observer = new MutationObserver(() => { if (chipsRestored) return; const chips = document.querySelector('#chips'); const chipBar = document.querySelector('ytd-feed-filter-chip-bar-renderer'); if (!chips && chipBar) { const chipsClone = chipBar.cloneNode(true); chipsClone.id = 'chips'; chipsClone.style.marginTop = '0'; chipsClone.style.marginBottom = '16px'; const grid = document.querySelector('ytd-rich-grid-renderer'); if (grid && grid.parentNode) { grid.parentNode.insertBefore(chipsClone, grid); chipsRestored = true; } } document.querySelectorAll( '#chips, ytd-feed-filter-chip-bar-renderer, yt-chip-cloud-renderer, yt-related-chip-cloud-renderer, #chips-wrapper.ytd-rich-grid-renderer' ).forEach(el => { el.style.display = 'flex'; el.style.visibility = 'visible'; el.style.opacity = '1'; }); }); observer.observe(document.body, {childList: true, subtree: true}); addStyles(` #chips { display: flex !important; flex-wrap: wrap; align-items: center; margin-bottom: 16px; animation: chipsFadeIn 0.3s; } @keyframes chipsFadeIn { from { opacity: 0; transform: translateY(-10px);} to { opacity: 1; transform: translateY(0);} } `); } // --- Добавление стилей в DOM --- function addStyles(css) { const style = document.createElement('style'); style.type = 'text/css'; style.textContent = css; const target = document.head || document.documentElement; if (target) { target.appendChild(style); } else { setTimeout(() => addStyles(css), 100); } } // --- Применение стилей --- function applyStyles() { const styles = generateStyles(); addStyles(styles); cleanupSpacing(); } // --- Очистка пробелов --- function cleanupSpacing() { if (!isYandexBrowser() || (isPlaylistModeActive && config.playlistModeFeature)) return; const selectors = [ '#contents.ytd-rich-grid-renderer', 'ytd-rich-grid-renderer', '#contentContainer.ytd-rich-grid-renderer' ]; selectors.forEach(selector => { try { document.querySelectorAll(selector).forEach(el => { if (el && el.style) { el.style.marginTop = '0'; el.style.paddingTop = '0'; } }); } catch (e) { console.error(`Error cleaning up selector ${selector}:`, e); } }); if (config.yandexGridFix) { try { const grid = document.querySelector('ytd-rich-grid-renderer'); if (grid) { grid.style.setProperty('--ytd-rich-grid-items-per-row', config.yandexVideoCount, 'important'); } } catch (e) { console.error('Error fixing Yandex grid:', e); } } } function generateStyles() { let css = ` :root { --chips-animation-duration: 0.3s; --ytd-rich-grid-items-per-row: ${isYandexBrowser() ? config.yandexVideoCount : 4}; --enhancer-bg: var(--yt-spec-base-background, #fff); --enhancer-fg: var(--yt-spec-text-primary, #030303); --enhancer-border: var(--yt-spec-10-percent-layer, #e5e7eb); --enhancer-radius: 18px; --enhancer-btn-radius: 18px; --enhancer-btn-border: var(--yt-spec-brand-button-background, #065fd4); --enhancer-btn-fg: var(--yt-spec-brand-button-background, #065fd4); --enhancer-btn-hover-bg: var(--yt-spec-brand-button-background, #065fd4); --enhancer-btn-hover-fg: #fff; --enhancer-badge-bg: var(--yt-spec-badge-chip-background, #f3f6fa); --enhancer-badge-fg: var(--yt-spec-brand-button-background, #065fd4); --enhancer-badge-exp-bg: #ffe6e6; --enhancer-badge-exp-fg: #ff4f4f; --enhancer-input-bg: var(--yt-spec-badge-chip-background, #f8fafc); --enhancer-input-fg: var(--yt-spec-text-primary, #181a1b); --enhancer-input-border: var(--yt-spec-10-percent-layer, #e5e7eb); --enhancer-tab-active: var(--yt-spec-brand-button-background, #065fd4); --enhancer-tab-inactive: var(--yt-spec-text-secondary, #b0b8c9); --enhancer-font: 'Roboto', 'Segoe UI', Arial, sans-serif; } /* Версия сверху */ #yt-enhancer-version { position: absolute; top: 5px; right: 15px; font-size: 0.85em; color: var(--enhancer-tab-inactive); opacity: 0.7; transition: opacity 0.3s; } #yt-enhancer-version:hover { opacity: 1; } /* Кнопка закрытия (крестик) — только вращение, без смены цвета и фона */ #yt-enhancer-settings .yt-enhancer-close-btn { background: none !important; border: none !important; box-shadow: none !important; outline: none !important; font-size: 1.8em !important; cursor: pointer; padding: 0 8px !important; line-height: 1 !important; transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55); transform-origin: center; color: inherit !important; /* Наследует цвет, не меняет его */ } #yt-enhancer-settings .yt-enhancer-close-btn:hover, #yt-enhancer-settings .yt-enhancer-close-btn:focus { background: none !important; color: inherit !important; border: none !important; box-shadow: none !important; outline: none !important; transform: rotate(90deg); } /* Badge анимации */ .yt-enhancer-badge { display: inline-block; margin-left: 6px; font-size: 0.75em; font-weight: 600; border-radius: 6px; padding: 2px 8px; vertical-align: middle; letter-spacing: 0.5px; background: var(--enhancer-badge-bg); color: var(--enhancer-badge-fg); border: none; opacity: 0.92; text-transform: uppercase; transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1); } .yt-enhancer-badge-exp { background: var(--enhancer-badge-exp-bg); color: var(--enhancer-badge-exp-fg); } .yt-enhancer-badge:hover { transform: scale(1.05); opacity: 1; animation: pulse 2s infinite; } .yt-enhancer-badge-exp:hover { animation: pulseExp 1.5s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } @keyframes pulseExp { 0% { transform: scale(1); opacity: 0.9; } 25% { transform: scale(1.2); opacity: 1; } 50% { transform: scale(0.95); opacity: 0.95; } 75% { transform: scale(1.15); opacity: 1; } 100% { transform: scale(1); opacity: 0.9; } } /* Стили для уведомления о плейлистах */ .yt-enhancer-playlist-warning { position: fixed; bottom: 20px; right: 20px; background: var(--yt-spec-brand-button-background, #065fd4); color: white; padding: 12px 24px; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 999999; max-width: 400px; font-family: var(--enhancer-font); animation: fadeIn 0.3s ease; display: none; } .yt-enhancer-playlist-warning.show { display: block; } .yt-enhancer-playlist-warning a { color: white !important; text-decoration: underline !important; font-weight: bold; } #yt-enhancer-settings { font-size: ${config.enhancerFontSize}px !important; line-height: 1.7 !important; font-family: var(--enhancer-font) !important; background: var(--enhancer-bg) !important; color: var(--enhancer-fg) !important; border-radius: var(--enhancer-radius) !important; border: 1.5px solid var(--enhancer-border) !important; min-width: ${Math.min(540, Math.max(320, config.enhancerFontSize * 20))}px; padding: 24px 18px 18px 18px !important; box-shadow: 0 2px 8px rgba(0,0,0,0.08) !important; transition: background 0.2s, color 0.2s; position: fixed; } #yt-enhancer-settings button, .yt-enhancer-lang-btn { background: none !important; color: var(--enhancer-btn-fg) !important; border: 2px solid var(--enhancer-btn-border) !important; border-radius: var(--enhancer-btn-radius) !important; font-weight: 600; letter-spacing: 0.02em; padding: 10px 18px !important; font-size: 1em; cursor: pointer; transition: background 0.18s, color 0.18s, border-color 0.18s; margin-bottom: 0.3em; box-shadow: none !important; } #yt-enhancer-settings button:hover, .yt-enhancer-lang-btn:hover { background: var(--enhancer-btn-hover-bg) !important; color: var(--enhancer-btn-hover-fg) !important; border-color: var(--enhancer-btn-hover-bg) !important; } #yt-enhancer-settings input, #yt-enhancer-settings select { background: var(--enhancer-input-bg) !important; color: var(--enhancer-input-fg) !important; border: 1.5px solid var(--enhancer-input-border) !important; border-radius: 8px !important; padding: 6px 10px !important; font-size: 1em; font-family: var(--enhancer-font) !important; margin-top: 3px; margin-bottom: 6px; outline: none; transition: border-color 0.15s; } #yt-enhancer-settings input:focus, #yt-enhancer-settings select:focus { border-color: var(--enhancer-btn-border) !important; } #yt-enhancer-settings input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--enhancer-btn-border); margin-right: 10px; margin-top: 2px; vertical-align: middle; } #yt-enhancer-settings input[type="range"] { width: 140px; margin-right: 8px; accent-color: var(--enhancer-btn-border); } #yt-enhancer-settings .yt-enhancer-tab { background: none; border: none; border-bottom: 2px solid transparent; cursor: pointer; font-weight: 600; color: var(--enhancer-tab-inactive); margin-right: 6px; font-size: 1em; transition: color 0.15s, border-bottom-color 0.15s; border-radius: 0; padding: 8px 14px; } #yt-enhancer-settings .yt-enhancer-tab.active { color: var(--enhancer-tab-active); border-bottom-color: var(--enhancer-tab-active); } #yt-enhancer-settings .yt-enhancer-section { margin-bottom: 18px; padding-bottom: 4px; } #yt-enhancer-settings .yt-enhancer-section:last-child { margin-bottom: 0; } #yt-enhancer-settings .yt-enhancer-checkbox-row { display: flex; align-items: flex-start; margin-bottom: 10px; gap: 6px; } #yt-enhancer-settings .yt-enhancer-checkbox-row label { font-weight: 500; font-size: 1em; } #yt-enhancer-settings .yt-enhancer-checkbox-row .desc { font-size: 0.92em; color: #7a869a; margin-top: 2px; } #yt-enhancer-settings .yt-enhancer-number-input { width: 100%; max-width: 100px; } @media (max-width: 700px) { #yt-enhancer-settings { min-width: 90vw !important; padding: 14px 4vw 14px 4vw !important; } #yt-enhancer-version { left: 6vw; } } @media (max-width: 480px) { #yt-enhancer-settings { min-width: 98vw !important; padding: 8px 1vw 8px 1vw !important; } #yt-enhancer-version { left: 2vw; } } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px);} to { opacity: 1; transform: translateY(0);} } @keyframes fadeOut { from { opacity: 1; transform: translateY(0);} to { opacity: 0; transform: translateY(10px);} } `; // --- THEME OVERRIDES --- // AUTO: полностью повторяет Material YouTube (цвета, скругления, кнопки) if (config.enhancerTheme === 'auto') { css += ` :root { --enhancer-radius: 16px !important; --enhancer-btn-radius: 12px !important; --enhancer-transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; } @media (prefers-color-scheme: dark) { :root { /* Основные цвета */ --enhancer-bg: var(--yt-spec-base-background, #0f0f0f) !important; --enhancer-fg: var(--yt-spec-text-primary, #f1f1f1) !important; --enhancer-border: var(--yt-spec-10-percent-layer, #272727) !important; /* Акценты */ --enhancer-primary: var(--yt-spec-brand-button-background, #3ea6ff) !important; --enhancer-secondary: #5fb4ff !important; --enhancer-accent: #7fc1ff !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-primary) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #000 !important; --enhancer-badge-bg: rgba(62, 166, 255, 0.15) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #ff7043 !important; --enhancer-badge-exp-fg: #000 !important; /* Формы */ --enhancer-input-bg: var(--yt-spec-badge-chip-background, #1f1f1f) !important; --enhancer-input-fg: var(--yt-spec-text-primary, #f1f1f1) !important; --enhancer-input-border: var(--yt-spec-10-percent-layer, #333) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-primary) !important; --enhancer-tab-inactive: var(--yt-spec-text-secondary, #aaa) !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(62, 166, 255, 0.3), transparent ) !important; /* Специальные цвета для select */ --enhancer-select-bg: #1f1f1f !important; --enhancer-select-fg: #ffffff !important; --enhancer-select-border: #333 !important; } /* Стили для темной темы */ #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(62, 166, 255, 0.2), 0 8px 32px rgba(0, 0, 0, 0.5) !important; backdrop-filter: blur(12px); } #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; background: linear-gradient(90deg, #3ea6ff, #5fb4ff); -webkit-background-clip: text; background-clip: text; color: transparent !important; margin-bottom: 24px; position: relative; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } } @media (prefers-color-scheme: light) { :root { /* Основные цвета */ --enhancer-bg: var(--yt-spec-base-background, #ffffff) !important; --enhancer-fg: var(--yt-spec-text-primary, #030303) !important; --enhancer-border: var(--yt-spec-10-percent-layer, #e5e7eb) !important; /* Акценты */ --enhancer-primary: var(--yt-spec-brand-button-background, #065fd4) !important; --enhancer-secondary: #1a73e8 !important; --enhancer-accent: #4285f4 !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-primary) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #ffffff !important; --enhancer-badge-bg: rgba(6, 95, 212, 0.1) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #ff9800 !important; --enhancer-badge-exp-fg: #ffffff !important; /* Формы */ --enhancer-input-bg: var(--yt-spec-badge-chip-background, #f8fafc) !important; --enhancer-input-fg: var(--yt-spec-text-primary, #181a1b) !important; --enhancer-input-border: var(--yt-spec-10-percent-layer, #e5e7eb) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-primary) !important; --enhancer-tab-inactive: var(--yt-spec-text-secondary, #b0b8c9) !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(6, 95, 212, 0.2), transparent ) !important; /* Специальные цвета для select */ --enhancer-select-bg: #ffffff !important; --enhancer-select-fg: #030303 !important; --enhancer-select-border: #e5e7eb !important; } /* Стили для светлой темы */ #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(6, 95, 212, 0.1), 0 8px 32px rgba(0, 0, 0, 0.1) !important; backdrop-filter: blur(8px); } #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; color: var(--enhancer-primary) !important; margin-bottom: 24px; position: relative; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } } /* Общие стили для обеих тем */ #yt-enhancer-settings h3 { font-weight: 600; color: var(--enhancer-fg) !important; margin: 24px 0 16px; padding-bottom: 8px; border-bottom: 1px solid var(--enhancer-border); } .yt-enhancer-section { position: relative; padding-bottom: 16px; margin-bottom: 24px; } .yt-enhancer-section::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings button { transition: var(--enhancer-transition) !important; position: relative; overflow: hidden; } #yt-enhancer-settings button:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; } #yt-enhancer-settings input[type="checkbox"] { accent-color: var(--enhancer-primary) !important; transition: transform 0.2s ease !important; } #yt-enhancer-settings input[type="checkbox"]:hover { transform: scale(1.1); } /* Исправленные стили для выпадающего списка */ #yt-enhancer-settings select { color: var(--enhancer-select-fg) !important; background-color: var(--enhancer-select-bg) !important; border: 1px solid var(--enhancer-select-border) !important; padding: 8px 12px !important; border-radius: 8px !important; transition: var(--enhancer-transition) !important; } #yt-enhancer-settings select:hover { border-color: var(--enhancer-primary) !important; } #yt-enhancer-settings select:focus { outline: none; box-shadow: 0 0 0 2px rgba(6, 95, 212, 0.2) !important; border-color: var(--enhancer-primary) !important; } @media (prefers-color-scheme: dark) { #yt-enhancer-settings select:focus { box-shadow: 0 0 0 2px rgba(62, 166, 255, 0.3) !important; } } `; } // DARKPINK: черный фон, ярко-розовая обводка, бело-розовый текст, только обводка у кнопок if (config.enhancerTheme === 'darkpink') { css += ` :root { /* Цветовая схема */ --enhancer-bg: #000000 !important; --enhancer-fg: #ffffff !important; --enhancer-border: rgba(255, 105, 180, 0.2) !important; /* Акценты */ --enhancer-primary: #ff69b4 !important; --enhancer-secondary: #ff8ac2 !important; --enhancer-accent: #ffb6e6 !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-primary) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #000 !important; --enhancer-badge-bg: rgba(255, 105, 180, 0.2) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #ff3d8e !important; --enhancer-badge-exp-fg: #ffffff !important; /* Формы */ --enhancer-input-bg: #18121e !important; --enhancer-input-fg: #ffffff !important; --enhancer-input-border: rgba(255, 105, 180, 0.4) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-primary) !important; --enhancer-tab-inactive: #b0b8c9 !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(255, 105, 180, 0.4), transparent ) !important; /* Анимации и скругления */ --enhancer-transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; --enhancer-radius: 16px !important; --enhancer-btn-radius: 12px !important; --enhancer-glow: 0 0 8px rgba(255, 105, 180, 0.6) !important; /* Select */ --enhancer-select-bg: #18121e !important; --enhancer-select-fg: #ffffff !important; --enhancer-select-border: rgba(255, 105, 180, 0.4) !important; } #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(255, 105, 180, 0.3), 0 8px 32px rgba(255, 105, 180, 0.15) !important; backdrop-filter: blur(12px); border-radius: var(--enhancer-radius); animation: pulse-glow 6s infinite alternate; } @keyframes pulse-glow { 0% { box-shadow: 0 0 0 1px rgba(255, 105, 180, 0.3), 0 8px 32px rgba(255, 105, 180, 0.15); } 50% { box-shadow: 0 0 0 1px rgba(255, 105, 180, 0.4), 0 8px 32px rgba(255, 105, 180, 0.25); } 100% { box-shadow: 0 0 0 1px rgba(255, 105, 180, 0.3), 0 8px 32px rgba(255, 105, 180, 0.15); } } #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; background: linear-gradient(90deg, #ff69b4, #ff8ac2); -webkit-background-clip: text; background-clip: text; color: transparent !important; margin-bottom: 24px; position: relative; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings h3 { font-weight: 600; color: var(--enhancer-fg) !important; margin: 24px 0 16px; padding-bottom: 8px; border-bottom: 1px solid var(--enhancer-border); } .yt-enhancer-section { position: relative; padding-bottom: 16px; margin-bottom: 24px; } .yt-enhancer-section::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings button { transition: var(--enhancer-transition) !important; border-radius: var(--enhancer-btn-radius) !important; position: relative; overflow: hidden; } #yt-enhancer-settings button:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; } #yt-enhancer-settings input[type="checkbox"] { accent-color: var(--enhancer-primary) !important; transition: transform 0.2s ease !important; } #yt-enhancer-settings input[type="checkbox"]:hover { transform: scale(1.1); } #yt-enhancer-settings select { color: var(--enhancer-select-fg) !important; background-color: var(--enhancer-select-bg) !important; border: 1px solid var(--enhancer-select-border) !important; padding: 8px 12px !important; border-radius: 8px !important; transition: var(--enhancer-transition) !important; } #yt-enhancer-settings select:hover { border-color: var(--enhancer-primary) !important; } #yt-enhancer-settings select:focus { outline: none; box-shadow: 0 0 0 2px rgba(255, 105, 180, 0.2) !important; border-color: var(--enhancer-primary) !important; } `; } // MIDNIGHT: темный фон, синий акцент, только обводка if (config.enhancerTheme === 'midnight') { css += ` :root { /* Цветовая схема */ --enhancer-bg: #0f111a !important; --enhancer-fg: #e0e5ff !important; --enhancer-border: rgba(58, 123, 213, 0.15) !important; /* Акценты */ --enhancer-primary: #3a7bd5 !important; --enhancer-secondary: #6c8bc7 !important; --enhancer-accent: #00d2ff !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-primary) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #ffffff !important; --enhancer-badge-bg: rgba(58, 123, 213, 0.2) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #ff7043 !important; --enhancer-badge-exp-fg: #0f111a !important; /* Формы */ --enhancer-input-bg: #1a2138 !important; --enhancer-input-fg: #e0e5ff !important; --enhancer-input-border: rgba(58, 123, 213, 0.3) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-primary) !important; --enhancer-tab-inactive: #4a5568 !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(58, 123, 213, 0.4), transparent ) !important; } /* Стили контейнера */ #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(58, 123, 213, 0.3), 0 8px 32px rgba(0, 0, 0, 0.5) !important; backdrop-filter: blur(8px); border-radius: 16px !important; } /* Заголовки */ #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; background: linear-gradient(90deg, #3a7bd5, #00d2ff); -webkit-background-clip: text; background-clip: text; color: transparent !important; margin-bottom: 24px; position: relative; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings h3 { font-weight: 600; color: #a4b8e1 !important; margin: 24px 0 16px; padding-bottom: 8px; border-bottom: 1px solid rgba(58, 123, 213, 0.3); } /* Разделители секций */ .yt-enhancer-section { position: relative; padding-bottom: 16px; margin-bottom: 24px; } .yt-enhancer-section::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } /* Анимации */ #yt-enhancer-settings button, .yt-enhancer-lang-btn { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; transform-origin: center; } #yt-enhancer-settings button:hover, .yt-enhancer-lang-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(58, 123, 213, 0.3) !important; } /* Чекбоксы с анимацией */ #yt-enhancer-settings input[type="checkbox"] { accent-color: var(--enhancer-primary) !important; transition: transform 0.2s, box-shadow 0.2s !important; } #yt-enhancer-settings input[type="checkbox"]:hover { transform: scale(1.1); } /* Выпадающие списки */ #yt-enhancer-settings select { transition: all 0.3s ease !important; background-repeat: no-repeat !important; background-position: right 10px center !important; } #yt-enhancer-settings select:hover { border-color: var(--enhancer-primary) !important; box-shadow: 0 0 0 1px var(--enhancer-primary) !important; } `; } // FROST: светлый фон, голубая обводка, только обводка if (config.enhancerTheme === 'frost') { css += ` :root { /* Цветовая схема */ --enhancer-bg: rgba(248, 250, 252, 0.96) !important; --enhancer-fg: #1e293b !important; --enhancer-border: rgba(203, 213, 225, 0.6) !important; /* Акценты */ --enhancer-primary: #2563eb !important; --enhancer-secondary: #3b82f6 !important; --enhancer-accent: #60a5fa !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-primary) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #ffffff !important; --enhancer-badge-bg: rgba(59, 130, 246, 0.1) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #f97316 !important; --enhancer-badge-exp-fg: #ffffff !important; /* Формы */ --enhancer-input-bg: rgba(255, 255, 255, 0.9) !important; --enhancer-input-fg: #1e293b !important; --enhancer-input-border: rgba(203, 213, 225, 0.8) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-primary) !important; --enhancer-tab-inactive: #94a3b8 !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(203, 213, 225, 0.6), transparent ) !important; } /* Стили контейнера */ #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(226, 232, 240, 0.8), 0 8px 32px rgba(148, 163, 184, 0.12) !important; backdrop-filter: blur(12px); border-radius: 16px !important; } /* Заголовки */ #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; color: var(--enhancer-primary) !important; margin-bottom: 24px; position: relative; letter-spacing: -0.5px; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings h3 { font-weight: 600; color: #475569 !important; margin: 24px 0 16px; padding-bottom: 8px; border-bottom: 1px solid rgba(203, 213, 225, 0.5); } /* Анимации кнопок */ #yt-enhancer-settings button { transition: all 0.3s ease !important; position: relative; overflow: hidden; } #yt-enhancer-settings button::after { content: ''; position: absolute; top: 50%; left: 50%; width: 5px; height: 5px; background: rgba(255, 255, 255, 0.5); opacity: 0; border-radius: 100%; transform: scale(1, 1) translate(-50%, -50%); transform-origin: 50% 50%; } #yt-enhancer-settings button:hover::after { animation: ripple 1s ease-out; } @keyframes ripple { 0% { transform: scale(0, 0); opacity: 0.5; } 100% { transform: scale(20, 20); opacity: 0; } } /* Плавные переходы для инпутов */ #yt-enhancer-settings input, #yt-enhancer-settings select { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; } #yt-enhancer-settings input:focus, #yt-enhancer-settings select:focus { border-color: var(--enhancer-primary) !important; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2) !important; } /* Стили для чекбоксов */ #yt-enhancer-settings input[type="checkbox"] { accent-color: var(--enhancer-primary) !important; width: 18px !important; height: 18px !important; transition: transform 0.2s ease !important; } #yt-enhancer-settings input[type="checkbox"]:hover { transform: scale(1.1); } `; } // SKY: светлый фон, голубой акцент, только обводка if (config.enhancerTheme === 'sky') { css += ` :root { /* Цветовая схема */ --enhancer-bg: rgba(240, 249, 255, 0.98) !important; --enhancer-fg: #0369a1 !important; --enhancer-border: rgba(186, 230, 253, 0.6) !important; /* Акценты */ --enhancer-primary: #0284c7 !important; --enhancer-secondary: #0ea5e9 !important; --enhancer-accent: #38bdf8 !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-accent) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #ffffff !important; --enhancer-badge-bg: rgba(56, 189, 248, 0.2) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #fb923c !important; --enhancer-badge-exp-fg: #ffffff !important; /* Формы */ --enhancer-input-bg: rgba(255, 255, 255, 0.9) !important; --enhancer-input-fg: #0369a1 !important; --enhancer-input-border: rgba(186, 230, 253, 0.8) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-accent) !important; --enhancer-tab-inactive: #7dd3fc !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(2, 132, 199, 0.2), transparent ) !important; } /* Стили контейнера */ #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(186, 230, 253, 0.5), 0 8px 32px rgba(2, 132, 199, 0.1) !important; backdrop-filter: blur(6px); border-radius: 16px !important; } /* Анимированные заголовки */ #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; background: linear-gradient(90deg, #0284c7, #38bdf8); -webkit-background-clip: text; background-clip: text; color: transparent !important; margin-bottom: 24px; position: relative; display: inline-block; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings h3 { font-weight: 600; color: #0c4a6e !important; margin: 24px 0 16px; padding-bottom: 8px; border-bottom: 1px solid rgba(2, 132, 199, 0.2); } /* Эффект волны для кнопок */ #yt-enhancer-settings button { position: relative; overflow: hidden; transition: all 0.3s !important; } #yt-enhancer-settings button:hover { transform: translateY(-2px); box-shadow: 0 4px 16px rgba(2, 132, 199, 0.2) !important; } #yt-enhancer-settings button::after { content: ''; position: absolute; top: 50%; left: 50%; width: 5px; height: 5px; background: rgba(255, 255, 255, 0.5); opacity: 0; border-radius: 100%; transform: scale(1, 1) translate(-50%, -50%); transform-origin: 50% 50%; } #yt-enhancer-settings button:hover::after { animation: ripple 1s ease-out; } /* Плавное появление элементов */ .yt-enhancer-section { animation: fadeIn 0.4s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* Стили для выпадающих списков */ #yt-enhancer-settings select { transition: all 0.3s ease !important; background-repeat: no-repeat !important; background-position: right 10px center !important; } #yt-enhancer-settings select:hover { border-color: var(--enhancer-accent) !important; box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.2) !important; } `; } // CLASSIC: светлый фон, серый акцент, только обводка if (config.enhancerTheme === 'classic') { css += ` :root { /* Цветовая схема */ --enhancer-bg: rgba(255, 255, 255, 0.98) !important; --enhancer-fg: #1f2937 !important; --enhancer-border: rgba(209, 213, 219, 0.6) !important; /* Акценты */ --enhancer-primary: #4b5563 !important; --enhancer-secondary: #6b7280 !important; --enhancer-accent: #9ca3af !important; /* Элементы интерфейса */ --enhancer-btn-border: var(--enhancer-accent) !important; --enhancer-btn-fg: var(--enhancer-primary) !important; --enhancer-btn-hover-bg: var(--enhancer-primary) !important; --enhancer-btn-hover-fg: #ffffff !important; --enhancer-badge-bg: rgba(156, 163, 175, 0.1) !important; --enhancer-badge-fg: var(--enhancer-primary) !important; --enhancer-badge-exp-bg: #f59e0b !important; --enhancer-badge-exp-fg: #ffffff !important; /* Формы */ --enhancer-input-bg: rgba(249, 250, 251, 0.9) !important; --enhancer-input-fg: #1f2937 !important; --enhancer-input-border: rgba(209, 213, 219, 0.8) !important; /* Вкладки */ --enhancer-tab-active: var(--enhancer-primary) !important; --enhancer-tab-inactive: var(--enhancer-accent) !important; /* Разделители */ --enhancer-divider: linear-gradient( 90deg, transparent, rgba(156, 163, 175, 0.4), transparent ) !important; } /* Стили контейнера */ #yt-enhancer-settings { box-shadow: 0 0 0 1px rgba(229, 231, 235, 0.9), 0 8px 32px rgba(0, 0, 0, 0.05) !important; backdrop-filter: blur(4px); border-radius: 16px !important; } /* Заголовки с тонкими разделителями */ #yt-enhancer-settings h2 { font-weight: 700; font-size: 1.5em; color: var(--enhancer-primary) !important; margin-bottom: 24px; position: relative; letter-spacing: -0.5px; } #yt-enhancer-settings h2::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 1px; background: var(--enhancer-divider); } #yt-enhancer-settings h3 { font-weight: 600; color: #374151 !important; margin: 24px 0 16px; padding-bottom: 8px; border-bottom: 1px solid rgba(209, 213, 219, 0.6); } /* Минималистичные анимации */ #yt-enhancer-settings button { transition: all 0.2s ease !important; } #yt-enhancer-settings button:hover { transform: translateY(-1px); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08) !important; } /* Плавное изменение инпутов */ #yt-enhancer-settings input, #yt-enhancer-settings select { transition: all 0.2s ease !important; } #yt-enhancer-settings input:focus, #yt-enhancer-settings select:focus { border-color: var(--enhancer-accent) !important; box-shadow: 0 0 0 2px rgba(156, 163, 175, 0.1) !important; } /* Стили для чекбоксов */ #yt-enhancer-settings input[type="checkbox"] { accent-color: var(--enhancer-primary) !important; transition: transform 0.2s ease !important; } #yt-enhancer-settings input[type="checkbox"]:hover { transform: scale(1.05); } `; } // Thumbnail size if (config.customThumbnailSize !== 'default' && !isPlaylistModeActive) { css += ` ytd-rich-grid-media { aspect-ratio: ${getThumbnailAspectRatio()} !important; } ytd-rich-item-renderer { width: ${getThumbnailWidth()} !important; } `; } // Yandex grid if (isYandexBrowser() && !isPlaylistModeActive) { css += ` #frosted-glass.with-chipbar { margin-top: ${config.yandexChipbarMargin}px !important; } ytd-rich-grid-renderer, #contents.ytd-rich-grid-renderer { margin-top: ${config.yandexExperimentalFix ? 0 : config.yandexVideoMargin}px !important; } ytd-rich-grid-renderer { --ytd-rich-grid-items-per-row: ${config.yandexVideoCount} !important; } `; } else if (!isPlaylistModeActive) { css += ` ytd-rich-grid-renderer { --ytd-rich-grid-items-per-row: 4 !important; } `; } // Playlist mode specific styles if (isPlaylistModeActive) { css += ` .${PLAYLIST_MODE_CLASS} #yt-enhancer-settings:not(.playlist-mode-exception) { opacity: 0.25 !important; pointer-events: none !important; } .${PLAYLIST_MODE_CLASS} #yt-enhancer-btn { opacity: 1 !important; pointer-events: auto !important; } .${PLAYLIST_MODE_CLASS} #yt-enhancer-settings button:not([disabled]) { opacity: 1 !important; pointer-events: auto !important; } `; } return css; } // --- Вспомогательные функции --- function getThumbnailAspectRatio() { switch(config.customThumbnailSize) { case 'small': return '16/9'; case 'medium': return '4/3'; case 'large': return '1/1'; default: return '16/9'; } } function getThumbnailWidth() { switch(config.customThumbnailSize) { case 'small': return '240px'; case 'medium': return '320px'; case 'large': return '360px'; default: return '100%'; } } // --- UI настроек --- function createSettingsUI() { if (document.getElementById('yt-enhancer-settings')) return; const dialog = document.createElement('div'); dialog.id = 'yt-enhancer-settings'; if (isPlaylistModeActive) { dialog.classList.add('playlist-mode-exception'); } dialog.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: var(--yt-spec-base-background, #fff); color: var(--yt-spec-text-primary, #030303); padding: 24px; border-radius: 22px; box-shadow: 0 8px 32px rgba(0,0,0,0.2); z-index: 999999; width: ${isYandexBrowser() ? '540px' : '400px'}; max-width: 98vw; max-height: 96vh; overflow-y: auto; font-family: 'Segoe UI', 'Roboto', Arial, sans-serif; border: 2px solid var(--yt-spec-10-percent-layer, #ddd); `; // --- Версия сверху --- const versionDiv = document.createElement('div'); versionDiv.id = 'yt-enhancer-version'; versionDiv.textContent = L.version; dialog.appendChild(versionDiv); // --- Заголовок и крестик --- const header = document.createElement('div'); header.style.display = 'flex'; header.style.justifyContent = 'space-between'; header.style.alignItems = 'center'; header.style.marginBottom = '20px'; const title = document.createElement('h2'); title.textContent = L.title; title.style.margin = '0'; title.style.fontSize = '1.5em'; title.style.color = 'var(--yt-spec-text-primary, #030303)'; title.style.fontWeight = 'bold'; const closeBtn = document.createElement('button'); closeBtn.className = 'yt-enhancer-close-btn'; setInnerHTML(closeBtn, '×'); closeBtn.style.cssText = ` background: none; border: none; font-size: 2em; cursor: pointer; color: var(--yt-spec-text-secondary, #606060); padding: 0 8px; line-height: 1; `; header.appendChild(title); header.appendChild(closeBtn); dialog.appendChild(header); if (!isYandexBrowser()) { const warning = document.createElement('div'); warning.style.padding = '12px'; warning.style.marginBottom = '20px'; warning.style.backgroundColor = 'var(--yt-spec-badge-chip-background, #f8f9fa)'; warning.style.borderRadius = '8px'; warning.style.textAlign = 'center'; setInnerHTML(warning, L.warning); dialog.appendChild(warning); } // --- Вкладки --- const tabs = document.createElement('div'); tabs.style.display = 'flex'; tabs.style.marginBottom = '20px'; tabs.style.borderBottom = '1px solid var(--yt-spec-10-percent-layer, #ddd)'; const tabNames = isYandexBrowser() ? L.tabs : L.tabsNoYandex; const tabContents = []; tabNames.forEach((name, i) => { const tab = document.createElement('button'); tab.textContent = name; tab.dataset.tab = i; tab.style.cssText = ` padding: 10px 18px; background: none; border: none; border-bottom: 2.5px solid transparent; cursor: pointer; font-weight: 600; color: var(--yt-spec-text-secondary, #606060); margin-right: 8px; font-size: 1em; transition: color 0.15s, border-bottom-color 0.15s; border-radius: 0; `; if (i === 0) { tab.style.color = 'var(--yt-spec-text-primary, #030303)'; tab.style.borderBottomColor = 'var(--yt-spec-brand-button-background, #065fd4)'; } tab.addEventListener('click', () => { tabs.querySelectorAll('button').forEach(t => { t.style.color = 'var(--yt-spec-text-secondary, #606060)'; t.style.borderBottomColor = 'transparent'; }); tab.style.color = 'var(--yt-spec-text-primary, #030303)'; tab.style.borderBottomColor = 'var(--yt-spec-brand-button-background, #065fd4)'; tabContents.forEach((content, j) => { content.style.display = i === j ? 'block' : 'none'; }); }); tabs.appendChild(tab); const content = document.createElement('div'); content.style.display = i === 0 ? 'block' : 'none'; content.style.marginBottom = '20px'; tabContents.push(content); }); dialog.appendChild(tabs); if (isYandexBrowser()) { createMainTab(tabContents[0]); createYandexTab(tabContents[1]); createAppearanceTab(tabContents[2]); } else { createMainTab(tabContents[0]); createAppearanceTab(tabContents[1]); } tabContents.forEach(content => dialog.appendChild(content)); // --- Кнопки сохранения/сброса --- const buttons = document.createElement('div'); buttons.style.display = 'flex'; buttons.style.justifyContent = 'space-between'; buttons.style.marginTop = '20px'; const saveBtn = document.createElement('button'); saveBtn.textContent = L.save; saveBtn.style.cssText = ` padding: 12px 24px; background: var(--yt-spec-brand-button-background, #065fd4); color: white; border: none; border-radius: 12px; cursor: pointer; font-weight: 600; flex: 1; margin-right: 10px; `; const resetBtn = document.createElement('button'); resetBtn.textContent = L.reset; resetBtn.style.cssText = ` padding: 12px 24px; background: var(--yt-spec-10-percent-layer, #f1f1f1); color: var(--yt-spec-text-primary, #030303); border: none; border-radius: 12px; cursor: pointer; flex: 1; font-weight: 600; `; buttons.appendChild(saveBtn); buttons.appendChild(resetBtn); dialog.appendChild(buttons); document.body.appendChild(dialog); closeBtn.addEventListener('click', () => dialog.remove()); saveBtn.addEventListener('click', () => { const inputs = dialog.querySelectorAll('input, select'); inputs.forEach(input => { if (input.type === 'checkbox') { config[input.id] = input.checked; } else if (input.type === 'number') { config[input.id] = parseInt(input.value) || 0; } else { config[input.id] = input.value; } }); // Автоматическое управление режимом оптимизации const playlistModeCheckbox = dialog.querySelector('#playlistModeFeature'); if (playlistModeCheckbox) { const perfModeCheckbox = dialog.querySelector('#yandexPerformanceMode'); if (perfModeCheckbox) { if (playlistModeCheckbox.checked) { // Если включен режим плейлистов, отключаем режим оптимизации perfModeCheckbox.checked = false; perfModeCheckbox.disabled = true; if (perfModeCheckbox.parentElement) { perfModeCheckbox.parentElement.style.opacity = '0.5'; } config.yandexPerformanceMode = false; } else { // Если выключен режим плейлистов, включаем режим оптимизации perfModeCheckbox.checked = true; perfModeCheckbox.disabled = false; if (perfModeCheckbox.parentElement) { perfModeCheckbox.parentElement.style.opacity = '1'; } config.yandexPerformanceMode = true; } } } storage.set('ytEnhancerConfig', config); applyStyles(); applyMainFeatures(); applyYandexFixes(); hideRFSlowWarning(); dialog.remove(); showNotification(L.saved); setTimeout(() => location.reload(), 1000); }); resetBtn.addEventListener('click', () => { if (confirm(L.confirmReset)) { config = {...defaultConfig}; storage.set('ytEnhancerConfig', config); applyStyles(); applyMainFeatures(); applyYandexFixes(); hideRFSlowWarning(); dialog.remove(); showNotification(L.reseted); setTimeout(() => location.reload(), 1000); } }); const handleOutsideClick = (e) => { if (!dialog.contains(e.target)) { dialog.remove(); document.removeEventListener('click', handleOutsideClick); } }; setTimeout(() => document.addEventListener('click', handleOutsideClick), 100); dialog.addEventListener('click', e => e.stopPropagation()); } // --- Основная вкладка --- function createMainTab(container) { const section = (title, description = '') => { const sectionDiv = document.createElement('div'); sectionDiv.style.marginBottom = '16px'; const h3 = document.createElement('h3'); h3.textContent = title; h3.style.margin = '16px 0 8px 0'; h3.style.fontSize = '1.1em'; h3.style.color = 'var(--yt-spec-text-primary, #030303)'; h3.style.fontWeight = 'bold'; if (description) { const desc = document.createElement('p'); desc.textContent = description; desc.style.margin = '4px 0 8px 0'; desc.style.fontSize = '0.9em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; sectionDiv.appendChild(desc); } sectionDiv.appendChild(h3); return sectionDiv; }; const mainSection = section(L.mainSection, L.mainDesc); const createCheckbox = (id, label, checked, description = '', isNew = false, isExp = false) => { const div = document.createElement('div'); div.style.display = 'flex'; div.style.alignItems = 'flex-start'; div.style.marginBottom = '12px'; const input = document.createElement('input'); input.type = 'checkbox'; input.id = id; input.checked = checked; input.style.marginRight = '10px'; input.style.marginTop = '3px'; const labelDiv = document.createElement('div'); const labelEl = document.createElement('label'); labelEl.htmlFor = id; labelEl.textContent = label; labelEl.style.userSelect = 'none'; labelEl.style.fontWeight = '500'; labelDiv.appendChild(labelEl); if (isNew) { const newMark = document.createElement('span'); newMark.textContent = L.newMark; newMark.className = 'yt-enhancer-badge'; labelDiv.appendChild(newMark); } if (isExp) { const expMark = document.createElement('span'); expMark.textContent = L.expMark; expMark.className = 'yt-enhancer-badge yt-enhancer-badge-exp'; labelDiv.appendChild(expMark); } if (description) { const desc = document.createElement('div'); desc.textContent = description; desc.style.fontSize = '0.85em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; desc.style.marginTop = '4px'; labelDiv.appendChild(desc); } div.appendChild(input); div.appendChild(labelDiv); return div; }; mainSection.appendChild(createCheckbox( 'hideChips', L.hideChips, config.hideChips, L.hideChipsDesc )); mainSection.appendChild(createCheckbox( 'compactMode', L.compactMode, config.compactMode, L.compactModeDesc )); mainSection.appendChild(createCheckbox( 'hideShorts', L.hideShorts, config.hideShorts, L.hideShortsDesc )); mainSection.appendChild(createCheckbox( 'hideRFSlowWarning', L.hideRFSlowWarning, config.hideRFSlowWarning, L.hideRFSlowWarningDesc )); mainSection.appendChild(createCheckbox( 'fixChannelCard', L.fixChannelCard, config.fixChannelCard, L.fixChannelCardDesc )); mainSection.appendChild(createCheckbox( 'restoreChips', L.restoreChips, config.restoreChips, L.restoreChipsDesc )); mainSection.appendChild(createCheckbox( 'playlistModeFeature', L.playlistModeFeature, config.playlistModeFeature, L.playlistModeFeatureDesc )); container.appendChild(mainSection); } // --- Яндекс вкладка --- function createYandexTab(container) { const section = (title, description = '') => { const sectionDiv = document.createElement('div'); sectionDiv.style.marginBottom = '16px'; const h3 = document.createElement('h3'); h3.textContent = title; h3.style.margin = '16px 0 8px 0'; h3.style.fontSize = '1.1em'; h3.style.color = 'var(--yt-spec-text-primary, #030303)'; h3.style.fontWeight = 'bold'; sectionDiv.appendChild(h3); if (description) { const desc = document.createElement('p'); desc.textContent = description; desc.style.margin = '4px 0 8px 0'; desc.style.fontSize = '0.9em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; sectionDiv.appendChild(desc); } return sectionDiv; }; const gridSection = section(L.yandexSection, L.yandexDesc); const createNumberInput = (id, label, value, min, max, description = '') => { const div = document.createElement('div'); div.style.marginBottom = '16px'; const labelDiv = document.createElement('div'); labelDiv.style.display = 'flex'; labelDiv.style.justifyContent = 'space-between'; labelDiv.style.marginBottom = '8px'; const labelEl = document.createElement('label'); labelEl.htmlFor = id; labelEl.textContent = label; labelEl.style.fontWeight = '500'; labelDiv.appendChild(labelEl); if (description) { const desc = document.createElement('div'); desc.textContent = description; desc.style.fontSize = '0.85em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; labelDiv.appendChild(desc); } div.appendChild(labelDiv); const input = document.createElement('input'); input.type = 'number'; input.id = id; input.value = value; input.min = min; input.max = max; input.style.width = '50%'; input.style.padding = '8px'; input.style.borderRadius = '10px'; input.style.border = '1px solid var(--yt-spec-10-percent-layer, #ddd)'; div.appendChild(input); return div; }; gridSection.appendChild(createNumberInput( 'yandexVideoCount', L.yandexVideoCount, config.yandexVideoCount, 1, 6 )); gridSection.appendChild(createNumberInput( 'yandexChipbarMargin', L.yandexChipbarMargin, config.yandexChipbarMargin, -100, 100 )); const videoMarginInput = createNumberInput( 'yandexVideoMargin', L.yandexVideoMargin, config.yandexVideoMargin, 0, 200 ); if (config.yandexExperimentalFix) { videoMarginInput.querySelector('input').disabled = true; videoMarginInput.style.opacity = '0.6'; } gridSection.appendChild(videoMarginInput); container.appendChild(gridSection); const expSection = section(L.yandexExpSection, L.yandexExpDesc); const createCheckbox = (id, label, checked, description = '', isExp = false) => { const div = document.createElement('div'); div.style.display = 'flex'; div.style.alignItems = 'flex-start'; div.style.marginBottom = '12px'; const input = document.createElement('input'); input.type = 'checkbox'; input.id = id; input.checked = checked; input.style.marginRight = '10px'; input.style.marginTop = '3px'; const labelDiv = document.createElement('div'); const labelEl = document.createElement('label'); labelEl.htmlFor = id; labelEl.textContent = label; labelEl.style.userSelect = 'none'; labelEl.style.fontWeight = '500'; labelDiv.appendChild(labelEl); if (isExp) { const expMark = document.createElement('span'); expMark.textContent = L.expMark; expMark.className = 'yt-enhancer-badge yt-enhancer-badge-exp'; labelDiv.appendChild(expMark); } if (description) { const desc = document.createElement('div'); desc.textContent = description; desc.style.fontSize = '0.85em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; desc.style.marginTop = '4px'; labelDiv.appendChild(desc); } div.appendChild(input); div.appendChild(labelDiv); return div; }; expSection.appendChild(createCheckbox( 'yandexGridFix', L.yandexGridFix, config.yandexGridFix, L.yandexGridFixDesc )); const perfModeCheckbox = createCheckbox( 'yandexPerformanceMode', L.yandexPerf, config.yandexPerformanceMode, L.yandexPerfDesc ); // Добавляем обработчик изменения для чекбокса плейлистов const playlistModeCheckbox = document.querySelector('#playlistModeFeature'); if (playlistModeCheckbox) { if (playlistModeCheckbox.checked) { perfModeCheckbox.querySelector('input').disabled = true; perfModeCheckbox.style.opacity = '0.5'; } playlistModeCheckbox.addEventListener('change', function() { const perfModeInput = perfModeCheckbox.querySelector('input'); if (this.checked) { perfModeInput.checked = false; perfModeInput.disabled = true; perfModeCheckbox.style.opacity = '0.5'; } else { perfModeInput.checked = true; perfModeInput.disabled = false; perfModeCheckbox.style.opacity = '1'; } }); } expSection.appendChild(perfModeCheckbox); expSection.appendChild(createCheckbox( 'yandexExperimentalFix', L.yandexExpFix, config.yandexExperimentalFix, L.yandexExpFixDesc, true )); if (config.yandexExperimentalFix) { const shiftDiv = document.createElement('div'); shiftDiv.style.marginBottom = '16px'; shiftDiv.style.marginLeft = '28px'; const shiftInput = createNumberInput( 'yandexSiteShift', L.yandexSiteShift, config.yandexSiteShift, 0, 500 ); shiftDiv.appendChild(shiftInput); expSection.appendChild(shiftDiv); } container.appendChild(expSection); } // --- Внешний вид вкладка --- function createAppearanceTab(container) { const section = (title, description = '') => { const sectionDiv = document.createElement('div'); sectionDiv.style.marginBottom = '16px'; const h3 = document.createElement('h3'); h3.textContent = title; h3.style.margin = '16px 0 8px 0'; h3.style.fontSize = '1.1em'; h3.style.color = 'var(--yt-spec-text-primary, #030303)'; h3.style.fontWeight = 'bold'; sectionDiv.appendChild(h3); if (description) { const desc = document.createElement('p'); desc.textContent = description; desc.style.margin = '4px 0 8px 0'; desc.style.fontSize = '0.9em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; sectionDiv.appendChild(desc); } return sectionDiv; }; const darkModeSection = section(L.appearanceSection, L.appearanceDesc); const createCheckbox = (id, label, checked, description = '') => { const div = document.createElement('div'); div.style.display = 'flex'; div.style.alignItems = 'flex-start'; div.style.marginBottom = '12px'; const input = document.createElement('input'); input.type = 'checkbox'; input.id = id; input.checked = checked; input.style.marginRight = '10px'; input.style.marginTop = '3px'; const labelDiv = document.createElement('div'); const labelEl = document.createElement('label'); labelEl.htmlFor = id; labelEl.textContent = label; labelEl.style.userSelect = 'none'; labelEl.style.fontWeight = '500'; labelDiv.appendChild(labelEl); if (description) { const desc = document.createElement('div'); desc.textContent = description; desc.style.fontSize = '0.85em'; desc.style.color = 'var(--yt-spec-text-secondary, #606060)'; desc.style.marginTop = '4px'; labelDiv.appendChild(desc); } div.appendChild(input); div.appendChild(labelDiv); return div; }; darkModeSection.appendChild(createCheckbox( 'darkModeSupport', L.darkModeSupport, config.darkModeSupport, L.darkModeSupportDesc )); container.appendChild(darkModeSection); const thumbSection = section(L.thumbSection, L.thumbDesc); const thumbSelect = document.createElement('select'); thumbSelect.id = 'customThumbnailSize'; thumbSelect.style.width = '50%'; thumbSelect.style.padding = '8px'; thumbSelect.style.borderRadius = '10px'; thumbSelect.style.marginBottom = '16px'; thumbSelect.style.border = '1px solid var(--yt-spec-10-percent-layer, #ddd)'; [ {value: 'default', label: L.thumbDefault}, {value: 'small', label: L.thumbSmall}, {value: 'medium', label: L.thumbMedium}, {value: 'large', label: L.thumbLarge} ].forEach(option => { const optEl = document.createElement('option'); optEl.value = option.value; optEl.textContent = option.label; if (option.value === config.customThumbnailSize) optEl.selected = true; thumbSelect.appendChild(optEl); }); thumbSection.appendChild(thumbSelect); container.appendChild(thumbSection); // --- Язык интерфейса выпадающим списком --- const langSection = section(L.langSection, L.langDesc); const langSelect = document.createElement('select'); langSelect.id = 'ytEnhancerUILang'; langSelect.style.width = '50%'; langSelect.style.padding = '8px'; langSelect.style.borderRadius = '10px'; langSelect.style.marginBottom = '16px'; langSelect.style.border = '1px solid var(--yt-spec-10-percent-layer, #ddd)'; [ {value: 'auto', label: L.langAuto}, {value: 'ru', label: L.ru}, {value: 'en', label: L.en} ].forEach(option => { const optEl = document.createElement('option'); optEl.value = option.value; optEl.textContent = option.label; if (getSavedUILang() === option.value) optEl.selected = true; langSelect.appendChild(optEl); }); langSection.appendChild(langSelect); container.appendChild(langSection); const themeSection = section(L.themeSection, L.themeDesc); const themeSelect = document.createElement('select'); themeSelect.id = 'enhancerTheme'; themeSelect.style.width = '50%'; themeSelect.style.padding = '8px'; themeSelect.style.borderRadius = '10px'; themeSelect.style.marginBottom = '16px'; themeSelect.style.border = '1px solid var(--yt-spec-10-percent-layer, #ddd)'; [ {value: 'darkpink', label: L.themeModernDarkPink}, {value: 'midnight', label: L.themeModernMidnight}, {value: 'frost', label: L.themeModernFrost}, {value: 'sky', label: L.themeModernSky}, {value: 'classic', label: L.themeModernClassic}, {value: 'dark', label: L.themeModernDark} ].forEach(option => { const optEl = document.createElement('option'); optEl.value = option.value; optEl.textContent = option.label; if (option.value === config.enhancerTheme) optEl.selected = true; themeSelect.appendChild(optEl); }); themeSection.appendChild(themeSelect); const fontSizeDiv = document.createElement('div'); fontSizeDiv.style.marginBottom = '16px'; const fontSizeLabel = document.createElement('label'); fontSizeLabel.htmlFor = 'enhancerFontSize'; fontSizeLabel.textContent = L.fontSize + ' '; fontSizeLabel.style.marginRight = '10px'; fontSizeLabel.style.fontWeight = '500'; const fontSizeInput = document.createElement('input'); fontSizeInput.type = 'range'; fontSizeInput.id = 'enhancerFontSize'; fontSizeInput.value = config.enhancerFontSize || 14; fontSizeInput.min = '12'; fontSizeInput.max = '20'; fontSizeInput.style.width = '200px'; fontSizeInput.style.marginRight = '10px'; const fontSizeValue = document.createElement('span'); fontSizeValue.textContent = `${config.enhancerFontSize || 14}px`; fontSizeValue.style.fontWeight = '500'; fontSizeInput.addEventListener('input', () => { fontSizeValue.textContent = `${fontSizeInput.value}px`; }); fontSizeDiv.appendChild(fontSizeLabel); fontSizeDiv.appendChild(fontSizeInput); fontSizeDiv.appendChild(fontSizeValue); themeSection.appendChild(fontSizeDiv); container.appendChild(themeSection); // --- Смена языка при выборе --- langSelect.addEventListener('change', () => { setSavedUILang(langSelect.value); uiLang = getCurrentUILang(); L = LANGS[uiLang]; document.getElementById('yt-enhancer-settings').remove(); setTimeout(createSettingsUI, 50); }); } // --- Показать уведомление --- function showNotification(message, duration = 3000) { const oldNotifications = document.querySelectorAll('.yt-enhancer-notification'); oldNotifications.forEach(n => n.remove()); const notification = document.createElement('div'); notification.className = 'yt-enhancer-notification'; notification.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: var(--yt-spec-brand-button-background, #065fd4); color: white; padding: 12px 24px; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 999999; animation: fadeIn 0.3s ease; font-family: 'Segoe UI', 'Roboto', Arial, sans-serif; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.style.animation = 'fadeOut 0.3s ease'; setTimeout(() => notification.remove(), 300); }, duration); if (!document.getElementById('yt-enhancer-notification-style')) { const style = document.createElement('style'); style.id = 'yt-enhancer-notification-style'; style.textContent = ` @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(10px); } } `; document.head.appendChild(style); } return notification; } // --- Показать предупреждение о плейлистах --- function showPlaylistWarning() { if (config.playlistModeFeature || !PLAYLIST_URL_REGEX.test(location.pathname)) return; const warning = document.createElement('div'); warning.className = 'yt-enhancer-playlist-warning'; warning.innerHTML = L.playlistModeWarning; document.body.appendChild(warning); setTimeout(() => warning.classList.add('show'), 1000); // Добавляем обработчик клика для открытия настроек warning.addEventListener('click', () => { createSettingsUI(); const mainTab = document.querySelector('#yt-enhancer-settings .yt-enhancer-tab[data-tab="0"]'); if (mainTab) mainTab.click(); }); // Автоматическое скрытие через 10 секунд setTimeout(() => { warning.classList.remove('show'); setTimeout(() => warning.remove(), 300); }, 10000); } // --- Добавить кнопку в интерфейс YouTube --- function addYouTubeButton() { const observer = new MutationObserver(() => { try { const header = document.querySelector('ytd-masthead #end'); if (header && !document.getElementById('yt-enhancer-btn')) { const button = document.createElement('button'); button.id = 'yt-enhancer-btn'; button.title = 'YouTube Fix for Yandex'; button.style.cssText = ` background: transparent; border: none; cursor: pointer; padding: 8px; margin-left: 8px; color: var(--yt-spec-text-primary); display: flex; align-items: center; justify-content: center; `; const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('width', '24'); svg.setAttribute('height', '24'); svg.style.verticalAlign = 'middle'; const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill', 'currentColor'); path.setAttribute('d', 'M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z'); svg.appendChild(path); button.appendChild(svg); button.addEventListener('click', (e) => { e.stopPropagation(); createSettingsUI(); }); header.insertBefore(button, header.firstChild); } } catch (e) { console.error('YouTube Fix for Yandex button error:', e); } }); observer.observe(document.body, {childList: true, subtree: true}); setTimeout(() => { const header = document.querySelector('ytd-masthead #end'); if (header && !document.getElementById('yt-enhancer-btn')) { const button = document.createElement('button'); button.id = 'yt-enhancer-btn'; button.title = 'YouTube Fix for Yandex'; button.style.cssText = ` background: transparent; border: none; cursor: pointer; padding: 8px; margin-left: 8px; color: var(--yt-spec-text-primary); display: flex; align-items: center; justify-content: center; `; const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('width', '24'); svg.setAttribute('height', '24'); svg.style.verticalAlign = 'middle'; const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill', 'currentColor'); path.setAttribute('d', 'M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z'); svg.appendChild(path); button.appendChild(svg); button.addEventListener('click', (e) => { e.stopPropagation(); createSettingsUI(); }); header.insertBefore(button, header.firstChild); } }, 1000); } // --- Проверка и активация режима плейлистов --- function checkPlaylistMode() { const isPlaylistPage = PLAYLIST_URL_REGEX.test(location.pathname); if (isPlaylistPage && !isPlaylistModeActive) { if (config.playlistModeFeature) { activatePlaylistMode(); } else { showPlaylistWarning(); } } else if (!isPlaylistPage && isPlaylistModeActive) { deactivatePlaylistMode(); } } // --- Активация режима плейлистов --- function activatePlaylistMode() { if (!config.playlistModeFeature) return; isPlaylistModeActive = true; document.documentElement.classList.add(PLAYLIST_MODE_CLASS); // Показываем уведомление showNotification(L.playlistModeNotification, 5000); // Добавляем стили для режима плейлистов addStyles(` .${PLAYLIST_MODE_CLASS} #yt-enhancer-settings .yt-enhancer-section:not(.playlist-mode-exception), .${PLAYLIST_MODE_CLASS} #yt-enhancer-settings .yt-enhancer-tab:not(.playlist-mode-exception), .${PLAYLIST_MODE_CLASS} #yt-enhancer-settings button:not(.playlist-mode-exception) { opacity: 0.5 !important; pointer-events: none !important; filter: grayscale(100%) !important; } .${PLAYLIST_MODE_CLASS} #yt-enhancer-btn { opacity: 1 !important; pointer-events: auto !important; } `); } // --- Деактивация режима плейлистов --- function deactivatePlaylistMode() { if (!config.playlistModeFeature) return; isPlaylistModeActive = false; document.documentElement.classList.remove(PLAYLIST_MODE_CLASS); // Показываем уведомление о перезагрузке const notification = showNotification( L.exitPlaylistModeNotification.replace('{seconds}', '2'), 2000 ); // Добавляем отсчет времени в уведомление let secondsLeft = 2; const interval = setInterval(() => { secondsLeft--; if (notification && notification.textContent) { notification.textContent = L.exitPlaylistModeNotification.replace('{seconds}', secondsLeft); } }, 1000); // Перезагружаем страницу через 2 секунды setTimeout(() => { clearInterval(interval); location.reload(); }, 2000); } // --- Инициализация --- function init() { applyStyles(); applyMainFeatures(); applyYandexFixes(); hideRFSlowWarning(); addYouTubeButton(); checkPlaylistMode(); // Оптимизированный наблюдатель для SPA-навигации let lastUrl = location.href; const spaObserver = new MutationObserver(() => { const currentUrl = location.href; if (currentUrl !== lastUrl) { lastUrl = currentUrl; // Используем requestAnimationFrame для оптимизации requestAnimationFrame(() => { checkPlaylistMode(); applyStyles(); applyMainFeatures(); applyYandexFixes(); hideRFSlowWarning(); }); } }); // Более точное наблюдение за изменениями spaObserver.observe(document, { subtree: true, childList: true, attributes: false, characterData: false }); // Уменьшим частоту проверки с 5 секунд до 10 секунд setInterval(() => { applyStyles(); applyMainFeatures(); applyYandexFixes(); hideRFSlowWarning(); }, 10000); } if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(init, 100); } else { document.addEventListener('DOMContentLoaded', init); window.addEventListener('load', init); } })();