🎧 YouTube Audio Enhancer Pro V7.3

Professional Audio Enhancer: Dolby Atmos, 3D Surround, & Bass Boost.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

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

(I already have a user script manager, let me install it!)

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.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         🎧 YouTube Audio Enhancer Pro V7.3
// @namespace    http://tampermonkey.net/
// @version      7.3
// @description  Professional Audio Enhancer: Dolby Atmos, 3D Surround, & Bass Boost.
// @author       Moryata
// @match        https://www.youtube.com/*
// @match        https://music.youtube.com/*
// @grant        none
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @license      MIT
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    const STORAGE_KEY = 'yt_audio_enhancer_data_v7';

    const CONFIG = {
        tabHeight: 40,
        snapThreshold: 50,
        presets: {
            dolby: { bass: 14, mid: -4, treble: 12, clarity: 9, surround: 35, volume: 130 },
            cinema: { bass: 10, mid: -2, treble: 8, clarity: 7, surround: 20, volume: 120 },
            hifi: { bass: 5, mid: 0, treble: 8, clarity: 4, surround: 0, volume: 100 },
            bass: { bass: 18, mid: -2, treble: 4, clarity: 6, surround: 5, volume: 115 },
            reset: { bass: 0, mid: 0, treble: 0, clarity: 5, surround: 0, volume: 100 }
        },
        defaults: {
            active: true,
            dockY: 150,
            dockSide: 'right',
            vals: { volume: 100, surround: 0, bass: 0, mid: 0, treble: 0, clarity: 5 }
        }
    };

    function loadSettings() {
        const saved = localStorage.getItem(STORAGE_KEY);
        if (saved) {
            try {
                const parsed = JSON.parse(saved);
                return {
                    ...CONFIG.defaults,
                    ...parsed,
                    vals: { ...CONFIG.defaults.vals, ...(parsed.vals || {}) }
                };
            } catch (e) { return CONFIG.defaults; }
        }
        return CONFIG.defaults;
    }

    const savedState = loadSettings();

    const state = {
        ctx: null,
        source: null,
        nodes: {},
        active: savedState.active,
        isDragging: false,
        dockY: Math.max(0, Math.min(window.innerHeight - 50, savedState.dockY)),
        dockSide: savedState.dockSide,
        expanded: false,
        videoElement: null,
        vals: savedState.vals
    };

    function saveSettings() {
        const dataToSave = {
            active: state.active,
            dockY: state.dockY,
            dockSide: state.dockSide,
            vals: state.vals
        };
        localStorage.setItem(STORAGE_KEY, JSON.stringify(dataToSave));
    }

    // ========== UI CONSTRUCTION ==========
    function createDock() {
        if (document.getElementById('ae-dock')) return null;

        const dock = document.createElement('div');
        dock.id = 'ae-dock';
        dock.className = state.dockSide;
        dock.style.top = `${state.dockY}px`;

        // SVG Icon Headphone
        const iconSVG = `
            <svg viewBox="0 0 24 24" width="22" height="22" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
                <path d="M3 18v-6a9 9 0 0 1 18 0v6"></path>
                <path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path>
            </svg>
        `;

        dock.innerHTML = `
            <style>
                #ae-dock {
                    position: fixed; z-index: 2147483647;
                    font-family: 'Segoe UI', sans-serif; display: flex; align-items: flex-start;
                    transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
                    user-select: none;
                }
                #ae-dock.right { right: 0; flex-direction: row; }
                #ae-dock.left { left: 0; flex-direction: row-reverse; }

                #ae-dock.right.hidden { transform: translateX(92%); opacity: 0.6; }
                #ae-dock.left.hidden { transform: translateX(-92%); opacity: 0.6; }
                #ae-dock.hidden:hover { transform: translateX(0); opacity: 1; }

                /* TAB STYLING - ICON FIX */
                .tab {
                    width: 42px; height: 42px; background: #0f0f0f; color: #fff;
                    display: flex; justify-content: center; align-items: center;
                    cursor: pointer;
                    box-shadow: 0 4px 15px rgba(0,0,0,0.5);
                    border: 1px solid #333;
                    z-index: 2;
                    transition: all 0.3s ease;
                }

                #ae-dock.right .tab { border-radius: 8px 0 0 8px; border-right: none; border-left: 3px solid #666; }
                #ae-dock.left .tab { border-radius: 0 8px 8px 0; border-left: none; border-right: 3px solid #666; }

                /* Indikator Status (Warna Icon) */
                .tab svg { transition: all 0.3s; stroke: #aaa; }

                .tab.connected { border-color: #00ff00; box-shadow: 0 0 15px rgba(0,255,0,0.2); }
                .tab.connected svg { stroke: #00ff00; filter: drop-shadow(0 0 3px #00ff00); }

                .tab.error { border-color: #ff0000; }
                .tab.error svg { stroke: #ff0000; }

                /* Panel */
                .panel {
                    width: 260px; background: rgba(10, 10, 10, 0.96);
                    backdrop-filter: blur(12px); color: #eee;
                    padding: 16px; display: none;
                    border: 1px solid #333;
                    box-shadow: 0 10px 30px rgba(0,0,0,0.8);
                }
                #ae-dock.right .panel { border-radius: 0 0 0 12px; border-right: none; }
                #ae-dock.left .panel { border-radius: 0 0 12px 0; border-left: none; }
                #ae-dock.expanded .panel { display: block; }

                /* Controls */
                .row { display: flex; justify-content: space-between; font-size: 11px; margin-bottom: 5px; color: #bbb; font-weight: 600; }
                .val-disp { color: #fff; font-family: monospace; }

                input[type=range] {
                    width: 100%; height: 4px; background: #333; margin-bottom: 14px;
                    cursor: pointer; accent-color: #3ea6ff; appearance: none; border-radius: 2px;
                }
                input[type=range]::-webkit-slider-thumb {
                    -webkit-appearance: none; width: 12px; height: 12px; background: #fff; border-radius: 50%;
                    transition: transform 0.1s;
                }
                input[type=range]::-webkit-slider-thumb:hover { transform: scale(1.3); background: #3ea6ff; }

                .btn-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; }
                button {
                    background: rgba(255,255,255,0.05); color: #ccc; border: 1px solid transparent;
                    padding: 8px 0; border-radius: 4px; cursor: pointer;
                    font-size: 10px; font-weight: 700; transition: 0.2s;
                }
                button:hover { background: rgba(255,255,255,0.15); color: #fff; }
                button[data-p="dolby"] { border-color: #00e5ff; color: #00e5ff; }
                button[data-p="dolby"]:hover { background: #00e5ff; color: #000; box-shadow: 0 0 10px rgba(0,229,255,0.3); }

                .header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #333; padding-bottom: 12px; margin-bottom: 12px; }

                .toggle-switch { position: relative; width: 34px; height: 18px; }
                .toggle-switch input { opacity: 0; width: 0; height: 0; }
                .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #333; transition: .3s; border-radius: 18px; }
                .slider:before { position: absolute; content: ""; height: 12px; width: 12px; left: 3px; bottom: 3px; background-color: #888; transition: .3s; border-radius: 50%; }
                input:checked + .slider { background-color: #3ea6ff; }
                input:checked + .slider:before { transform: translateX(16px); background-color: #fff; }
            </style>

            <div class="tab" id="ae-tab">${iconSVG}</div>
            <div class="panel">
                <div class="header">
                    <span style="font-weight:800; font-size:13px; color:#fff;">AUDIO ENHANCER PRO</span>
                    <label class="toggle-switch">
                        <input type="checkbox" id="ae-toggle" ${state.active ? 'checked' : ''}>
                        <span class="slider"></span>
                    </label>
                </div>
                <div style="font-size:9px; color:#666; margin-bottom:8px; letter-spacing:0.5px;" id="ae-status">INITIALIZING ENGINE...</div>

                ${slider('volume', 'PRE-AMP', state.vals.volume, 0, 200, '%')}
                ${slider('surround', '3D SURROUND', state.vals.surround, 0, 100, '%')}
                ${slider('bass', 'SUB BASS', state.vals.bass, -20, 20, 'dB')}
                ${slider('mid', 'VOCAL', state.vals.mid, -20, 20, 'dB')}
                ${slider('treble', 'DETAIL', state.vals.treble, -20, 20, 'dB')}
                ${slider('clarity', 'ADAPTIVE COMP', state.vals.clarity, 0, 10, '')}

                <div class="btn-grid">
                    <button data-p="dolby">DOLBY</button>
                    <button data-p="cinema">CINEMA</button>
                    <button data-p="hifi">HI-FI</button>
                    <button data-p="bass">BASS</button>
                    <button data-p="reset" style="color:#ff5555">RESET</button>
                </div>
            </div>
        `;
        document.body.appendChild(dock);
        return {
            dock,
            tab: dock.querySelector('.tab'),
            panel: dock.querySelector('.panel'),
            status: document.getElementById('ae-status'),
            inputs: dock.querySelectorAll('input[type=range]')
        };
    }

    function slider(id, label, val, min, max, unit) {
        return `<div class="row"><span>${label}</span><span id="val-${id}" class="val-disp">${val}</span></div>
                <input type="range" id="sl-${id}" min="${min}" max="${max}" value="${val}">`;
    }

    // ========== INTERACTION ==========
    function initInteraction(ui) {
        let startX, startY, startTop;
        let isDown = false;
        let hasMoved = false;

        ui.tab.addEventListener('pointerdown', (e) => {
            e.preventDefault();
            isDown = true;
            hasMoved = false;
            startY = e.clientY;
            startX = e.clientX;
            startTop = state.dockY;
            ui.tab.setPointerCapture(e.pointerId);
        });

        ui.tab.addEventListener('pointermove', (e) => {
            if (!isDown) return;

            const deltaY = e.clientY - startY;
            const deltaX = e.clientX - startX;

            if (Math.abs(deltaY) > 5 || Math.abs(deltaX) > 5) {
                hasMoved = true;
                state.isDragging = true;

                let newY = startTop + deltaY;
                newY = Math.max(0, Math.min(window.innerHeight - 42, newY));
                state.dockY = newY;
                ui.dock.style.top = `${newY}px`;

                if (e.clientX < CONFIG.snapThreshold) {
                    state.dockSide = 'left';
                } else if (e.clientX > window.innerWidth - CONFIG.snapThreshold) {
                    state.dockSide = 'right';
                }
                ui.dock.className = `${state.dockSide} ${state.expanded ? 'expanded' : ''}`;
            }
        });

        ui.tab.addEventListener('pointerup', (e) => {
            isDown = false;
            state.isDragging = false;
            ui.tab.releasePointerCapture(e.pointerId);

            if (!hasMoved) {
                state.expanded = !state.expanded;
                ui.dock.className = `${state.dockSide} ${state.expanded ? 'expanded' : 'hidden'}`;
            } else {
                saveSettings();
                ui.dock.className = `${state.dockSide} ${state.expanded ? 'expanded' : 'hidden'}`;
            }
        });

        ui.panel.addEventListener('mousedown', e => e.stopPropagation());
    }

    // ========== AUDIO ENGINE ==========
    function initAudio(video, ui) {
        if (!ui) return;
        if (state.source && state.videoElement === video) return;

        try {
            if (!state.ctx) {
                const AudioContext = window.AudioContext || window.webkitAudioContext;
                state.ctx = new AudioContext();
            }
            if (state.ctx.state === 'suspended') state.ctx.resume();
            if (!video.crossOrigin) video.crossOrigin = "anonymous";

            try {
                state.source = state.ctx.createMediaElementSource(video);
            } catch (e) { return; }

            state.videoElement = video;

            state.nodes.bass = state.ctx.createBiquadFilter();
            state.nodes.bass.type = 'lowshelf';
            state.nodes.bass.frequency.value = 100;

            state.nodes.mid = state.ctx.createBiquadFilter();
            state.nodes.mid.type = 'peaking';
            state.nodes.mid.frequency.value = 1000;
            state.nodes.mid.Q.value = 0.8;

            state.nodes.treble = state.ctx.createBiquadFilter();
            state.nodes.treble.type = 'highshelf';
            state.nodes.treble.frequency.value = 8000;

            state.nodes.gain = state.ctx.createGain();
            state.nodes.compressor = state.ctx.createDynamicsCompressor();
            state.nodes.compressor.knee.value = 30;
            state.nodes.compressor.attack.value = 0.003;

            updateRouting();
            updateAudioParams(true);

            // Visual Update for Success
            ui.tab.classList.add('connected');
            ui.tab.classList.remove('error');
            ui.status.innerText = "ENGINE ONLINE";
            ui.status.style.color = "#00ff00";

        } catch (e) {
            // Visual Update for Error
            ui.tab.classList.add('error');
            ui.status.innerText = "CORS/SECURITY ERROR";
            ui.status.style.color = "#ff0000";
        }
    }

    function updateRouting() {
        if (!state.source || !state.nodes.bass) return;
        try { state.source.disconnect(); state.nodes.compressor.disconnect(); } catch(e){}

        if (state.active) {
            state.source.connect(state.nodes.bass);
            state.nodes.bass.connect(state.nodes.mid);
            state.nodes.mid.connect(state.nodes.treble);
            state.nodes.treble.connect(state.nodes.gain);
            state.nodes.gain.connect(state.nodes.compressor);
            state.nodes.compressor.connect(state.ctx.destination);
        } else {
            state.source.connect(state.ctx.destination);
        }
    }

    function updateAudioParams() {
        if (!state.nodes.bass) return;
        const vals = state.vals;

        state.nodes.bass.gain.setTargetAtTime(vals.bass, state.ctx.currentTime, 0.1);
        state.nodes.mid.gain.setTargetAtTime(vals.mid, state.ctx.currentTime, 0.1);

        const trebleTotal = vals.treble + (vals.surround * 0.12);
        state.nodes.treble.gain.setTargetAtTime(trebleTotal, state.ctx.currentTime, 0.1);

        state.nodes.gain.gain.setTargetAtTime(vals.volume / 100, state.ctx.currentTime, 0.1);

        state.nodes.compressor.threshold.value = -12 - (vals.clarity * 3);
        state.nodes.compressor.ratio.value = 1 + (vals.clarity * 1.5);
        state.nodes.compressor.release.value = 0.2 + (vals.surround * 0.006);
    }

    // ========== INIT ==========
    const ui = createDock();
    if (ui) {
        initInteraction(ui);

        document.getElementById('ae-toggle').addEventListener('change', (e) => {
            state.active = e.target.checked;
            updateRouting();
            ui.status.innerText = state.active ? "ENGINE ONLINE" : "BYPASSED";
            ui.status.style.color = state.active ? "#00ff00" : "#666";
            saveSettings();
        });

        ui.inputs.forEach(el => {
            el.addEventListener('input', (e) => {
                const id = e.target.id.replace('sl-', '');
                const val = parseFloat(e.target.value);
                document.getElementById(`val-${id}`).innerText = val;
                state.vals[id] = val;
                updateAudioParams();
                saveSettings();
            });
            el.addEventListener('dblclick', (e) => {
                e.target.value = e.target.defaultValue;
                e.target.dispatchEvent(new Event('input'));
            });
        });

        document.querySelectorAll('button').forEach(b => {
            b.addEventListener('click', (e) => {
                const p = CONFIG.presets[e.target.dataset.p];
                if (p) {
                    Object.keys(p).forEach(k => {
                        const el = document.getElementById(`sl-${k}`);
                        if(el) {
                            el.value = p[k];
                            document.getElementById(`val-${k}`).innerText = p[k];
                            state.vals[k] = p[k];
                        }
                    });
                    updateAudioParams();
                    saveSettings();
                }
            });
        });

        setInterval(() => {
            const video = document.querySelector('video');
            if (video) initAudio(video, ui);
        }, 1000);
    }

})();