YouTube Speed Controller Pro

YouTube persistent speed slider overlay, minimize toggle. Pro Features: Automatic 1x speed for Music/Movies, intelligent chapter navigation, and high-fidelity Pitch Shift toggle.

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         YouTube Speed Controller Pro
// @namespace    http://tampermonkey.net/
// @version      3.2.68
// @description  YouTube persistent speed slider overlay, minimize toggle. Pro Features: Automatic 1x speed for Music/Movies, intelligent chapter navigation, and high-fidelity Pitch Shift toggle.
// @author       AI-generated with assistance from Gemini 3 Flash based on concepts by RickZabel
// @license      CC-BY-NC-SA-4.0
// @copyright    2026, RickZabel (https://greasyfork.org/en/users/5920-rickzabel)
// @icon         data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDI0IiBoZWlnaHQ9IjEwMjQiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI2ZmMDAwMCIgZD0iTSA1MTIgNzQ1IGMgMCAwIDIxMiAwIDI2NCAtMTQgMjkgLTcgNTEgLTMwIDYwIC01OSAxNCAtNTEgMTQgLTE2MCAxNCAtMTYwIDAgMCAwIC0xMDggLTE0IC0xNjAgLTggLTI5IDMwIC01MSAtNjAgLTU5IC01MiAtMTQgLTI2NCAtMTQgLTI2NCAtMTQgMCAwIC0yMTEgMCAtMjY0IDE0IC0yOSA3IC01MSAzMCAtNjAgNTkgLTE0IDUyIC0xNCAxNjAgLTE0IDE2MCAwIDAgMCAxMDkgMTQgMTYwIDggMjkgMzAgNTEgNjAgNTkgNTIgMTQgMjY0IDE0IDI2NCAxNCB6Ii8+PHBhdGggZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9Ijg0IiBkPSJNIDY4MyA1MTIgbCAtMjcgLTE1IHYgMzEgei BNIDUwNiA1MTIgbCAtMjcgLTE1IHYgMzEgeiIvPjxwYXRoIGZpbGw9IiNmZmZmZmYiIGQ9Ik0gMzMwIDQyMSBoIDQxIHYgMTgyIGggLTQxIHogTSAyNTUgNDIxIGggNDEgdiAxODIgaCAtNDEgeiIvPjwvc3ZnPg==
// @match        *://*.youtube.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

/**
 * CHROME USERS: If this script does not appear to load:
 * 1. Go to chrome://extensions/
 * 2. Ensure "Developer mode" (top right) is ON.
 * 3. Click "Details" on the Tampermonkey extension.
 * 4. Scroll down and ensure "Allow user scripts" is ON.
 * 5. Ensure "Allow access to file URLs" is ON.
 */

/*
  AI-generated with assistance from Gemini 3 Flash based on concepts by RickZabel

  MASTER PROMPT / REBUILD RECIPE (v3.2.67):
  "Create a Tampermonkey script for YouTube that adds a persistent, draggable speed control overlay with a License/Pro system.

  Core Features & UI:
  - Precision Controls: Granular slider (0.05 increments) and presets (Pause to 2x).
  - Custom Logo: Must use specific SVG paths (lp1, lp2, lp3) with Transformation Matrix (6.201...) and colors (#ff0000, #ffffff). Acts as a minimize toggle with hold-to-manage license logic.
  - Transparency: 25% step toggle using a dynamic SVG pie-chart icon; persists via localStorage.
  - Smart Tooltips: 0.8s transition delay, 11px normal weight text, and 'Smart Boundary' logic to auto-flip orientation at window edges.
  - Color Palette: Primary text/icons #888888; Slider thumb dark red (#880000) switching to bright red (#ff0000) on hover. Pro 'Override' state uses green (#00ff00).

  Layout & Structure:
  - Main Container: Flexbox row alignment with 8px gap. Background: rgba(0,0,0,0.8) with 8px border-radius.
  - Minimized State: When minimized, the container shrinks to only the Logo. A dedicated drag handle (dots icon) must appear to the left of the logo only when minimized to allow repositioning.
  - Pro Button Group: A dedicated sub-container (.pro-btns) using 'display: flex; gap: 3px; flex: 1; overflow: visible !important;' to house Pro toggles.

  Pro Features (License Key Required):
  - Chapter Navigation: « and » arrows with fixed -2.1px top offset and 18px font size.
  - Auto-Speed Logic: Context-aware 1x speed override for 'Music', 'Movies', and 'Shows' categories.
  - High-Fidelity Audio: 'P' toggle to disable YouTube's pitch correction (preservesPitch = false).
  - Analytics: Lifetime 'Time Saved' tracker based on playback rate vs. actual duration.

  Logic & Correctness Constraints:
  - Vertical Centering: Pause button text wrapped in a span with -1.8px top nudge for visual balance.
  - Playback Preservation: Toggling Pro buttons (Music/Movies/P) while paused must never trigger auto-resume.
  - License Guard: checkLicense() must immediately disable all Pro logic and reset audio fidelity if the key is removed.
  - Persistence: LocalStorage must remember speed, coordinates, opacity, settings, and minimized state."
*/


