Disable YouTube Hotkeys with Modern Settings Page

Disable various YouTube hotkeys, including frame skip, with a modern settings page

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         Disable YouTube Hotkeys with Modern Settings Page
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Disable various YouTube hotkeys, including frame skip, with a modern settings page
// @author       You
// @match        *://www.youtube.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==


(function() {
    'use strict';

    // Load saved settings or default to enabling all keys
    let settings = GM_getValue('hotkeySettings', {
        disableNumericKeys: false,
        disableSpacebar: false,
        disableArrowKeys: false,
        disableFKey: false,
        disableMKey: false,
        disableSpeedControl: false,
        disableFrameSkip: false
    });

    // Function to handle keydown events and disable selected hotkeys
    window.addEventListener('keydown', function(e) {
        // Disable numeric keys (0-9)
        if (settings.disableNumericKeys && e.key >= '0' && e.key <= '9') {
            e.stopPropagation();
            e.preventDefault();
        }

        // Disable spacebar
        if (settings.disableSpacebar && e.code === 'Space') {
            e.stopPropagation();
            e.preventDefault();
        }

        // Disable arrow keys (left, right, up, down)
        if (settings.disableArrowKeys && ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.code)) {
            e.stopPropagation();
            e.preventDefault();
        }

        // Disable F (for fullscreen)
        if (settings.disableFKey && e.key.toLowerCase() === 'f') {
            e.stopPropagation();
            e.preventDefault();
        }

        // Disable M (for mute)
        if (settings.disableMKey && e.key.toLowerCase() === 'm') {
            e.stopPropagation();
            e.preventDefault();
        }

        // Disable speed control (Shift + > or Shift + <)
        if (settings.disableSpeedControl && (e.shiftKey && (e.key === '>' || e.key === '<'))) {
            e.stopPropagation();
            e.preventDefault();
        }

        // Disable frame skip (`,` for backward, `.` for forward)
        if (settings.disableFrameSkip && (e.key === ',' || e.key === '.')) {
            e.stopPropagation();
            e.preventDefault();
        }
    }, true);

    // Create and display the settings modal using safe DOM manipulation
    function openSettings() {
        // Remove any existing modal or overlay
        let existingModal = document.getElementById('yt-hotkey-settings-modal');
        let existingOverlay = document.getElementById('yt-hotkey-settings-overlay');
        if (existingModal) existingModal.remove();
        if (existingOverlay) existingOverlay.remove();

        // Create the modal container
        let modal = document.createElement('div');
        modal.id = 'yt-hotkey-settings-modal';
        modal.className = 'modal-card';

        // Create modal header
        let header = document.createElement('div');
        header.className = 'modal-header';

        let title = document.createElement('h2');
        title.textContent = 'YouTube Hotkey Settings';
        header.appendChild(title);

        let closeButton = document.createElement('span');
        closeButton.id = 'closeSettingsBtn';
        closeButton.className = 'close-btn';
        closeButton.textContent = '×';
        header.appendChild(closeButton);

        modal.appendChild(header);

        // Create modal content (checkboxes)
        let content = document.createElement('div');
        content.className = 'modal-content';

        let checkboxes = [
            { id: 'disableNumericKeys', label: 'Disable Numeric Keys (0-9)', checked: settings.disableNumericKeys },
            { id: 'disableSpacebar', label: 'Disable Spacebar (Play/Pause)', checked: settings.disableSpacebar },
            { id: 'disableArrowKeys', label: 'Disable Arrow Keys (Rewind/FF, Volume)', checked: settings.disableArrowKeys },
            { id: 'disableFKey', label: 'Disable F Key (Fullscreen)', checked: settings.disableFKey },
            { id: 'disableMKey', label: 'Disable M Key (Mute)', checked: settings.disableMKey },
            { id: 'disableSpeedControl', label: 'Disable Speed Control (Shift + > / <)', checked: settings.disableSpeedControl },
            { id: 'disableFrameSkip', label: 'Disable Frame Skip (`,` and `.`)', checked: settings.disableFrameSkip }
        ];

        checkboxes.forEach(hotkey => {
            let label = document.createElement('label');
            label.className = 'custom-checkbox';

            let checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.id = hotkey.id;
            checkbox.checked = hotkey.checked;

            let checkmark = document.createElement('span');
            checkmark.className = 'checkmark';

            label.appendChild(checkbox);
            label.appendChild(checkmark);
            label.appendChild(document.createTextNode(` ${hotkey.label}`));
            content.appendChild(label);
        });

        modal.appendChild(content);

        // Create modal footer (save button)
        let footer = document.createElement('div');
        footer.className = 'modal-footer';

        let saveButton = document.createElement('button');
        saveButton.id = 'saveSettingsBtn';
        saveButton.className = 'primary-btn';
        saveButton.textContent = 'Save Settings';
        footer.appendChild(saveButton);

        modal.appendChild(footer);

        // Append modal to the document body
        document.body.appendChild(modal);

        // Create the overlay (dark background behind modal)
        let overlay = document.createElement('div');
        overlay.id = 'yt-hotkey-settings-overlay';
        overlay.className = 'modal-overlay';
        document.body.appendChild(overlay);

        // Close modal on clicking the close button or overlay
        closeButton.addEventListener('click', closeSettings);
        overlay.addEventListener('click', closeSettings);

        // Save settings on clicking the save button
        saveButton.addEventListener('click', function() {
            settings.disableNumericKeys = document.getElementById('disableNumericKeys').checked;
            settings.disableSpacebar = document.getElementById('disableSpacebar').checked;
            settings.disableArrowKeys = document.getElementById('disableArrowKeys').checked;
            settings.disableFKey = document.getElementById('disableFKey').checked;
            settings.disableMKey = document.getElementById('disableMKey').checked;
            settings.disableSpeedControl = document.getElementById('disableSpeedControl').checked;
            settings.disableFrameSkip = document.getElementById('disableFrameSkip').checked;
            GM_setValue('hotkeySettings', settings);

            // Show a success message and close modal after a short delay
            showNotification('Settings saved successfully!', modal);
            setTimeout(closeSettings, 1500);
        });

        // Function to close the settings modal
        function closeSettings() {
            modal.remove();
            overlay.remove();
        }
    }

    // Function to show a notification banner
    function showNotification(message, parentElement) {
        let banner = document.createElement('div');
        banner.className = 'notification-banner';
        banner.textContent = message;
        parentElement.appendChild(banner);

        setTimeout(() => banner.remove(), 3000);
    }

    // Register the settings menu command
    GM_registerMenuCommand('YouTube Hotkey Settings', openSettings);

    // Add styles for the modal and modern UI
    GM_addStyle(`
        /* General Modal Styling */
        .modal-card {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            width: 400px;
            max-width: 90%;
            z-index: 10001;
            overflow: hidden;
            animation: slide-down 0.3s ease-out;
        }

        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 10000;
        }

        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            background-color: #007bff;
            color: white;
            padding: 15px;
        }

        .modal-content {
            padding: 20px;
        }

        .modal-footer {
            display: flex;
            justify-content: flex-end;
            padding: 10px;
            border-top: 1px solid #ddd;
        }

        /* Checkbox Styling */
        .custom-checkbox {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
            font-size: 16px;
        }

        .custom-checkbox input[type="checkbox"] {
            display: none;
        }

        .custom-checkbox .checkmark {
            display: inline-block;
            width: 18px;
            height: 18px;
            border: 2px solid #007bff;
            border-radius: 3px;
            margin-right: 10px;
            transition: all 0.2s;
        }

        .custom-checkbox input[type="checkbox"]:checked + .checkmark {
            background-color: #007bff;
            border-color: #007bff;
        }

        /* Button Styling */
        .primary-btn {
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 5px;
            padding: 10px 20px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .primary-btn:hover {
            background-color: #0056b3;
        }

        /* Close Button */
        .close-btn {
            font-size: 24px;
            color: white;
            cursor: pointer;
            padding: 0 10px;
        }

        /* Notification Banner */
        .notification-banner {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            padding: 10px;
            background-color: #28a745;
            color: white;
            text-align: center;
            animation: fade-in-out 3s ease-out;
        }

        /* Animations */
        @keyframes slide-down {
            from { transform: translate(-50%, -60%); opacity: 0; }
            to { transform: translate(-50%, -50%); opacity: 1; }
        }

        @keyframes fade-in-out {
            0%, 100% { opacity: 0; }
            20%, 80% { opacity: 1; }
        }
    `);
})();