Themes, cursors, effects, drawing!
// ==UserScript==
// @name YouTube ✨ Enhancer Pro
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Themes, cursors, effects, drawing!
// @author Bveery
// @match https://www.youtube.com/*
// @license GPL-3.0-or-later
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const cfg = {
theme: GM_getValue('theme', 'none'),
rbSpeed: GM_getValue('rbSpeed', 6),
cursor: GM_getValue('cursor', 'none'),
cursorEffect: GM_getValue('cursorEffect', 'none'),
cinema: GM_getValue('cinema', false),
menuColor: GM_getValue('menuColor', 'default'),
menuBlur: GM_getValue('menuBlur', false),
menuTransparent: GM_getValue('menuTransparent', false),
pauseOnMenu: GM_getValue('pauseOnMenu', false),
language: GM_getValue('language', 'en'),
seasonal: GM_getValue('seasonal', 'none'),
videoSpeed: GM_getValue('videoSpeed', 1),
videoVolume: GM_getValue('videoVolume', 100),
rememberPosition: GM_getValue('rememberPosition', false),
drawMode: GM_getValue('drawMode', false),
drawColor: GM_getValue('drawColor', '#ff2060'),
drawSize: GM_getValue('drawSize', 4),
};
function save(k, v) { cfg[k] = v; GM_setValue(k, v); }
const LANG = {
en: {
title: '✨ YT Enhancer Pro',
categories: { youtube: '▶️ YouTube', menu: '▶️ Menu', design: '▶️ Design', cursor: '▶️ Cursor' },
youtube: {
speedSection: 'Playback Speed',
speed: '⚡ Speed',
volumeSection: 'Volume',
volume: '▶️ Volume',
rememberSection: 'Remember Position',
remember: '▶️ Remember where I stopped',
},
menu: {
colorTitle: 'Menu Color',
blur: 'Blur Background',
transparent: 'Glass Effect',
pauseOnMenu: 'Pause on Menu',
lang: 'Language',
langEn: 'English',
langRu: 'Russian',
},
design: {
rbSection: 'Rainbow',
rainbow: 'Rainbow',
speed: 'Speed',
seasonal: 'Seasonal Theme',
s_none: 'None',
s_ny: 'New Year',
s_hw: 'Halloween',
cinSection: 'Cinema',
cinema: 'Cinema Mode',
},
cursor: {
drawSection: 'Drawing Mode',
drawMode: '▶️ Drawing Mode',
drawColor: '▶️ Brush Color',
drawSize: '▶️ Brush Size',
drawClear: '▶️ Clear Canvas',
cursorSection: 'Cursor Style',
none: 'Default',
heart: '❤️ Heart',
crosshair: '➕ Crosshair',
custom: '⭐ Star',
diamond: '💎 Diamond',
electro: '⚡ Electro',
effectSection: 'Cursor Effect',
fx_none: 'None',
fx_sparks: '✨ Sparks',
fx_hearts: '❤️ Hearts',
fx_snow: '❄️ Snow',
fx_rainbow: '🌈 Rainbow',
fx_stars: '⭐ Stars',
}
},
ru: {
title: '✨ YT Enhancer Pro',
categories: { youtube: '▶️ YouTube', menu: '▶️ Меню', design: '▶️ Дизайн', cursor: '▶️ Курсор' },
youtube: {
speedSection: 'Скорость воспроизведения',
speed: '⚡ Скорость',
volumeSection: 'Громкость',
volume: '▶️ Громкость',
rememberSection: 'Запомнить позицию',
remember: '▶️ Запомнить где остановился',
},
menu: {
colorTitle: 'Цвет меню',
blur: 'Блюр фона',
transparent: 'Эффект стекла',
pauseOnMenu: 'Пауза при меню',
lang: 'Язык',
langEn: 'English',
langRu: 'Русский',
},
design: {
rbSection: 'Радуга',
rainbow: 'Радуга',
speed: 'Скорость',
seasonal: 'Сезонная тема',
s_none: 'Выкл',
s_ny: 'Новый год',
s_hw: 'Хеллоуин',
cinSection: 'Кинотеатр',
cinema: 'Кинотеатр',
},
cursor: {
drawSection: 'Режим рисования',
drawMode: '▶️ Режим рисования',
drawColor: '▶️ Цвет кисти',
drawSize: '▶️ Размер кисти',
drawClear: '▶️ Очистить холст',
cursorSection: 'Стиль курсора',
none: 'Стандартный',
heart: '❤️ Сердечко',
crosshair: '➕ Перекрестие',
custom: '⭐ Звезда',
diamond: '💎 Алмаз',
electro: '⚡ Электро',
effectSection: 'Эффект курсора',
fx_none: 'Выкл',
fx_sparks: '✨ Искры',
fx_hearts: '❤️ Сердечки',
fx_snow: '❄️ Снег',
fx_rainbow: '🌈 Радуга',
fx_stars: '⭐ Звёзды',
}
}
};
function t(key) {
const keys = key.split('.');
let val = LANG[cfg.language] || LANG.en;
for (const k of keys) val = val?.[k];
return val ?? key;
}
const MENU_COLORS = {
default: { bg: 'linear-gradient(160deg,rgba(14,14,26,.95),rgba(19,19,42,.95))', text: '#eef', border: 'rgba(255,255,255,.2)' },
pink: { bg: 'linear-gradient(160deg,rgba(26,10,20,.95),rgba(42,16,32,.95))', text: '#ffd6e7', border: 'rgba(255,120,180,.35)' },
blue: { bg: 'linear-gradient(160deg,rgba(10,16,26,.95),rgba(16,26,42,.95))', text: '#d6e7ff', border: 'rgba(120,180,255,.35)' },
green: { bg: 'linear-gradient(160deg,rgba(10,26,16,.95),rgba(16,42,24,.95))', text: '#d6ffe0', border: 'rgba(120,255,180,.35)' },
purple: { bg: 'linear-gradient(160deg,rgba(26,10,31,.95),rgba(42,16,48,.95))', text: '#e7d6ff', border: 'rgba(180,120,255,.35)' },
orange: { bg: 'linear-gradient(160deg,rgba(26,18,10,.95),rgba(42,28,16,.95))', text: '#ffe7d6', border: 'rgba(255,180,120,.35)' },
red: { bg: 'linear-gradient(160deg,rgba(26,8,8,.95),rgba(42,16,16,.95))', text: '#ffd6d6', border: 'rgba(255,120,120,.35)' },
cyan: { bg: 'linear-gradient(160deg,rgba(10,26,31,.95),rgba(16,42,48,.95))', text: '#d6ffff', border: 'rgba(120,255,255,.35)' },
};
const COLOR_CHIPS = {
default: '#8888ff', pink: '#ff78b4', blue: '#78b4ff', green: '#78ffb4',
purple: '#b478ff', orange: '#ffb478', red: '#ff7878', cyan: '#78ffff',
};
// ══════════════════════════════════════════════════════════════
// КУРСОРЫ
// ══════════════════════════════════════════════════════════════
function getCursorStyle(key) {
if (key === 'none') return '';
if (key === 'crosshair') return 'crosshair';
if (key === 'heart') {
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">'
+ '<path d="M16 28s-14-9-14-18a8 8 0 0 1 14-5.3A8 8 0 0 1 30 10c0 9-14 18-14 18z" fill="#ff2060" stroke="#ff80a0" stroke-width="1.5"/>'
+ '</svg>';
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '") 16 28, auto';
}
if (key === 'custom') {
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">'
+ '<polygon points="16,2 20,12 30,12 22,19 25,30 16,23 7,30 10,19 2,12 12,12" fill="gold" stroke="orange" stroke-width="1"/>'
+ '</svg>';
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '") 16 16, auto';
}
if (key === 'diamond') {
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="36" viewBox="0 0 32 36">'
+ '<defs><linearGradient id="dg" x1="0" y1="0" x2="1" y2="1">'
+ '<stop offset="0%" stop-color="#a0f0ff" stop-opacity="0.7"/>'
+ '<stop offset="50%" stop-color="#00c8ff" stop-opacity="0.5"/>'
+ '<stop offset="100%" stop-color="#0055aa" stop-opacity="0.7"/>'
+ '</linearGradient></defs>'
+ '<polygon points="16,2 30,12 16,34 2,12" fill="url(#dg)" opacity="0.85"/>'
+ '<polygon points="16,2 30,12 16,34 2,12" fill="none" stroke="#00eeff" stroke-width="1.5" opacity="0.9"/>'
+ '<polygon points="16,2 30,12 16,12" fill="rgba(180,240,255,0.55)"/>'
+ '<polygon points="2,12 16,12 16,34" fill="rgba(0,180,220,0.45)"/>'
+ '<polygon points="30,12 16,12 16,34" fill="rgba(0,120,180,0.45)"/>'
+ '<line x1="2" y1="12" x2="30" y2="12" stroke="#00eeff" stroke-width="1" opacity="0.7"/>'
+ '<line x1="16" y1="2" x2="2" y2="12" stroke="#aaf8ff" stroke-width="0.8" opacity="0.6"/>'
+ '<line x1="16" y1="2" x2="30" y2="12" stroke="#aaf8ff" stroke-width="0.8" opacity="0.6"/>'
+ '<circle cx="16" cy="10" r="2.5" fill="white" opacity="0.9"/>'
+ '</svg>';
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '") 16 2, auto';
}
if (key === 'electro') {
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">'
+ '<defs>'
+ '<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">'
+ '<feGaussianBlur stdDeviation="1.5" result="blur"/>'
+ '<feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>'
+ '</filter>'
+ '<linearGradient id="eg" x1="0" y1="0" x2="0" y2="1">'
+ '<stop offset="0%" stop-color="#ffffff" stop-opacity="0.9"/>'
+ '<stop offset="100%" stop-color="#ff9900" stop-opacity="0.3"/>'
+ '</linearGradient>'
+ '</defs>'
+ '<g filter="url(#glow)">'
+ '<polygon points="19,2 10,16 16,16 13,30 23,14 17,14" fill="#ffe44d" stroke="#ffffff" stroke-width="0.5" opacity="0.95"/>'
+ '<polygon points="19,2 10,16 16,16 13,30 23,14 17,14" fill="url(#eg)" opacity="0.6"/>'
+ '</g>'
+ '</svg>';
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '") 16 2, auto';
}
return '';
}
const CURSOR_KEYS = ['none', 'heart', 'crosshair', 'custom', 'diamond', 'electro'];
// ══════════════════════════════════════════════════════════════
// РЕЖИМ РИСОВАНИЯ
// ══════════════════════════════════════════════════════════════
let drawCanvas = null;
let drawCtx = null;
let isDrawing = false;
let lastX = 0;
let lastY = 0;
const DRAW_COLORS = [
{ color: '#ff2060' }, { color: '#ff8c00' },
{ color: '#ffdd00' }, { color: '#00dd44' },
{ color: '#0088ff' }, { color: '#8855ff' },
{ color: '#ffffff' }, { color: '#000000' },
];
function ensureDrawCanvas() {
if (drawCanvas) return;
drawCanvas = document.createElement('canvas');
drawCanvas.id = 'yt-draw-canvas';
drawCanvas.width = window.innerWidth;
drawCanvas.height = window.innerHeight;
drawCanvas.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2147483644;pointer-events:none;';
document.documentElement.appendChild(drawCanvas);
drawCtx = drawCanvas.getContext('2d');
window.addEventListener('resize', () => {
const img = drawCtx.getImageData(0, 0, drawCanvas.width, drawCanvas.height);
drawCanvas.width = window.innerWidth;
drawCanvas.height = window.innerHeight;
drawCtx.putImageData(img, 0, 0);
});
}
function startDrawMode() {
ensureDrawCanvas();
drawCanvas.style.pointerEvents = 'all';
drawCanvas.style.cursor = 'crosshair';
drawCanvas.addEventListener('mousedown', onDrawStart);
drawCanvas.addEventListener('mousemove', onDrawMove);
drawCanvas.addEventListener('mouseup', onDrawEnd);
drawCanvas.addEventListener('mouseleave', onDrawEnd);
showToast('✏️ Drawing ON — hold LMB to draw!');
}
function stopDrawMode() {
if (!drawCanvas) return;
drawCanvas.style.pointerEvents = 'none';
drawCanvas.removeEventListener('mousedown', onDrawStart);
drawCanvas.removeEventListener('mousemove', onDrawMove);
drawCanvas.removeEventListener('mouseup', onDrawEnd);
drawCanvas.removeEventListener('mouseleave', onDrawEnd);
isDrawing = false;
showToast('⏹️ Drawing OFF');
}
function clearDrawCanvas() {
if (!drawCtx || !drawCanvas) return;
drawCtx.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
showToast('🧹 Canvas cleared!');
}
function onDrawStart(e) {
isDrawing = true;
lastX = e.clientX; lastY = e.clientY;
drawCtx.beginPath();
drawCtx.arc(lastX, lastY, cfg.drawSize / 2, 0, Math.PI * 2);
drawCtx.fillStyle = cfg.drawColor;
drawCtx.shadowBlur = cfg.drawSize;
drawCtx.shadowColor = cfg.drawColor;
drawCtx.fill();
}
function onDrawMove(e) {
if (!isDrawing) return;
drawCtx.beginPath();
drawCtx.moveTo(lastX, lastY);
drawCtx.lineTo(e.clientX, e.clientY);
drawCtx.strokeStyle = cfg.drawColor;
drawCtx.lineWidth = cfg.drawSize;
drawCtx.lineCap = 'round';
drawCtx.lineJoin = 'round';
drawCtx.shadowBlur = cfg.drawSize * 0.8;
drawCtx.shadowColor = cfg.drawColor;
drawCtx.stroke();
lastX = e.clientX; lastY = e.clientY;
}
function onDrawEnd() {
isDrawing = false;
if (drawCtx) drawCtx.shadowBlur = 0;
}
function applyDrawMode() {
const on = cfg.drawMode === true || cfg.drawMode === 'true';
if (on) startDrawMode(); else stopDrawMode();
}
// ══════════════════════════════════════════════════════════════
// ЭФФЕКТЫ КУРСОРА
// ══════════════════════════════════════════════════════════════
let fxCanvas = null, fxCtx = null, fxRAF = null;
let fxParticles = [], fxMouseX = 0, fxMouseY = 0;
let fxMouseMoved = false, fxMoveHandler = null;
let fxActive = false, fxType = 'none';
function ensureFxCanvas() {
if (fxCanvas) return;
fxCanvas = document.createElement('canvas');
fxCanvas.id = 'yt-cursor-fx';
fxCanvas.width = window.innerWidth;
fxCanvas.height = window.innerHeight;
fxCanvas.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483643;';
document.documentElement.appendChild(fxCanvas);
fxCtx = fxCanvas.getContext('2d');
window.addEventListener('resize', () => {
fxCanvas.width = window.innerWidth;
fxCanvas.height = window.innerHeight;
});
}
function spawnFxParticles(x, y) {
switch (fxType) {
case 'sparks': {
const colors = ['#ff2060','#ff8c00','#ffdd00','#ff4488','#ff6600','#ffffff'];
for (let i = 0; i < 3 + Math.floor(Math.random()*4); i++) {
const a = Math.random()*Math.PI*2, s = 2+Math.random()*4;
fxParticles.push({ x, y, vx:Math.cos(a)*s, vy:Math.sin(a)*s-2, life:1,
decay:0.035+Math.random()*0.035, size:2+Math.random()*3,
color:colors[Math.floor(Math.random()*colors.length)], type:'spark' });
}
break;
}
case 'hearts':
if (Math.random()>0.35) break;
fxParticles.push({ x:x+(Math.random()-0.5)*24, y, vx:(Math.random()-0.5)*1.2,
vy:-(1.5+Math.random()*2.5), life:1, decay:0.018+Math.random()*0.018,
size:12+Math.random()*14, type:'heart' });
break;
case 'snow':
if (Math.random()>0.3) break;
fxParticles.push({ x:x+(Math.random()-0.5)*20, y, vx:(Math.random()-0.5)*0.6,
vy:0.8+Math.random()*1.5, life:1, decay:0.012+Math.random()*0.012,
size:10+Math.random()*12, type:'snow' });
break;
case 'rainbow': {
for (let i = 0; i < 2+Math.floor(Math.random()*3); i++) {
const hue=Math.random()*360, a=Math.random()*Math.PI*2, s=0.8+Math.random()*1.5;
fxParticles.push({ x:x+(Math.random()-0.5)*8, y:y+(Math.random()-0.5)*8,
vx:Math.cos(a)*s, vy:Math.sin(a)*s-0.5, life:1, decay:0.012+Math.random()*0.012,
size:6+Math.random()*8, color:'hsl('+hue+',100%,65%)', type:'dot' });
}
break;
}
case 'stars':
if (Math.random()>0.4) break;
fxParticles.push({ x:x+(Math.random()-0.5)*24, y:y+(Math.random()-0.5)*24,
vx:(Math.random()-0.5)*1, vy:-(0.5+Math.random()*1.5), life:1,
decay:0.015+Math.random()*0.015, size:12+Math.random()*16, type:'star' });
break;
}
}
function renderParticle(p) {
fxCtx.save();
fxCtx.globalAlpha = Math.max(0, p.life);
switch (p.type) {
case 'spark':
fxCtx.shadowBlur=12; fxCtx.shadowColor=p.color; fxCtx.strokeStyle=p.color;
fxCtx.lineWidth=p.size*p.life; fxCtx.lineCap='round';
fxCtx.beginPath(); fxCtx.moveTo(p.x,p.y); fxCtx.lineTo(p.x-p.vx*3,p.y-p.vy*3); fxCtx.stroke();
fxCtx.fillStyle='#fff'; fxCtx.shadowBlur=6;
fxCtx.beginPath(); fxCtx.arc(p.x,p.y,p.size*p.life*0.6,0,Math.PI*2); fxCtx.fill();
break;
case 'dot': {
const g = fxCtx.createRadialGradient(p.x,p.y,0,p.x,p.y,p.size);
g.addColorStop(0,p.color); g.addColorStop(1,'transparent');
fxCtx.fillStyle=g; fxCtx.beginPath(); fxCtx.arc(p.x,p.y,p.size,0,Math.PI*2); fxCtx.fill();
break;
}
default:
fxCtx.font=p.size+'px serif'; fxCtx.textAlign='center'; fxCtx.textBaseline='middle';
fxCtx.fillText(
p.type==='heart' ? '❤️' : p.type==='snow' ? '❄️' : '⭐',
p.x, p.y
);
}
fxCtx.restore();
}
function fxLoop() {
fxRAF = requestAnimationFrame(fxLoop);
fxCtx.clearRect(0,0,fxCanvas.width,fxCanvas.height);
if (fxActive && fxMouseMoved && fxType!=='none') {
spawnFxParticles(fxMouseX, fxMouseY);
fxMouseMoved = false;
}
const alive = [];
for (const p of fxParticles) {
p.x+=p.vx; p.y+=p.vy; p.vy+=0.06; p.life-=p.decay;
if (p.life>0) { renderParticle(p); alive.push(p); }
}
fxParticles = alive;
}
function stopCursorEffect() {
fxActive=false; fxType='none';
if (fxMoveHandler) { document.removeEventListener('mousemove',fxMoveHandler); fxMoveHandler=null; }
fxParticles=[];
if (fxCtx&&fxCanvas) fxCtx.clearRect(0,0,fxCanvas.width,fxCanvas.height);
}
function startCursorEffect(type) {
stopCursorEffect();
if (type==='none') return;
ensureFxCanvas();
fxType=type; fxActive=true;
if (!fxRAF) fxLoop();
fxMoveHandler = e => { fxMouseX=e.clientX; fxMouseY=e.clientY; fxMouseMoved=true; };
document.addEventListener('mousemove',fxMoveHandler);
}
// ══════════════════════════════════════════════════════════════
// ЗАПОМНИТЬ ПОЗИЦИЮ
// ══════════════════════════════════════════════════════════════
const POSITIONS_KEY = 'yt_pro_positions';
function loadPositions() { try { return JSON.parse(GM_getValue(POSITIONS_KEY,'{}')); } catch(e) { return {}; } }
function savePosition(id,t) { const p=loadPositions(); p[id]=t; const k=Object.keys(p); if(k.length>200) delete p[k[0]]; GM_setValue(POSITIONS_KEY,JSON.stringify(p)); }
function getSavedPosition(id) { return loadPositions()[id]||0; }
let positionRestored=false;
function startPositionWatcher() {
setInterval(()=>{
if (!(cfg.rememberPosition===true||cfg.rememberPosition==='true')) return;
const id=new URLSearchParams(window.location.search).get('v');
const v=document.querySelector('video');
if (id&&v&&!v.paused&&v.currentTime>3) savePosition(id,v.currentTime);
},1000);
let lastUrl=location.href;
new MutationObserver(()=>{
if (location.href!==lastUrl) { lastUrl=location.href; positionRestored=false; setTimeout(restorePosition,2000); }
}).observe(document.documentElement,{childList:true,subtree:true});
setTimeout(restorePosition,2500);
}
function restorePosition() {
if (!(cfg.rememberPosition===true||cfg.rememberPosition==='true')) return;
if (positionRestored) return;
const id=new URLSearchParams(window.location.search).get('v');
if (!id) return;
const saved=getSavedPosition(id);
if (saved<3) return;
const v=document.querySelector('video');
if (!v) { setTimeout(restorePosition,1000); return; }
if (v.duration&&saved<v.duration-10) { v.currentTime=saved; positionRestored=true; showToast('🕒 Resumed from '+formatTime(saved)); }
}
function formatTime(sec) {
sec=Math.floor(sec);
const h=Math.floor(sec/3600), m=Math.floor((sec%3600)/60), s=sec%60;
if (h>0) return h+':'+String(m).padStart(2,'0')+':'+String(s).padStart(2,'0');
return m+':'+String(s).padStart(2,'0');
}
// ══════════════════════════════════════════════════════════════
// TOAST
// ══════════════════════════════════════════════════════════════
function showToast(msg) {
let toast=document.getElementById('yt-pro-toast');
if (!toast) { toast=document.createElement('div'); toast.id='yt-pro-toast'; document.documentElement.appendChild(toast); }
toast.textContent=msg;
toast.style.opacity='1';
toast.style.transform='translateX(-50%) translateY(0)';
clearTimeout(toast._timer);
toast._timer=setTimeout(()=>{ toast.style.opacity='0'; toast.style.transform='translateX(-50%) translateY(20px)'; },3000);
}
// ══════════════════════════════════════════════════════════════
// ВИДЕО
// ══════════════════════════════════════════════════════════════
let audioCtx=null, gainNode=null, mediaSource=null;
function setupAudioBoost(v) {
if (!v||v._ytProBoosted) return;
try {
if (!audioCtx) audioCtx=new (window.AudioContext||window.webkitAudioContext)();
if (gainNode) { try{gainNode.disconnect();}catch(e){} }
if (mediaSource) { try{mediaSource.disconnect();}catch(e){} }
mediaSource=audioCtx.createMediaElementSource(v);
gainNode=audioCtx.createGain();
mediaSource.connect(gainNode); gainNode.connect(audioCtx.destination);
v._ytProBoosted=true; applyVideoVolume(cfg.videoVolume);
} catch(e) { console.warn('[YT Pro]',e); }
}
function applyVideoSpeed(val) { const v=document.querySelector('video'); if(v) v.playbackRate=parseFloat(val); }
function applyVideoVolume(val) {
const pct=parseFloat(val), v=document.querySelector('video');
if (!v) return;
if (pct<=100) { v.volume=pct/100; if(gainNode) gainNode.gain.value=1; }
else { if(!v._ytProBoosted) setupAudioBoost(v); v.volume=1; if(gainNode) gainNode.gain.value=pct/100; }
}
function watchVideo() {
new MutationObserver(()=>{
const v=document.querySelector('video');
if (v) { if(!v._ytProBoosted&&cfg.videoVolume>100) setupAudioBoost(v); v.playbackRate=parseFloat(cfg.videoSpeed); applyVideoVolume(cfg.videoVolume); }
}).observe(document.body,{childList:true,subtree:true});
document.addEventListener('loadeddata',()=>{
const v=document.querySelector('video');
if (v) { if(!v._ytProBoosted) setupAudioBoost(v); applyVideoSpeed(cfg.videoSpeed); applyVideoVolume(cfg.videoVolume); }
},true);
}
let wePaused=false;
function pauseVideo() { const v=document.querySelector('video'); if(v&&!v.paused){v.pause();return true;} return false; }
function resumeVideo() { const v=document.querySelector('video'); if(v&&v.paused) v.play(); }
// ══════════════════════════════════════════════════════════════
// СЕЗОННЫЕ ТЕМЫ
// ══════════════════════════════════════════════════════════════
const PARTICLE_CONFIG = {
ny:{ count:60, emojis:['❄️','❅','❆','⛄','🌨️'], sizes:[14,18,22,26], speed:[6,14],
css:`html.yt-ny ytd-app,html.yt-ny #content{background:linear-gradient(180deg,#0a1628 0%,#0d2044 40%,#0a1628 100%)!important}
html.yt-ny #masthead{background:linear-gradient(90deg,#0d2a5e,#1a4a8a,#0d2a5e)!important;border-bottom:2px solid #4af!important;box-shadow:0 2px 20px rgba(100,180,255,0.4)!important}
html.yt-ny ytd-guide-renderer,html.yt-ny #guide-inner-content{background:linear-gradient(180deg,#0a1e40,#0d2855)!important}
html.yt-ny yt-formatted-string,html.yt-ny #video-title,html.yt-ny .title{color:#c8e8ff!important}
html.yt-ny ytd-thumbnail{border-radius:10px!important;box-shadow:0 0 12px rgba(150,210,255,0.25)!important}` },
hw:{ count:40, emojis:['🎃','👻','🕷️','🦇','💀'], sizes:[18,22,28,34], speed:[5,12],
css:`html.yt-hw ytd-app,html.yt-hw #content{background:linear-gradient(180deg,#0d0500 0%,#1a0a00 40%,#0d0500 100%)!important}
html.yt-hw #masthead{background:linear-gradient(90deg,#1a0a00,#2d1200,#1a0a00)!important;border-bottom:2px solid #c05000!important;box-shadow:0 2px 20px rgba(200,80,0,0.5)!important}
html.yt-hw ytd-guide-renderer,html.yt-hw #guide-inner-content{background:linear-gradient(180deg,#120600,#1e0e00)!important}
html.yt-hw yt-formatted-string,html.yt-hw #video-title,html.yt-hw .title{color:#ffb060!important}
html.yt-hw ytd-thumbnail{border-radius:10px!important;box-shadow:0 0 14px rgba(200,80,0,0.3)!important}` }
};
let particleContainer=null, particleInterval=null;
function clearParticles() { particleContainer?.remove(); particleContainer=null; if(particleInterval){clearInterval(particleInterval);particleInterval=null;} }
function spawnParticle(pcfg) {
if (!particleContainer) return;
const span=document.createElement('span');
const emoji=pcfg.emojis[Math.floor(Math.random()*pcfg.emojis.length)];
const size=pcfg.sizes[Math.floor(Math.random()*pcfg.sizes.length)];
const left=Math.random()*100, dur=pcfg.speed[0]+Math.random()*(pcfg.speed[1]-pcfg.speed[0]);
const delay=Math.random()*-dur, wobbleX=(Math.random()-0.5)*80;
span.textContent=emoji;
span.style.cssText=['position:fixed','top:-60px','left:'+left+'vw','font-size:'+size+'px',
'opacity:'+(0.6+Math.random()*0.4),'pointer-events:none','z-index:2147483630','user-select:none',
'animation:yt-particle-fall '+dur+'s linear '+delay+'s infinite','--wobble:'+wobbleX+'px'].join(';');
particleContainer.appendChild(span);
if (particleContainer.children.length>pcfg.count+10) particleContainer.children[0].remove();
}
function startParticles(type) {
clearParticles(); if(type==='none') return;
const pcfg=PARTICLE_CONFIG[type]; if(!pcfg) return;
particleContainer=document.createElement('div');
particleContainer.id='yt-particles';
particleContainer.style.cssText='position:fixed;inset:0;pointer-events:none;z-index:2147483630;overflow:hidden';
document.documentElement.appendChild(particleContainer);
for (let i=0;i<pcfg.count;i++) setTimeout(()=>spawnParticle(pcfg),i*150);
particleInterval=setInterval(()=>spawnParticle(pcfg),600);
}
let seasonStyleEl=null;
function setSeasonStyle() {
if (!seasonStyleEl) { seasonStyleEl=document.createElement('style'); seasonStyleEl.id='yt-season-style'; document.head.appendChild(seasonStyleEl); }
document.documentElement.classList.remove('yt-ny','yt-hw');
if (cfg.seasonal==='ny') {
seasonStyleEl.textContent=PARTICLE_CONFIG.ny.css+'@keyframes yt-particle-fall{0%{transform:translateY(0) translateX(0) rotate(0deg);opacity:1}50%{transform:translateY(50vh) translateX(var(--wobble)) rotate(180deg)}100%{transform:translateY(110vh) translateX(0) rotate(360deg);opacity:0.3}}';
document.documentElement.classList.add('yt-ny'); startParticles('ny');
} else if (cfg.seasonal==='hw') {
seasonStyleEl.textContent=PARTICLE_CONFIG.hw.css+'@keyframes yt-particle-fall{0%{transform:translateY(0) translateX(0) rotate(-10deg);opacity:1}25%{transform:translateY(25vh) translateX(var(--wobble)) rotate(10deg)}50%{transform:translateY(50vh) translateX(0) rotate(-15deg)}75%{transform:translateY(75vh) translateX(calc(var(--wobble)*-0.5)) rotate(8deg)}100%{transform:translateY(110vh) translateX(0) rotate(-5deg);opacity:0.2}}';
document.documentElement.classList.add('yt-hw'); startParticles('hw');
} else { seasonStyleEl.textContent=''; clearParticles(); }
}
let rbStyleEl=null;
function setRainbowStyle() {
if (!rbStyleEl) { rbStyleEl=document.createElement('style'); rbStyleEl.id='yt-rb-style'; document.head.appendChild(rbStyleEl); }
if (cfg.theme!=='rainbow') { rbStyleEl.textContent=''; return; }
const spd=Number(cfg.rbSpeed)+'s';
rbStyleEl.textContent=[
'@keyframes yt-rb-hue{0%{filter:hue-rotate(0deg)}100%{filter:hue-rotate(360deg)}}',
'@keyframes yt-rb-pos{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}',
'html.yt-rb-on{animation:yt-rb-hue '+spd+' linear infinite!important}',
'#yt-rb-overlay{position:fixed!important;inset:0!important;z-index:2147483640!important;pointer-events:none!important;background:linear-gradient(135deg,rgba(255,0,0,.15),rgba(255,120,0,.15),rgba(255,255,0,.15),rgba(0,255,80,.15),rgba(0,200,255,.15),rgba(80,0,255,.15),rgba(255,0,200,.15),rgba(255,0,0,.15))!important;background-size:400% 400%!important;animation:yt-rb-pos '+spd+' ease infinite!important;mix-blend-mode:color!important;}'
].join('');
}
function syncRainbowOverlay() {
let ov=document.getElementById('yt-rb-overlay');
if (cfg.theme==='rainbow') {
if(!ov){ov=document.createElement('div');ov.id='yt-rb-overlay';document.documentElement.appendChild(ov);}
document.documentElement.classList.add('yt-rb-on');
} else { ov?.remove(); document.documentElement.classList.remove('yt-rb-on'); }
}
// ══════════════════════════════════════════════════════════════
// СТИЛИ
// ══════════════════════════════════════════════════════════════
GM_addStyle([
"@import url('https://fonts.googleapis.com/css2?family=Exo+2:wght@400;600;900&display=swap');",
'#yt-proroot{position:fixed!important;top:0!important;left:0!important;width:0!important;height:0!important;overflow:visible!important;z-index:2147483647!important;pointer-events:none!important;transform:none!important;}',
'#yt-pro-menu{position:fixed!important;border-radius:16px;box-shadow:0 20px 60px rgba(0,0,0,0.9);display:flex;visibility:hidden;opacity:0;pointer-events:none;flex-direction:row;overflow:hidden;font-family:"Exo 2",sans-serif;color:#eef;z-index:2147483647;transition:opacity .35s ease,visibility 0s linear .35s;border:1px solid rgba(255,255,255,0.15);width:650px;height:530px;}',
'#yt-pro-menu.active{visibility:visible!important;opacity:1!important;pointer-events:all!important;transition:opacity .35s ease,visibility 0s linear 0s;}',
'#yt-pro-menu.dragging{transition:none!important;user-select:none!important;}',
'.yt-sidebar{width:180px;background:rgba(0,0,0,0.3);border-right:1px solid rgba(255,255,255,0.08);padding:20px 10px;display:flex;flex-direction:column;gap:10px;flex-shrink:0;}',
'.yt-sidebar-credit{margin-top:auto;padding-top:10px;font-size:10px;color:rgba(255,255,255,0.2);text-align:center;line-height:1.5;user-select:none;letter-spacing:0.3px;}',
'.yt-nav-btn{padding:12px;border-radius:10px;cursor:pointer;font-weight:600;color:#888;transition:all .25s;display:flex;align-items:center;gap:10px;user-select:none;}',
'.yt-nav-btn:hover{color:#ccc;background:rgba(255,255,255,0.05);}',
'.yt-nav-btn.sel{background:linear-gradient(90deg,rgba(255,32,96,0.2),rgba(136,85,255,0.2));color:#fff;border-left:3px solid #ff2060;}',
'.yt-content{flex:1;padding:20px;overflow-y:auto;}',
'.yt-content::-webkit-scrollbar{width:4px;}',
'.yt-content::-webkit-scrollbar-track{background:transparent;}',
'.yt-content::-webkit-scrollbar-thumb{background:rgba(136,85,255,0.5);border-radius:2px;}',
'.yt-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;border-bottom:1px solid rgba(255,255,255,0.1);padding-bottom:10px;cursor:grab;user-select:none;}',
'.yt-header:active{cursor:grabbing;}',
'.yt-title{font-size:20px;font-weight:900;background:linear-gradient(90deg,#ff2060,#8855ff);-webkit-background-clip:text;-webkit-text-fill-color:transparent;pointer-events:none;}',
'.yt-close{cursor:pointer!important;font-size:24px;line-height:1;opacity:0.7;transition:opacity .2s;pointer-events:all!important;}',
'.yt-close:hover{opacity:1;}',
'.yt-section{display:none;}',
'.yt-section.show{display:block;}',
'.yt-row{display:flex;align-items:center;justify-content:space-between;padding:12px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:12px;margin-bottom:8px;cursor:pointer;transition:border-color .2s,background .2s;user-select:none;}',
'.yt-row:hover{background:rgba(255,255,255,0.07);}',
'.yt-row.active{border-color:#8855ff;background:rgba(136,85,255,0.13);}',
'.yt-draw-colors{display:flex;flex-wrap:wrap;gap:8px;padding:10px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:12px;margin-bottom:8px;}',
'.yt-draw-color{width:28px;height:28px;border-radius:50%;cursor:pointer;border:3px solid transparent;transition:all .2s;flex-shrink:0;}',
'.yt-draw-color:hover{transform:scale(1.2);}',
'.yt-draw-color.active{border-color:#fff!important;transform:scale(1.25);box-shadow:0 0 10px rgba(255,255,255,0.5);}',
'.yt-clear-btn{width:100%;padding:10px;border-radius:12px;border:1.5px solid rgba(255,80,80,0.4);background:rgba(255,50,50,0.08);color:#ff8080;font-family:"Exo 2",sans-serif;font-size:13px;font-weight:700;cursor:pointer;transition:all .2s;margin-bottom:8px;letter-spacing:0.5px;}',
'.yt-clear-btn:hover{background:rgba(255,50,50,0.2);border-color:rgba(255,80,80,0.8);color:#fff;box-shadow:0 0 12px rgba(255,50,50,0.3);}',
'.yt-fx-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:8px;}',
'.yt-fx-card{border-radius:12px;border:2px solid rgba(255,255,255,0.08);padding:12px 6px;text-align:center;cursor:pointer;transition:all .25s;user-select:none;background:rgba(255,255,255,0.03);}',
'.yt-fx-card:hover{background:rgba(255,255,255,0.07);border-color:rgba(255,255,255,0.2);}',
'.yt-fx-card.active{border-color:#ff2060;background:rgba(255,32,96,0.13);box-shadow:0 0 14px rgba(255,32,96,0.2);}',
'.yt-fx-icon{font-size:24px;display:block;margin-bottom:4px;}',
'.yt-fx-label{font-size:11px;font-weight:700;letter-spacing:.3px;color:#aaa;}',
'.yt-fx-card.active .yt-fx-label{color:#ff8099;}',
'.yt-slider-row{padding:14px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:12px;margin-bottom:8px;}',
'.yt-slider-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;}',
'.yt-slider-label{font-size:13px;font-weight:600;}',
'.yt-slider-val{font-size:13px;font-weight:700;background:linear-gradient(90deg,#ff2060,#8855ff);-webkit-background-clip:text;-webkit-text-fill-color:transparent;min-width:50px;text-align:right;}',
'.yt-lang-block{background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:12px;margin-bottom:8px;overflow:hidden;}',
'.yt-lang-header{display:flex;align-items:center;justify-content:space-between;padding:12px;cursor:pointer;user-select:none;transition:background .2s;}',
'.yt-lang-header:hover{background:rgba(255,255,255,0.04);}',
'.yt-lang-header-left{display:flex;align-items:center;gap:8px;}',
'.yt-lang-arrow{font-size:10px;color:#666;transition:transform .3s;display:inline-block;}',
'.yt-lang-arrow.open{transform:rotate(180deg);}',
'.yt-lang-body{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(0.4,0,0.2,1);}',
'.yt-lang-body.open{max-height:200px;}',
'.yt-lang-options{padding:6px 10px 12px;display:flex;flex-direction:column;gap:6px;}',
'.yt-lang-option{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:10px;cursor:pointer;transition:background .2s,border-color .2s;border:1.5px solid rgba(255,255,255,0.06);user-select:none;}',
'.yt-lang-option:hover{background:rgba(255,255,255,0.06);}',
'.yt-lang-option.active{border-color:#8855ff;background:rgba(136,85,255,0.13);}',
'.yt-lang-flag{font-size:20px;}',
'.yt-lang-name{font-weight:600;font-size:14px;}',
'.yt-lang-check{margin-left:auto;color:#8855ff;font-size:16px;}',
'.yt-season-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:8px;}',
'.yt-season-card{border-radius:14px;border:2px solid rgba(255,255,255,0.08);padding:14px 8px;text-align:center;cursor:pointer;transition:all .25s;user-select:none;position:relative;overflow:hidden;}',
'.yt-season-card::before{content:"";position:absolute;inset:0;opacity:0;transition:opacity .25s;}',
'.yt-season-card:hover::before{opacity:1;}',
'.yt-season-card .sc-icon{font-size:32px;display:block;margin-bottom:6px;}',
'.yt-season-card .sc-label{font-size:12px;font-weight:700;letter-spacing:.5px;}',
'.yt-season-card.sc-none{background:rgba(255,255,255,0.03);}',
'.yt-season-card.sc-none::before{background:rgba(255,255,255,0.04);}',
'.yt-season-card.sc-none.active{border-color:#8855ff;background:rgba(136,85,255,0.15);}',
'.yt-season-card.sc-ny{background:linear-gradient(145deg,rgba(10,30,80,0.8),rgba(20,60,120,0.8));}',
'.yt-season-card.sc-ny::before{background:linear-gradient(145deg,rgba(100,180,255,0.1),rgba(200,240,255,0.05));}',
'.yt-season-card.sc-ny.active{border-color:#4af;box-shadow:0 0 20px rgba(80,180,255,0.4),inset 0 0 20px rgba(80,180,255,0.1);}',
'.yt-season-card.sc-ny .sc-label{color:#9cf;}',
'.yt-season-card.sc-hw{background:linear-gradient(145deg,rgba(40,15,0,0.9),rgba(80,30,0,0.9));}',
'.yt-season-card.sc-hw::before{background:linear-gradient(145deg,rgba(255,100,0,0.1),rgba(255,60,0,0.05));}',
'.yt-season-card.sc-hw.active{border-color:#f80;box-shadow:0 0 20px rgba(255,120,0,0.4),inset 0 0 20px rgba(255,80,0,0.1);}',
'.yt-season-card.sc-hw .sc-label{color:#f90;}',
'.yt-switch{width:38px;height:20px;background:rgba(255,255,255,0.15);border-radius:20px;position:relative;transition:background .3s;flex-shrink:0;}',
'.yt-switch.on{background:linear-gradient(90deg,#ff2060,#8855ff);}',
'.yt-switch::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;background:#fff;border-radius:50%;transition:left .3s;box-shadow:0 1px 3px rgba(0,0,0,0.4);}',
'.yt-switch.on::after{left:20px;}',
'input.yt-range{-webkit-appearance:none;width:100%;height:4px;background:linear-gradient(90deg,#ff2060,#8855ff);border-radius:2px;outline:none;cursor:pointer;}',
'input.yt-range::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;background:#fff;border-radius:50%;cursor:pointer;box-shadow:0 0 8px rgba(255,32,96,0.8);}',
'.yt-color-chip{width:18px;height:18px;border-radius:50%;border:2px solid rgba(255,255,255,0.3);flex-shrink:0;}',
'#yt-blur-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2147483646;opacity:0;visibility:hidden;pointer-events:none;backdrop-filter:blur(8px);background:rgba(0,0,0,0.35);cursor:pointer;transition:opacity .35s ease,visibility 0s linear .35s;}',
'#yt-blur-overlay.on{opacity:1;visibility:visible;pointer-events:all;transition:opacity .35s ease,visibility 0s linear 0s;}',
'body.yt-cinema #masthead{opacity:0!important;pointer-events:none!important;transition:opacity .5s!important;}',
'body.yt-cinema ytd-guide-renderer{opacity:0!important;pointer-events:none!important;transition:opacity .5s!important;}',
'body.yt-cinema #secondary{opacity:0!important;pointer-events:none!important;transition:opacity .5s!important;}',
'body.yt-cinema #below{opacity:0!important;pointer-events:none!important;transition:opacity .5s!important;}',
'body.yt-cinema ytd-app{background:#000!important;}',
'.yt-sep{height:1px;background:rgba(255,255,255,0.08);margin:10px 0;}',
'.yt-section-label{font-size:11px;font-weight:700;letter-spacing:1px;color:#666;text-transform:uppercase;margin-bottom:8px;padding-left:4px;}',
'#yt-pro-toast{position:fixed;bottom:80px;left:50%;transform:translateX(-50%) translateY(20px);background:linear-gradient(135deg,rgba(255,32,96,0.95),rgba(136,85,255,0.95));color:#fff;padding:10px 20px;border-radius:30px;font-family:"Exo 2",sans-serif;font-size:14px;font-weight:600;z-index:2147483647;opacity:0;transition:opacity .4s ease,transform .4s ease;pointer-events:none;box-shadow:0 4px 20px rgba(255,32,96,0.4);letter-spacing:0.3px;}',
].join(''));
// ─── Хелперы ──────────────────────────────────────────────────
function el(tag, cls, txt) {
const e = document.createElement(tag);
if (cls) e.className = cls;
if (txt !== undefined) e.textContent = txt;
return e;
}
function sep() { return el('div','yt-sep'); }
function lbl(txt) { return el('div','yt-section-label',txt); }
function makeSwitch(row, active, onToggle) {
const sw = el('div','yt-switch'+(active?' on':''));
row.addEventListener('click', e => { e.stopPropagation(); onToggle(sw.classList.toggle('on')); });
row.appendChild(sw);
return sw;
}
function makeSlider({ label, min, max, step, value, unit, onChange }) {
const row=el('div','yt-slider-row'), top=el('div','yt-slider-top');
const lblEl=el('span','yt-slider-label',label), valEl=el('span','yt-slider-val',value+unit);
top.append(lblEl,valEl);
const input=document.createElement('input');
input.type='range'; input.min=min; input.max=max; input.step=step; input.value=value; input.className='yt-range';
input.addEventListener('input', e => { e.stopPropagation(); const v=parseFloat(input.value); valEl.textContent=v+unit; onChange(v); });
row.append(top,input);
return { row, input, valEl };
}
function applySettings() {
setRainbowStyle(); syncRainbowOverlay(); setSeasonStyle();
document.body.classList.toggle('yt-cinema', cfg.cinema===true||cfg.cinema==='true');
document.documentElement.style.setProperty('cursor', getCursorStyle(cfg.cursor), 'important');
updateMenuStyle(); applyVideoSpeed(cfg.videoSpeed); applyVideoVolume(cfg.videoVolume);
startCursorEffect(cfg.cursorEffect); applyDrawMode();
}
function updateMenuStyle() {
const menu=document.getElementById('yt-pro-menu');
if (!menu) return;
const isGlass=cfg.menuTransparent===true||cfg.menuTransparent==='true';
if (isGlass) {
menu.style.background='rgba(200,200,220,0.06)';
menu.style.backdropFilter='blur(28px) saturate(150%) brightness(1.15)';
menu.style.borderColor='rgba(255,255,255,0.3)';
menu.style.color='#fff';
menu.style.boxShadow='0 8px 32px rgba(0,0,0,0.4),inset 0 0 0 1px rgba(255,255,255,0.15)';
} else {
const color=MENU_COLORS[cfg.menuColor]||MENU_COLORS.default;
menu.style.background=color.bg; menu.style.backdropFilter='none';
menu.style.borderColor=color.border; menu.style.color=color.text;
menu.style.boxShadow='0 20px 60px rgba(0,0,0,0.9)';
}
}
function syncOverlay(menuOpen) {
const ov=document.getElementById('yt-blur-overlay');
if (!ov) return;
ov.classList.toggle('on', menuOpen&&(cfg.menuBlur===true||cfg.menuBlur==='true'));
}
// ─── Построение меню ──────────────────────────────────────────
function createMenu() {
if (document.getElementById('yt-pro-menu')) return;
const root=el('div'); root.id='yt-pro-root';
document.documentElement.appendChild(root);
const overlay=el('div'); overlay.id='yt-blur-overlay';
overlay.addEventListener('click', closeMenu);
root.appendChild(overlay);
const menu=el('div'); menu.id='yt-pro-menu';
const startX = Math.round(window.innerWidth / 2 - 325);
const startY = Math.round(window.innerHeight / 2 - 265);
menu.style.left = startX + 'px';
menu.style.top = startY + 'px';
const sidebar=el('div','yt-sidebar');
const content=el('div','yt-content');
const tabs=[
{id:'y', label:t('categories.youtube')},
{id:'m', label:t('categories.menu')},
{id:'d', label:t('categories.design')},
{id:'c', label:t('categories.cursor')},
];
const sections={};
tabs.forEach((tab,i)=>{
const btn=el('div','yt-nav-btn'+(i===0?' sel':''),tab.label);
btn.addEventListener('click',()=>{
sidebar.querySelectorAll('.yt-nav-btn').forEach(b=>b.classList.remove('sel'));
btn.classList.add('sel');
Object.values(sections).forEach(s=>s.classList.remove('show'));
sections[tab.id].classList.add('show');
});
sidebar.appendChild(btn);
const sec=el('div','yt-section'+(i===0?' show':''));
sec.id='tab-'+tab.id; sections[tab.id]=sec;
});
const credit=el('div','yt-sidebar-credit','YouTube menu\nby ');
credit.style.whiteSpace='pre';
const creditLink=document.createElement('a');
creditLink.textContent='Bveery';
creditLink.href='https://www.youtube.com/@Bveery';
creditLink.target='_blank';
creditLink.style.cssText='color:rgba(255,100,120,0.6);text-decoration:none;transition:color .2s;cursor:pointer;';
creditLink.addEventListener('mouseenter',()=>{creditLink.style.color='#ff2060';creditLink.style.textShadow='0 0 8px rgba(255,32,96,0.6)';});
creditLink.addEventListener('mouseleave',()=>{creditLink.style.color='rgba(255,100,120,0.6)';creditLink.style.textShadow='none';});
credit.appendChild(creditLink);
sidebar.appendChild(credit);
const header=el('div','yt-header');
const titleEl=el('div','yt-title',t('title'));
const closeBtn=el('div','yt-close','×');
closeBtn.addEventListener('click', closeMenu);
header.append(titleEl, closeBtn);
content.appendChild(header);
// Перетаскивание
let dragActive=false, dragOffX=0, dragOffY=0;
header.addEventListener('mousedown', e => {
if (e.target === closeBtn) return;
dragActive = true;
menu.classList.add('dragging');
const rect = menu.getBoundingClientRect();
dragOffX = e.clientX - rect.left;
dragOffY = e.clientY - rect.top;
e.preventDefault();
});
document.addEventListener('mousemove', e => {
if (!dragActive) return;
let nx = e.clientX - dragOffX;
let ny = e.clientY - dragOffY;
nx = Math.max(0, Math.min(window.innerWidth - menu.offsetWidth, nx));
ny = Math.max(0, Math.min(window.innerHeight - menu.offsetHeight, ny));
menu.style.left = nx + 'px';
menu.style.top = ny + 'px';
});
document.addEventListener('mouseup', () => {
if (!dragActive) return;
dragActive = false;
menu.classList.remove('dragging');
});
// ══ TAB: YOUTUBE ══════════════════════════════════════════
const tabY=sections.y;
tabY.appendChild(lbl(t('youtube.speedSection')));
const {row:speedRow}=makeSlider({label:t('youtube.speed'),min:0.25,max:16,step:0.25,value:cfg.videoSpeed,unit:'x',onChange:v=>{save('videoSpeed',v);applyVideoSpeed(v);}});
tabY.appendChild(speedRow);
tabY.appendChild(sep());
tabY.appendChild(lbl(t('youtube.volumeSection')));
const {row:volRow}=makeSlider({label:t('youtube.volume'),min:0,max:300,step:1,value:cfg.videoVolume,unit:'%',onChange:v=>{save('videoVolume',v);applyVideoVolume(v);}});
tabY.appendChild(volRow);
const volHint=el('div','','⚠️ Values above 100% may distort audio');
volHint.style.cssText='font-size:10px;color:rgba(255,180,0,0.6);padding:4px 4px 8px;';
tabY.appendChild(volHint);
tabY.appendChild(sep());
tabY.appendChild(lbl(t('youtube.rememberSection')));
const remRow=el('div','yt-row',t('youtube.remember'));
makeSwitch(remRow,cfg.rememberPosition,on=>{save('rememberPosition',on);if(on){showToast('🕒 Position memory ON');restorePosition();}else showToast('⏹️ Position memory OFF');});
tabY.appendChild(remRow);
// ══ TAB: MENU ═════════════════════════════════════════════
const tabM=sections.m;
const langBlock=el('div','yt-lang-block');
const langHeader=el('div','yt-lang-header');
const langLeft=el('div','yt-lang-header-left');
langLeft.append(el('span','','⚙️'),el('span','',t('menu.lang')));
const langArrow=el('span','yt-lang-arrow','▼');
langHeader.append(langLeft,langArrow);
const langBody=el('div','yt-lang-body');
const langOptions=el('div','yt-lang-options');
[{code:'en',flag:'🇬🇧',name:t('menu.langEn')},{code:'ru',flag:'🇷🇺',name:t('menu.langRu')}].forEach(lang=>{
const opt=el('div','yt-lang-option'+(cfg.language===lang.code?' active':''));
opt.append(el('span','yt-lang-flag',lang.flag),el('span','yt-lang-name',lang.name),el('span','yt-lang-check',cfg.language===lang.code?'✓':''));
opt.addEventListener('click',()=>{if(cfg.language===lang.code)return;save('language',lang.code);location.reload();});
langOptions.appendChild(opt);
});
langBody.appendChild(langOptions);
langBlock.append(langHeader,langBody);
let langOpen=false;
langHeader.addEventListener('click',()=>{langOpen=!langOpen;langBody.classList.toggle('open',langOpen);langArrow.classList.toggle('open',langOpen);});
tabM.appendChild(langBlock);
const blurRow=el('div','yt-row',t('menu.blur'));
makeSwitch(blurRow,cfg.menuBlur,on=>{save('menuBlur',on);syncOverlay(isVisible);});
tabM.appendChild(blurRow);
const glassRow=el('div','yt-row',t('menu.transparent'));
makeSwitch(glassRow,cfg.menuTransparent,on=>{save('menuTransparent',on);updateMenuStyle();});
tabM.appendChild(glassRow);
const pauseRow=el('div','yt-row',t('menu.pauseOnMenu'));
makeSwitch(pauseRow,cfg.pauseOnMenu,on=>{save('pauseOnMenu',on);});
tabM.appendChild(pauseRow);
tabM.appendChild(sep());
tabM.appendChild(lbl(t('menu.colorTitle')));
Object.keys(MENU_COLORS).forEach(c=>{
const row=el('div','yt-row'+(cfg.menuColor===c?' active':''));
const name=el('span','',c.charAt(0).toUpperCase()+c.slice(1));
const chip=el('div','yt-color-chip'); chip.style.background=COLOR_CHIPS[c]||'#888';
row.append(name,chip);
row.addEventListener('click',()=>{save('menuColor',c);tabM.querySelectorAll('.yt-row').forEach(r=>r.classList.remove('active'));row.classList.add('active');updateMenuStyle();});
tabM.appendChild(row);
});
// ══ TAB: DESIGN ═══════════════════════════════════════════
const tabD=sections.d;
tabD.appendChild(lbl(t('design.rbSection')));
const rbRow=el('div','yt-row',t('design.rainbow'));
makeSwitch(rbRow,cfg.theme==='rainbow',on=>{save('theme',on?'rainbow':'none');applySettings();});
tabD.appendChild(rbRow);
const {row:rbSpeedRow}=makeSlider({label:t('design.speed'),min:1,max:20,step:1,value:cfg.rbSpeed,unit:'s',onChange:v=>{save('rbSpeed',v);setRainbowStyle();}});
tabD.appendChild(rbSpeedRow);
tabD.appendChild(sep());
tabD.appendChild(lbl(t('design.seasonal')));
const grid=el('div','yt-season-grid');
[{key:'none',cls:'sc-none',icon:'⚪',label:t('design.s_none')},{key:'ny',cls:'sc-ny',icon:'❄️',label:t('design.s_ny')},{key:'hw',cls:'sc-hw',icon:'🎃',label:t('design.s_hw')}].forEach(sc=>{
const card=el('div','yt-season-card '+sc.cls+(cfg.seasonal===sc.key?' active':''));
card.append(el('span','sc-icon',sc.icon),el('span','sc-label',sc.label));
card.addEventListener('click',()=>{save('seasonal',sc.key);grid.querySelectorAll('.yt-season-card').forEach(c=>c.classList.remove('active'));card.classList.add('active');setSeasonStyle();});
grid.appendChild(card);
});
tabD.appendChild(grid);
tabD.appendChild(sep());
tabD.appendChild(lbl(t('design.cinSection')));
const cinRow=el('div','yt-row',t('design.cinema'));
makeSwitch(cinRow,cfg.cinema,on=>{save('cinema',on);applySettings();});
tabD.appendChild(cinRow);
// ══ TAB: CURSOR ═══════════════════════════════════════════
const tabC=sections.c;
// Рисование
tabC.appendChild(lbl(t('cursor.drawSection')));
const drawRow=el('div','yt-row',t('cursor.drawMode'));
makeSwitch(drawRow,cfg.drawMode,on=>{save('drawMode',on);applyDrawMode();});
tabC.appendChild(drawRow);
tabC.appendChild(lbl(t('cursor.drawColor')));
const colorPicker=el('div','yt-draw-colors');
DRAW_COLORS.forEach(dc=>{
const chip=el('div','yt-draw-color'+(cfg.drawColor===dc.color?' active':''));
chip.style.background=dc.color;
chip.addEventListener('click',()=>{
save('drawColor',dc.color);
colorPicker.querySelectorAll('.yt-draw-color').forEach(c=>c.classList.remove('active'));
chip.classList.add('active');
});
colorPicker.appendChild(chip);
});
tabC.appendChild(colorPicker);
const {row:sizeRow}=makeSlider({label:t('cursor.drawSize'),min:1,max:40,step:1,value:cfg.drawSize,unit:'px',onChange:v=>{save('drawSize',v);}});
tabC.appendChild(sizeRow);
const clearBtn=document.createElement('button');
clearBtn.className='yt-clear-btn';
clearBtn.textContent=t('cursor.drawClear');
clearBtn.addEventListener('click',e=>{e.stopPropagation();clearDrawCanvas();});
tabC.appendChild(clearBtn);
tabC.appendChild(sep());
// Стиль курсора
tabC.appendChild(lbl(t('cursor.cursorSection')));
CURSOR_KEYS.forEach(key=>{
const row=el('div','yt-row'+(cfg.cursor===key?' active':''),t('cursor.'+key));
row.addEventListener('click',()=>{
save('cursor',key);
tabC.querySelectorAll('.yt-row').forEach(r=>r.classList.remove('active'));
row.classList.add('active');
applySettings();
});
tabC.appendChild(row);
});
tabC.appendChild(sep());
// Эффекты курсора
tabC.appendChild(lbl(t('cursor.effectSection')));
const fxData=[
{key:'none', icon:'⚪', label:t('cursor.fx_none')},
{key:'sparks', icon:'✨', label:t('cursor.fx_sparks')},
{key:'hearts', icon:'❤️', label:t('cursor.fx_hearts')},
{key:'snow', icon:'❄️', label:t('cursor.fx_snow')},
{key:'rainbow',icon:'🌈', label:t('cursor.fx_rainbow')},
{key:'stars', icon:'⭐', label:t('cursor.fx_stars')},
];
const fxGrid=el('div','yt-fx-grid');
fxData.forEach(fx=>{
const card=el('div','yt-fx-card'+(cfg.cursorEffect===fx.key?' active':''));
card.append(el('span','yt-fx-icon',fx.icon),el('span','yt-fx-label',fx.label));
card.addEventListener('click',()=>{
save('cursorEffect',fx.key);
fxGrid.querySelectorAll('.yt-fx-card').forEach(c=>c.classList.remove('active'));
card.classList.add('active');
startCursorEffect(fx.key);
});
fxGrid.appendChild(card);
});
tabC.appendChild(fxGrid);
Object.values(sections).forEach(s=>content.appendChild(s));
menu.append(sidebar,content);
root.appendChild(menu);
applySettings();
}
// ─── Открытие / Закрытие ──────────────────────────────────────
let isVisible=false;
function openMenu() {
if (!document.getElementById('yt-pro-menu')) createMenu();
isVisible=true;
document.getElementById('yt-pro-menu').classList.add('active');
updateMenuStyle();
syncOverlay(true);
if (cfg.pauseOnMenu===true||cfg.pauseOnMenu==='true') wePaused=pauseVideo();
}
function closeMenu() {
isVisible=false;
document.getElementById('yt-pro-menu')?.classList.remove('active');
syncOverlay(false);
if (wePaused&&(cfg.pauseOnMenu===true||cfg.pauseOnMenu==='true')) resumeVideo();
wePaused=false;
}
function toggleMenu() { isVisible?closeMenu():openMenu(); }
window.addEventListener('keyup', e => { if (e.code==='ShiftRight') toggleMenu(); });
watchVideo();
startPositionWatcher();
applySettings();
})();