(function() {
    'use strict';

    const GREASYFORK_URL = 'https://greasyfork.org/en/users/5920-rickzabel';
    const VALID_KEY = '1234';

    let isProUser = false;
    let lastActiveSpeed = parseFloat(localStorage.getItem('ytPersistentSpeed')) || 1.0;
    let prePauseSpeed = lastActiveSpeed;
    let isMinimized = localStorage.getItem('ytSpeedMinimized') === 'true';
    let opacityLevel = parseFloat(localStorage.getItem('ytSpeedOpacity')) || 1.0;
    let pitchShiftEnabled = localStorage.getItem('ytPitchShiftEnabled') === 'true';
    let totalSecondsSaved = parseFloat(localStorage.getItem('ytTotalTimeSaved')) || 0;
    let lastTimestamp = 0;
    let autoSpeedActive = false;

    let proSettings = JSON.parse(localStorage.getItem('ytProSettings')) || { musicOneX: false, movieOneX: false };
    const categoryMap = { "1": "Film & Animation", "10": "Music", "30": "Movies", "43": "Shows" };

    function updateStateFromStorage() {
        isProUser = localStorage.getItem('ytSpeed_ProKey') === VALID_KEY;
        pitchShiftEnabled = isProUser && localStorage.getItem('ytPitchShiftEnabled') === 'true';
    }

    function checkLicense() {
            const key = localStorage.getItem('ytSpeed_ProKey');
            const wasPro = isProUser;
            isProUser = (key === VALID_KEY);

            // MANDATORY: If license is no longer valid, kill all Pro logic
            if (!isProUser) {
                pitchShiftEnabled = false;
                proSettings.musicOneX = false;
                proSettings.movieOneX = false;
                autoSpeedActive = false;
                localStorage.setItem('ytPitchShiftEnabled', 'false');
                saveProSettings();

                const v = document.querySelector('video');
                if (v) v.preservesPitch = true; // Restore default high-quality audio
            }

            // Refresh the overlay to hide/show Pro sections based on the new state
            if (document.getElementById('yt-speed-overlay')) redrawOverlay();
        }
    function saveProSettings() { if (isProUser) localStorage.setItem('ytProSettings', JSON.stringify(proSettings)); }
    function isDarkMode() { return document.documentElement.getAttribute('dark') !== null || window.matchMedia('(prefers-color-scheme: dark)').matches; }

    function trackTimeSaved() {
        if (!isProUser) return;
        const video = document.querySelector('video');
        if (!video || video.paused || video.playbackRate <= 1.0) { lastTimestamp = 0; return; }
        if (lastTimestamp === 0) { lastTimestamp = video.currentTime; return; }
        const actualTimePassed = video.currentTime - lastTimestamp;
        if (actualTimePassed > 0 && actualTimePassed < 1) {
            const saved = actualTimePassed - (actualTimePassed / video.playbackRate);
            totalSecondsSaved += saved;
            localStorage.setItem('ytTotalTimeSaved', totalSecondsSaved);
        }
        lastTimestamp = video.currentTime;
    }

    function updateSavedDisplay() {
        const valEl = document.getElementById('time-saved-stat');
        if (!valEl || !isProUser) return;
        let s = totalSecondsSaved;
        const years = Math.floor(s / 31536000), days = Math.floor((s % 31536000) / 86400), hrs = Math.floor((s % 86400) / 3600), mins = Math.floor((s % 3600) / 60), secs = Math.floor(s % 60);
        let parts = [];
        if (years > 0) parts.push(years + "y"); if (days > 0) parts.push(days + "d"); if (hrs > 0) parts.push(hrs + "h"); if (mins > 0) parts.push(mins + "m"); if (secs > 0 || parts.length === 0) parts.push(secs + "s");
        valEl.textContent = "Time Saved: " + parts.join(" ");
    }

    function getCategoryInfo() {
        try {
            let id = window.ytInitialPlayerResponse?.videoDetails?.categoryId;
            let name = categoryMap[id];
            if (!id || !name) {
                const catStr = window.ytInitialPlayerResponse?.microformat?.playerMicroformatRenderer?.category;
                if (catStr) { name = catStr; if (catStr === "Music") id = "10"; else if (catStr === "Movies" || catStr === "Film & Animation") id = "30"; else if (catStr === "Shows") id = "43"; }
            }
            return { id: id ? String(id) : "N/A", name: name || "Not Detected" };
        } catch (e) { }
        return { id: "N/A", name: "Not Detected" };
    }

    function checkCategoryAndAdjustSpeed() {
        if (!isProUser) return;
        const info = getCategoryInfo();
        const isMusicActive = (info.id === "10" || info.name === "Music") && proSettings.musicOneX;
        const isMovieActive = (["30", "43", "1"].includes(info.id) || ["Movies", "Shows", "Film & Animation"].includes(info.name)) && proSettings.movieOneX;
        autoSpeedActive = (isMusicActive || isMovieActive);
        const target = autoSpeedActive ? 1.0 : lastActiveSpeed;
        applySpeedToVideo(target);
        updateUI(target);
    }

    function navigateChapter(direction) {
        const video = document.querySelector('video'); if (!video) return;
        const chapters = getChapters(), currentTime = video.currentTime;
        if (chapters.length === 0) return;
        if (direction === 'next') { const next = chapters.find(t => t > currentTime + 5); if (next !== undefined) video.currentTime = next; }
        else { const prevIndex = chapters.findLastIndex(t => t < currentTime - 3); video.currentTime = prevIndex !== -1 ? chapters[prevIndex] : 0; }
    }

    function getChapters() {
        const video = document.querySelector('video'); if (!video || isNaN(video.duration)) return [];
        let chapters = new Set();
        document.querySelectorAll('.ytp-chapter-hover-container, .ytp-chapter-marker').forEach(el => {
            const leftPct = parseFloat(el.style.left);
            if (!isNaN(leftPct)) chapters.add((leftPct / 100) * video.duration);
        });
        let sorted = Array.from(chapters).sort((a, b) => a - b);
        if (sorted.length > 0 && sorted[0] > 2) sorted.unshift(0);
        return sorted;
    }

    function checkTooltipPos(e) {
        const el = e.currentTarget;
        el.classList.remove('tt-left', 'tt-right', 'tt-down');
        const rect = el.getBoundingClientRect();
        if (rect.left < 60) el.classList.add('tt-left');
        else if (window.innerWidth - rect.right < 60) el.classList.add('tt-right');
        if (rect.top < 60) el.classList.add('tt-down');
    }

    function ensureInView() {
        const container = document.getElementById('yt-speed-overlay');
        if (!container) return;
        const rect = container.getBoundingClientRect();
        const isOut = (rect.bottom < 0 || rect.top > window.innerHeight || rect.right < 0 || rect.left > window.innerWidth);
        if (isOut) performReset();
    }

    function performReset() {
        localStorage.setItem('ytSpeedPos', JSON.stringify({ top: '60px', left: '20px' }));
        redrawOverlay();
    }

    let logoHoldTimer, countdownInterval, holdSecondsRemaining = 3, isLicenseMode = false;

    function redrawOverlay() {
        updateStateFromStorage();
        const e1 = document.getElementById('yt-speed-overlay'), e2 = document.getElementById('yt-speed-styles');
        if (e1) e1.remove(); if (e2) e2.remove();
        setTimeout(inject, 0);
    }

    function getTransparencyPath(opacity) {
        if (opacity === 0.25) return "M50,50 L50,0 A50,50 0 0,1 100,50 Z";
        if (opacity === 0.50) return "M50,50 L50,0 A50,50 0 0,1 100,50 A50,50 0 0,1 50,100 Z";
        if (opacity === 0.75) return "M50,50 L50,0 A50,50 0 0,1 100,50 A50,50 0 0,1 50,100 A50,50 0 0,1 0,50 Z";
        return "M50,50 m-50,0 a50,50 0 1,0 100,0 a50,50 0 1,0 -100,0";
    }

    function inject() {
        if (document.getElementById('yt-speed-overlay')) return;
        updateStateFromStorage();
        if (!document.body) return;

        const dark = isDarkMode();
        const colors = {
            //usage name: check ? 'false' : 'true'
            bg: dark ? 'rgba(15, 15, 15, 0.95)' : 'rgba(255, 255, 255, 0.95)',
            text: dark ? '#ffffff' : '#000000',
            accentBright: '#ff0000',
            accentDark: '#880000',
            muted: '#888888',
            border: dark ? 'rgba(255, 255, 255, 0.15)' : 'rgba(0, 0, 0, 0.1)',
            //btnBg: dark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.05)',
            btnBg: dark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.05)',
            btnHover: dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.1)',
            btnText: dark ? '#ffffff' : '#000000',
            tooltipBg: '#111111',
            activeGreen: '#2ecc71',
        };

        const style = document.createElement('style');
        style.id = 'yt-speed-styles';
        style.textContent = `

        #yt-speed-overlay {
            position: fixed;
            bottom: 150px;
            left: 20px;
            width: 330px;
            background: ${colors.bg} !important;
            color: ${colors.text} !important;
            padding: 6px;
            border-radius: 12px;
            backdrop-filter: blur(12px);
            border: 1px solid ${colors.border};
            z-index: 2147483647 !important;
            font-family: "Segoe UI", Roboto, sans-serif;
            font-size: 0px !important;
            user-select: none;
            opacity: ${opacityLevel};
            transition: opacity 0.3s, width 0.3s, height 0.3s;
            /*box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);*/
            touch-action: none;
            /*gap: 12px;*/
            display: block;
            box-sizing: border-box !important;
            line-height: normal !important;
        }


        #yt-speed-overlay.minimized {
            width: 42px !important;
            height: 42px !important;
            padding: 0 !important;
            overflow: hidden;
            align-items: center;
            justify-content: center;
        }

        #yt-speed-overlay.minimized .header-row,
        #yt-speed-overlay.minimized .chapter-nav,
        #yt-speed-overlay.minimized .main-content-area,
        #yt-speed-overlay.minimized .center-group,
        #yt-speed-overlay.minimized .trans-toggle,
        #yt-speed-overlay.minimized .reset-btn,
        #yt-speed-overlay.minimized .right-group {
            display: none !important;
        }

        #yt-speed-overlay.minimized .top-bar {
            margin: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: center;
        }

        #yt-speed-overlay.minimized .min-drag-dots {
            display: block !important;
            width: 100%;
            text-align: center;
            font-size: 8px;
            color: ${colors.muted};
            cursor: move;
            line-height: 8px;
            margin-top: 1px;
        }

        #yt-speed-overlay.minimized .left-group {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
        }

        #yt-speed-overlay:hover {
            opacity: 1 !important;
        }

        .header-row {
            display: flex;
            align-items: center;
            height: 12px;
            margin-bottom: 2px;
            position: relative;
        }

        .script-title {
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            font-size: 10.5px;
            color: ${colors.muted};
            text-transform: uppercase;
            letter-spacing: 0.5px;
            opacity: 0.8;
            white-space: nowrap;
            cursor: move;
        }

        .top-bar {
            display: flex;
            align-items: center;
            height: 14px;
            margin-bottom: 0px;
            position: relative;
            padding-top: 2px;
            padding-bottom: 2px;
        }

        .left-group {
            display: flex;
            align-items: center;
            flex: 0 0 40px;
        }

        .center-group {
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            align-items: center;
            justify-content: center;
            pointer-events: none;
        }

        .right-group {
            display: flex;
            align-items: center;
            gap: 3px;
            margin-left: auto;
        }

        .drag-handle {
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: move;
            font-size: 10px;
            color: ${colors.text};
            opacity: 0.7;
            padding: 0 2px;
        }

        .min-drag-dots {
            display: none;
        }

        [data-tooltip] {
            position: relative;
        }

        /*[data-tooltip]:hover:before { opacity: 1; visibility: visible; }*/

        [data-tooltip].tt-left:before {
            left: 0;
            transform: translateX(0);
        }

        [data-tooltip].tt-right:before {
            left: auto;
            right: 0;
            transform: translateX(0);
        }


        [data-tooltip]:before {
            content: attr(data-tooltip);
            position: absolute !important;
            /* Prevents button squishing */
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%);
            padding: 5px 9px;
            background: #111111 !important;
            color: #ffffff !important;
            font-size: 11px !important;
            /* Uniform font size */
            font-weight: normal !important;
            /* Uniform normal weight */
            border-radius: 4px;
            white-space: nowrap;
            opacity: 0;
            visibility: hidden;
            transition: opacity 0.2s, transform 0.2s;
            transition-delay: 1.8s;
            z-index: 2147483649;
            pointer-events: none;
            border: none !important;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
        }

        [data-tooltip]:hover:before {
            opacity: 1;
            visibility: visible;
        }

        /* Smart Boundary Fixes: Flips tips inward when near screen edges */
        #yt-speed-overlay.edge-right [data-tooltip]:before {
            left: auto !important;
            right: 0 !important;
            transform: translateX(0) !important;
        }

        #yt-speed-overlay.edge-left [data-tooltip]:before {
            left: 0 !important;
            right: auto !important;
            transform: translateX(0) !important;
        }

        .pro-btns [data-tooltip]:before,
        .logo-container [data-tooltip]:before,
        .chapter-nav [data-tooltip]:before {
            bottom: 100% !important;
        }

        /*[data-tooltip].tt-down:before { bottom: auto; top: 100%; }*/

        [data-tooltip].tt-down:before {
            bottom: auto !important;
            top: 140% !important;
        }


        .pro-area,
        .pro-btns {
            overflow: visible !important;
        }

        .pro-area {
            overflow: visible !important;
        }

        .logo-container {
            cursor: pointer;
            transition: transform 0.2s;
            display: flex;
            align-items: center;
            justify-content: center;
            transform: translate(-4px, -10px);
        }

        .logo-container:hover {
            transform: translate(-4px, -10px) scale(1.1);
        }

        #yt-speed-overlay.minimized .logo-container {
            transform: translate(0px, 0px);
        }

        .chapter-nav {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 18px;
            color: ${colors.muted};
        }

        .chapter-nav span:hover {
            color: #ff0033;
            cursor: pointer;
        }

        .trans-toggle {
            cursor: pointer;
            display: flex;
            align-items: center;
            padding: 0 2px;
            /*opacity: 0.6;*/
            transform: translate(-0px, 1.4px);
        }

        .trans-toggle svg {
            width: 12px;
            height: 12px;
            fill: ${colors.muted};
        }

        .trans-toggle:hover {
            opacity: 1;
        }

        #speed-val {
            font-weight: bold;
            font-size: 9px !important;
            color: ${colors.muted};
            text-align: center;
            pointer-events: auto;
        }

        #speed-val.override {
            color: ${colors.activeGreen} !important;
        }

        .gf-link {
            margin-left: auto;
            display: flex;
            align-items: center;
        }

        .gf-link svg {
            width: 10px;
            height: 10px;
            fill: ${colors.muted};
            transition: fill 0.2s;
        }

        .gf-link:hover svg {
            fill: #ff0033;
        }


        /*f2f2f2 hover e5e5e5*/
        .reset-btn {
            cursor: pointer;
            font-size: 16px;
            color: ${colors.muted};
            transition: color 0.2s;
        }

        .reset-btn:hover {
            color: #ff0033;
        }

        .preset-btn {
            flex: 1;
            /*background: ${colors.btnBg};*/
            background: ${colors.btnBg} !important;
            border: none;
            color: ${colors.btnText};
            padding: 7.5px 0;
            cursor: pointer;
            font-size: 12px;
            border-radius: 4px;
            transition: all 0.2s;
            height: 33px;
            min-width: 36px;
            border-radius: 18px; /* Makes them pill-shaped like YouTube buttons */
        }

        .preset-btn:hover {
            /*background: rgba(255, 255, 255, 0.15) !important;*/
            background: ${colors.btnHover} !important;
            /*color: #ff0033 !important;*/
        }

        .preset-btn.active {
            color: #ff0033 !important;
            font-weight: bold;
        }

        .preset-btn.override {
            color: ${colors.activeGreen} !important;
        }

        .preset-btn.active.pro-toggle {
            color: ${colors.activeGreen} !important;
        }

        #speed-slider {
            width: 100%;
            height: 4px;
            background: #444;
            -webkit-appearance: none;
            border-radius: 2px;
            margin: 4px 0 8px 0;
            cursor: pointer;
        }

        #speed-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            height: 10px;
            width: 10px;
            border-radius: 50%;
            background: #ff0033;
            transition: background 0.2s;
        }

        #yt-speed-overlay.pro-active #speed-slider::-webkit-slider-thumb {
            background: ${colors.activeGreen} !important;
        }

        #yt-speed-overlay.is-paused #speed-slider::-webkit-slider-thumb {
            background: #ff0033 !important;
        }


        #speed-slider.override::-webkit-slider-thumb {
            background: #00ff00 !important; /* Pro Green */
        }


        .pro-area {
            display: flex;
            flex-direction: column;
            gap: 3px;
            margin-top: 6px;
            border-top: 1px solid ${colors.border};
        }

        .pro-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .pro-btns {
            display: flex;
            gap: 3px;
            flex: 1;
            overflow: visible !important;
        }

        #time-saved-stat {
            font-size: 12px;
            color: ${colors.muted};
            white-space: nowrap;
            margin-left: 5px;
        }

        .chapter-nav {
            flex: 1;
            background: transparent !important;
            border: none;
            color: ${colors.muted};
            padding: 0 6px 0 0;
            cursor: pointer;
            font-size: 27px;
            transition: color 0.2s;
            display: inline-flex;
            align-items: center;
            justify-content: flex-end;
            position: relative;
            top: -3.15px;
        }

        .chapter-nav.data-tooltip:hover {
            color: #ffffff !important;
            background: transparent !important;
        }

        .stats-row {
            font-size: 9px;
            color: ${colors.muted};
            text-align: left;
            display: flex;
            align-items: center;
            justify-content: space-between;
            height: 15px;
        }

        .license-mgr {
            display: flex;
            flex-direction: column;
            gap: 8px;
            padding: 10px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 6px;
        }

        .license-mgr input {
            background: #222;
            border: 1px solid #444;
            color: #fff;
            padding: 6px;
            border-radius: 4px;
            font-size: 11px;
            width: 100%;
            box-sizing: border-box;
        }

        .license-mgr button {
            background: ${colors.activeGreen};
            border: none;
            color: #000;
            padding: 6px;
            border-radius: 4px;
            font-weight: bold;
            cursor: pointer;
        }

        `;
        document.head.appendChild(style);

        const container = document.createElement('div'); container.id = 'yt-speed-overlay';
        if (isMinimized) container.classList.add('minimized');

        const svgNS = "http://www.w3.org/2000/svg", headerRow = document.createElement('div'); headerRow.className = 'header-row';
        const title = document.createElement('div'); title.className = 'script-title'; title.textContent = 'YouTube Speed Controller Pro';

        const gfLink = document.createElement('a'); gfLink.className = 'gf-link'; gfLink.href = GREASYFORK_URL; gfLink.target = '_blank'; gfLink.setAttribute('data-tooltip', "Rick's Scripts"); gfLink.onmouseover = checkTooltipPos;
        const gfSvg = document.createElementNS(svgNS, "svg"); gfSvg.setAttribute("viewBox", "0 0 24 24");
        const gfPath = document.createElementNS(svgNS, "path"); gfPath.setAttribute("d", "M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z");
        gfSvg.appendChild(gfPath); gfLink.appendChild(gfSvg);

        const titleDragHandle = document.createElement('div'); titleDragHandle.className = 'drag-handle'; titleDragHandle.textContent = '••••';

        headerRow.appendChild(title); headerRow.appendChild(gfLink); headerRow.appendChild(titleDragHandle);

        const topBar = document.createElement('div'); topBar.className = 'top-bar';
        const minDrag = document.createElement('div'); minDrag.className = 'min-drag-dots'; minDrag.textContent = '••••';
        const leftGroup = document.createElement('div'); leftGroup.className = 'left-group';
        const logoWrap = document.createElement('div'); logoWrap.className = 'logo-container';
        logoWrap.onmouseover = checkTooltipPos;
        logoWrap.onmousedown = () => {
            if (isLicenseMode) return;
            holdSecondsRemaining = 3; logoWrap.setAttribute('data-tooltip', `Hold: ${holdSecondsRemaining}s...`);
            countdownInterval = setInterval(() => { holdSecondsRemaining--; logoWrap.setAttribute('data-tooltip', `Hold: ${holdSecondsRemaining}s...`); if (holdSecondsRemaining <= 0) clearInterval(countdownInterval); }, 1000);
            logoHoldTimer = setTimeout(() => { isLicenseMode = true; isMinimized = false; redrawOverlay(); }, 3000);
        };
        logoWrap.onmouseup = logoWrap.onmouseleave = () => { clearTimeout(logoHoldTimer); clearInterval(countdownInterval); logoWrap.setAttribute('data-tooltip', 'Hold 3s to Manage License'); };
        logoWrap.onclick = () => { if (holdSecondsRemaining >= 1 && !isLicenseMode) { isMinimized = !isMinimized; localStorage.setItem('ytSpeedMinimized', isMinimized); redrawOverlay(); } };

        const logoSvg = document.createElementNS(svgNS, "svg"); logoSvg.setAttribute("viewBox", "0 0 1024 1024");
        logoSvg.style.width = isMinimized ? "32px" : "40px"; logoSvg.style.height = isMinimized ? "32px" : "40px";
        const lp1 = document.createElementNS(svgNS, "path"); lp1.setAttribute("fill", "#ff0033"); lp1.setAttribute("d", "M 511.65 745.41 c 0 0 212.05 0 264.64 -14.01 29.62 -7.94 51.89 -30.81 59.7 -59.05 14.45 -51.82 14.45 -160.82 14.45 -160.82 0 0 0 -108.3 -14.45 -159.65 C 828.18 322.94 805.9 300.53 776.29 292.83 723.69 278.59 511.65 278.59 511.65 278.59 c 0 0 -211.57 0 -263.94 14.24 -29.14 7.7 -51.89 30.11 -60.18 59.05 -13.98 51.35 -13.98 159.65 -13.98 159.65 0 0 0 109 13.98 160.82 8.29 28.24 31.04 51.12 60.18 59.05 52.36 14.01 263.94 14.01 263.94 14.01 z");
        const lp2 = document.createElementNS(svgNS, "path"); lp2.setAttribute("fill", "#ffffff"); lp2.setAttribute("stroke", "#ffffff"); lp2.setAttribute("stroke-width", "84"); lp2.setAttribute("d", "M 683 512 l -27 -15 v 31 z M 506 512 l -27 -15 v 31 z");
        const lp3 = document.createElementNS(svgNS, "path"); lp3.setAttribute("fill", "#ffffff"); lp3.setAttribute("d", "M 330 421 h 41 v 182 h -41 z M 255 421 h 41 v 182 h -41 z");
        logoSvg.appendChild(lp1); logoSvg.appendChild(lp2); logoSvg.appendChild(lp3); logoWrap.appendChild(logoSvg);
        leftGroup.appendChild(logoWrap);

        const centerGroup = document.createElement('div'); centerGroup.className = 'center-group';
        const speedVal = document.createElement('span'); speedVal.id = 'speed-val';
        centerGroup.appendChild(speedVal);

        const rightGroup = document.createElement('div'); rightGroup.className = 'right-group';

        const transTog = document.createElement('div');
        transTog.className = 'trans-toggle';
        transTog.setAttribute('data-tooltip', `Transparency: ${opacityLevel * 100}%`);
        transTog.onmouseover = checkTooltipPos;
        const transSvg = document.createElementNS(svgNS, "svg");
        transSvg.setAttribute("viewBox", "0 0 100 100");
        const transCircle = document.createElementNS(svgNS, "circle");
        transCircle.setAttribute("cx", "50");
        transCircle.setAttribute("cy", "50");
        transCircle.setAttribute("r", "45");
        transCircle.setAttribute("fill", colors.btnBg);
        transCircle.setAttribute("stroke", colors.btnHover);
        transCircle.setAttribute("stroke-width", "5");
        const transPath = document.createElementNS(svgNS, "path");
        transPath.setAttribute("fill", colors.btnHover);
        transPath.setAttribute("d", getTransparencyPath(opacityLevel));
        transSvg.appendChild(transCircle);
        transSvg.appendChild(transPath);
        transTog.appendChild(transSvg);

        transTog.onclick = () => {
            opacityLevel = opacityLevel >= 1.0 ? 0.25 : opacityLevel + 0.25;
            localStorage.setItem('ytSpeedOpacity', opacityLevel);
            container.style.opacity = opacityLevel;
            transTog.setAttribute('data-tooltip', `Transparency: ${opacityLevel * 100}%`);
            transPath.setAttribute("d", getTransparencyPath(opacityLevel));
        };

        const resetBtn = document.createElement('div'); resetBtn.className = 'reset-btn'; resetBtn.textContent = '↺'; resetBtn.setAttribute('data-tooltip', 'Reset Position'); resetBtn.onmouseover = checkTooltipPos;
        resetBtn.onclick = performReset;

        rightGroup.appendChild(transTog); rightGroup.appendChild(resetBtn);
        topBar.appendChild(minDrag); topBar.appendChild(leftGroup); topBar.appendChild(centerGroup); topBar.appendChild(rightGroup);

        const mainContent = document.createElement('div'); mainContent.className = 'main-content-area';
        if (isLicenseMode) {
            const lm = document.createElement('div'); lm.className = 'license-mgr';
            const input = document.createElement('input'); input.placeholder = 'License Key...'; input.value = localStorage.getItem('ytSpeed_ProKey') || "";

            const ok = document.createElement('button'); ok.textContent = 'OK';
            //ok.onclick = () => { localStorage.setItem('ytSpeed_ProKey', input.value.trim()); isLicenseMode = false; redrawOverlay(); };
            ok.onclick = () => {
                localStorage.setItem('ytSpeed_ProKey', input.value.trim());
                isLicenseMode = false;
                checkLicense(); // Triggers the shutdown if the key is wrong
            };
            lm.appendChild(input); lm.appendChild(ok); mainContent.appendChild(lm);
        } else {
            const slider = document.createElement('input'); slider.type = 'range'; slider.id = 'speed-slider'; slider.min = '0'; slider.max = '2.0'; slider.step = '0.05'; slider.oninput = (e) => updateSpeed(e.target.value, true);
            const btnRow = document.createElement('div'); btnRow.style.display="flex"; btnRow.style.gap="3px";
            const ps = [{t:'⏸', type:'pause'}, {t:'.25', v:0.25}, {t:'.75', v:0.75}, {t:'1x', v:1}, {t:'1.25', v:1.25}, {t:'1.5', v:1.5}, {t:'2x', v:2}];
            ps.forEach(item => {
                //const b = document.createElement('button'); b.className = 'preset-btn'; b.textContent = item.t;
                const b = document.createElement('button');
                b.className = 'preset-btn';
                if (item.type === 'pause') {
                    b.id = 'pause-toggle-btn';
                    // Wrap text in a span so we can move just the text in CSS
                    const textSpan = document.createElement('span');
                    textSpan.textContent = item.t;
                    textSpan.style.position = 'relative';
                    textSpan.style.top = '-2.7px'; // Exact match to your chapter nav
                    b.appendChild(textSpan);
                    b.onclick = () => togglePause();
                } else {
                    b.textContent = item.t;
                    b.onclick = () => updateSpeed(item.v, true);
                }
                if (item.type === 'pause') { b.id = 'pause-toggle-btn'; b.onclick = () => togglePause(); } else b.onclick = () => updateSpeed(item.v, true);
                btnRow.appendChild(b);
            });
            mainContent.appendChild(slider); mainContent.appendChild(btnRow);
            if (isProUser) {
                const proArea = document.createElement('div'); proArea.className = 'pro-area';
                const stats = document.createElement('div'); stats.className = 'stats-row';
                const timeSpan = document.createElement('span'); timeSpan.id = 'time-saved-stat';

                const chapNav = document.createElement('div'); chapNav.className = 'chapter-nav';
                const prevC = document.createElement('span'); prevC.textContent = '«'; prevC.setAttribute('data-tooltip', 'Prev Chapter'); prevC.onmouseover = checkTooltipPos; prevC.onclick = (e) => { e.stopPropagation(); navigateChapter('prev'); };
                const nextC = document.createElement('span'); nextC.textContent = '»'; nextC.setAttribute('data-tooltip', 'Next Chapter'); nextC.onmouseover = checkTooltipPos; nextC.onclick = (e) => { e.stopPropagation(); navigateChapter('next'); };
                chapNav.appendChild(prevC); chapNav.appendChild(nextC);

                stats.appendChild(timeSpan); stats.appendChild(chapNav);

                const proBtns = document.createElement('div'); proBtns.className = 'pro-btns';

                const mBtn = document.createElement('button');
                mBtn.className = 'preset-btn';
                mBtn.textContent = 'Music';
                mBtn.setAttribute('data-tooltip', 'Music Mode (1x)'); // Corrected
                mBtn.onmouseover = checkTooltipPos; // Corrected
                mBtn.onclick = () => {
                    proSettings.musicOneX = !proSettings.musicOneX;
                    saveProSettings();
                    const info = getCategoryInfo();
                    const isNowMusic = (info.id === "10" || info.name === "Music") && proSettings.musicOneX;

                    const v = document.querySelector('video');
                    if (v && !v.paused) {
                        checkCategoryAndAdjustSpeed();
                    } else {
                        autoSpeedActive = isNowMusic; // Update state without triggering video play
                        updateUI(0);
                    }
                };

                const vBtn = document.createElement('button');
                vBtn.className = 'preset-btn';
                vBtn.textContent = 'Movies';
                vBtn.setAttribute('data-tooltip', 'Movie Mode (1x)'); // Corrected
                vBtn.onmouseover = checkTooltipPos; // Corrected
                vBtn.onclick = () => {
                    proSettings.movieOneX = !proSettings.movieOneX;
                    saveProSettings();
                    const info = getCategoryInfo();
                    const isNowMovie = (["30", "43", "1"].includes(info.id) || ["Movies", "Shows", "Film & Animation"].includes(info.name)) && proSettings.movieOneX;

                    const v = document.querySelector('video');
                    if (v && !v.paused) {
                        checkCategoryAndAdjustSpeed();
                    } else {
                        autoSpeedActive = isNowMovie; // Update state without triggering video play
                        updateUI(0);
                    }
                };

                const pBtn = document.createElement('button');
                pBtn.className = 'preset-btn';
                pBtn.textContent = 'P';
                pBtn.setAttribute('data-tooltip', 'Toggle Pitch Shift'); // Corrected
                pBtn.onmouseover = checkTooltipPos; // Corrected
                pBtn.onclick = () => togglePitch();



               proBtns.appendChild(mBtn); proBtns.appendChild(vBtn); proBtns.appendChild(pBtn);

                proArea.appendChild(stats); proArea.appendChild(proBtns); mainContent.appendChild(proArea); updateSavedDisplay();
            }
        }
        container.appendChild(headerRow); container.appendChild(topBar); container.appendChild(mainContent); document.body.appendChild(container);

        [headerRow, titleDragHandle, minDrag].forEach(el => {
            el.onmousedown = (e) => {
                if (e.target.closest('.gf-link')) return;
                const rect = container.getBoundingClientRect(); let sx = e.clientX - rect.left, sy = e.clientY - rect.top;
                //function move(me) { container.style.left = (me.clientX - sx) + 'px'; container.style.top = (me.clientY - sy) + 'px'; container.style.bottom = 'auto'; }
                function move(me) {
                    container.style.left = (me.clientX - sx) + 'px';
                    container.style.top = (me.clientY - sy) + 'px';
                    container.style.bottom = 'auto';

                    // Boundary Check for Tooltips
                    const rect = container.getBoundingClientRect();
                    if (rect.right > window.innerWidth - 100) {
                        container.classList.add('edge-right');
                        container.classList.remove('edge-left');
                    } else if (rect.left < 100) {
                        container.classList.add('edge-left');
                        container.classList.remove('edge-right');
                    } else {
                        container.classList.remove('edge-right', 'edge-left');
                    }
                }

                function stop() { document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', stop); localStorage.setItem('ytSpeedPos', JSON.stringify({ top: container.style.top, left: container.style.left })); }
                document.addEventListener('mousemove', move); document.addEventListener('mouseup', stop);
            };
        });
        const savedPos = JSON.parse(localStorage.getItem('ytSpeedPos'));
        if (savedPos) { container.style.left = savedPos.left; container.style.top = savedPos.top; container.style.bottom = 'auto'; }
        updateUI(autoSpeedActive ? 1.0 : lastActiveSpeed);
        setInterval(ensureInView, 3000);
    }

    function togglePitch() {
        if (!isProUser) return;
        pitchShiftEnabled = !pitchShiftEnabled;
        localStorage.setItem('ytPitchShiftEnabled', pitchShiftEnabled);
        const v = document.querySelector('video');
        if (v) {
            v.preservesPitch = !pitchShiftEnabled;
            // Only trigger playback rate change if not paused
            if (!v.paused) {
                const target = autoSpeedActive ? 1.0 : lastActiveSpeed;
                v.playbackRate = target;
            }
        }
        updateUI(v && v.paused ? 0 : (autoSpeedActive ? 1.0 : lastActiveSpeed));
    }
    function togglePause() { const v = document.querySelector('video'); if (!v) return; if (!v.paused && v.playbackRate > 0) { prePauseSpeed = v.playbackRate; updateSpeed(0, false); } else { const res = autoSpeedActive ? 1.0 : (prePauseSpeed || lastActiveSpeed || 1.0); applySpeedToVideo(res); updateUI(res); } }

    function updateSpeed(val, isUser) {
        let n = parseFloat(val);
        if (isNaN(n)) n = 1.0;
        if (isUser && n > 0 && autoSpeedActive) {
            const info = getCategoryInfo();
            if ((info.name === "Music") && proSettings.musicOneX) proSettings.musicOneX = false;
            else if (["Movies", "Shows", "Film & Animation"].includes(info.name) && proSettings.movieOneX) proSettings.movieOneX = false;
            saveProSettings(); autoSpeedActive = false;
        }
        if (n > 0 && !autoSpeedActive) { lastActiveSpeed = n; localStorage.setItem('ytPersistentSpeed', n); }
        applySpeedToVideo(n); updateUI(n);
    }

    function applySpeedToVideo(n) { const v = document.querySelector('video'); if (v) { v.preservesPitch = !pitchShiftEnabled; if (n === 0) v.pause(); else { v.playbackRate = n; if (v.paused) v.play().catch(e => { }); } } }

function updateUI(n) {
    const container = document.getElementById('yt-speed-overlay');
    const sld = document.getElementById('speed-slider');
    const val = document.getElementById('speed-val');
    if (!container) return;

    // 1. Handle Slider Color Logic (Classes for CSS)
    const isProFeatureOn = (autoSpeedActive || pitchShiftEnabled);
    container.classList.toggle('pro-active', isProFeatureOn);
    container.classList.toggle('is-paused', n === 0);

    // 2. Update Slider Value & Text Display
    //if (sld) sld.value = n;
    if (sld) {
        sld.value = n;
        /** * FIX: Slider thumb logic
         * Ensures it reverts to standard red when at 1x speed.
         */
        sld.classList.toggle('override', isProFeatureOn && n > 0 && n !== 1);
    }

    if (val) {
        // Update the text content (PAUSED or Speed)
        val.textContent = n > 0 ? n.toFixed(2) + 'x' : 'PAUSED';
        val.classList.toggle('override', isProFeatureOn && n > 0 && n !== 1);
    }

    // 3. Update All Button Active States
    document.querySelectorAll('.preset-btn').forEach(b => {
        const txt = b.textContent;

        // A. Speed Presets (.25, 1x, 2x, etc.)
        // We exclude Music, Movies, P, and ⏸ from the numeric comparison
        if (!['Music', 'Movies', 'P', '⏸'].includes(txt)) {
            const isCurrentSpeed = parseFloat(txt) === n || (txt === '1x' && n === 1);
            b.classList.toggle('active', isCurrentSpeed);
        }

        // B. Pro Toggle Buttons (Music, Movies, P)
        if (txt === 'Music') b.classList.toggle('active', proSettings.musicOneX);
        if (txt === 'Movies') b.classList.toggle('active', proSettings.movieOneX);
        if (txt === 'P') b.classList.toggle('active', pitchShiftEnabled);

        // C. Pause Button (Optional: stays active while paused)
        if (txt === '⏸') b.classList.toggle('active', n === 0);
    });

    // 4. Update the "Time Saved" display
    updateSavedDisplay();
}

    function updateUIClasses(rate) {
        const video = document.querySelector('video'), info = getCategoryInfo();
        const curRate = rate !== undefined ? rate : (video ? (video.paused ? 0 : video.playbackRate) : 1.0);
        const isPaused = video ? (video.paused || curRate === 0) : (curRate === 0);
        document.querySelectorAll('.preset-btn').forEach(btn => {
            btn.classList.remove('active', 'override');
            if (btn.id === 'pause-toggle-btn') { if (isPaused) btn.classList.add('active'); }
            else { const val = parseFloat(btn.textContent); if (!isPaused && (val === curRate || (btn.textContent === '1x' && curRate === 1))) btn.classList.add('active'); }
            if (btn.textContent === 'P' && isProUser && pitchShiftEnabled) { btn.classList.add('active'); if (curRate !== 1.0 && !isPaused) btn.classList.add('override'); }
            if (btn.textContent === 'Music' && isProUser && proSettings.musicOneX) { btn.classList.add('active'); if (info.name === "Music" && !isPaused) btn.classList.add('override'); }
            if (btn.textContent === 'Movies' && isProUser && proSettings.movieOneX) { btn.classList.add('active'); if (["Movies","Shows","Film & Animation"].includes(info.name) && !isPaused) btn.classList.add('override'); }
        });
    }

    function syncLoop() {
        if (!document.getElementById('yt-speed-overlay')) redrawOverlay();
        const v = document.querySelector('video'); if (isProUser) updateSavedDisplay();
        if (v) {
            if (!v.dataset.trackingAttached) { v.addEventListener('timeupdate', trackTimeSaved); v.dataset.trackingAttached = "true"; }
            const target = autoSpeedActive ? 1.0 : lastActiveSpeed;
            if (v.paused) updateUI(0);
            else { if (Math.abs(v.playbackRate - target) > 0.01 && !isLicenseMode) v.playbackRate = target; updateUI(v.playbackRate); }
            updateUIClasses();
        }
        requestAnimationFrame(syncLoop);
    }

    window.addEventListener('yt-navigate-finish', () => { setTimeout(checkCategoryAndAdjustSpeed, 1200); });
    updateStateFromStorage(); syncLoop();
})();