Universal Video Shortcuts (Enhanced - Video-Centered)

Control any HTML5 video with YouTube-style keyboard shortcuts - notifications centered on video

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Universal Video Shortcuts (Enhanced - Video-Centered)
// @namespace    http://tampermonkey.net/
// @version      5.5
// @description  Control any HTML5 video with YouTube-style keyboard shortcuts - notifications centered on video
// @author       You
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    console.log('🎬 Universal Video Shortcuts - Script started (ENHANCED)');

    // Add CSS for settings window
    GM_addStyle(`
        .video-shortcuts-settings {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.95);
            color: white;
            padding: 30px;
            border-radius: 15px;
            border: 2px solid #4285f4;
            z-index: 100000;
            font-family: Arial, sans-serif;
            min-width: 450px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.5);
            backdrop-filter: blur(10px);
            max-height: 80vh;
            overflow-y: auto;
        }

        .video-shortcuts-settings h3 {
            margin: 0 0 20px 0;
            color: #4285f4;
            text-align: center;
            font-size: 20px;
        }

        .settings-group {
            margin-bottom: 20px;
        }

        .settings-label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
            color: #8ab4f8;
        }

        .settings-select, .settings-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #4285f4;
            border-radius: 8px;
            background: rgba(255,255,255,0.1);
            color: white;
            font-size: 14px;
        }

        .settings-checkbox {
            margin-right: 10px;
        }

        .settings-buttons {
            display: flex;
            gap: 10px;
            margin-top: 25px;
        }

        .settings-button {
            flex: 1;
            padding: 12px;
            border: none;
            border-radius: 8px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .settings-save {
            background: #34a853;
            color: white;
        }

        .settings-save:hover {
            background: #2e8b47;
        }

        .settings-cancel {
            background: #ea4335;
            color: white;
        }

        .settings-cancel:hover {
            background: #d33426;
        }

        .settings-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.7);
            z-index: 99999;
        }

        .settings-row {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
        }

        .settings-range {
            width: 100%;
            margin: 10px 0;
        }

        .range-value {
            color: #fbbc05;
            font-weight: bold;
            margin-left: 10px;
        }

        .border-options {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-top: 10px;
        }

        .border-option {
            display: flex;
            align-items: center;
            padding: 8px;
            border: 1px solid #4285f4;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .border-option:hover {
            background: rgba(66, 133, 244, 0.1);
        }

        .border-option.selected {
            background: rgba(66, 133, 244, 0.2);
            border-color: #fbbc05;
        }

        .universal-video-notification {
            position: fixed;
            z-index: 10000;
            pointer-events: none;
            opacity: 1;
            transition: opacity 0.4s ease;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .text-with-border {
            padding: 2px 8px;
            border-radius: 4px;
        }

        .icon-with-border {
            padding: 4px;
            border-radius: 8px;
        }
    `);

    // Default settings
    const defaultSettings = {
        theme: 'dark',
        backgroundShape: 'rounded',
        showLabels: true,
        backgroundOpacity: 0.9,
        notificationDuration: 1200,
        enableSounds: false,
        iconSize: 42,
        showNotification: true,
        notificationPosition: 'auto',
        notificationSize: 'medium',
        textBorder: 'none',
        iconBorder: 'none'
    };

    // Load settings from storage
    let settings = {};
    Object.keys(defaultSettings).forEach(key => {
        settings[key] = GM_getValue(key, defaultSettings[key]);
    });

    // Register menu command
    GM_registerMenuCommand('🎬 Video Shortcuts Settings', showSettingsWindow);

    // SVG Icons Library
    const svgIcons = {
        // Colored icons for dark theme
        play: `<svg viewBox="0 0 24 24"><path fill="#4285f4" d="M8 5v14l11-7z"/></svg>`,
        pause: `<svg viewBox="0 0 24 24"><path fill="#4285f4" d="M6 19h4V5H6zm8-14v14h4V5z"/></svg>`,
        mute: `<svg viewBox="0 0 24 24"><path fill="#34a853" d="M3 10v4h4l5 5V5L7 10H3z"/></svg>`,
        volume: `<svg viewBox="0 0 24 24"><path fill="#ea4335" d="M7 10H3v4h4l5 5V5z"/><path fill="#ea4335" d="M16.5 12c0-1.77-.77-3.29-2-4.31v8.62c1.23-1.02 2-2.54 2-4.31z"/></svg>`,
        fullscreen: `<svg viewBox="0 0 24 24"><path fill="#fbbc05" d="M7 14H5v5h5v-2H7v-3zm12 3h-3v2h5v-5h-2v3zM7 7h3V5H5v5h2V7zm12 3V5h-5v2h3v3h2z"/></svg>`,
        captions: `<svg viewBox="0 0 24 24"><path fill="#8ab4f8" d="M19 4H5c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 10H7V8h4v2H9v2h2v2zm6 0h-4V8h4v2h-2v2h2v2z"/></svg>`,
        forward: `<svg viewBox="0 0 24 24"><path fill="#4285f4" d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/></svg>`,
        rewind: `<svg viewBox="0 0 24 24"><path fill="#4285f4" d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/></svg>`,
        speed: `<svg viewBox="0 0 24 24"><path fill="#fbbc05" d="M20.38 8.57l-1.23 1.85a8 8 0 0 1-.22 7.58H5.07A8 8 0 0 1 15.58 6.85l1.85-1.23A10 10 0 0 0 3.35 19a2 2 0 0 0 1.72 1h13.85a2 2 0 0 0 1.74-1 10 10 0 0 0-.27-10.44z"/><path fill="#fbbc05" d="M10.59 15.41a2 2 0 0 0 2.83 0l5.66-8.49-8.49 5.66a2 2 0 0 0 0 2.83z"/></svg>`,
        normal_speed: `<svg viewBox="0 0 24 24"><path fill="#34a853" d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6a7 7 0 0 1 7-7 7 7 0 0 1 7 7 7 7 0 0 1-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.896 8.896 0 0 0 13 21a9 9 0 0 0 0-18z"/><path fill="#34a853" d="M12 8v5l4.25 2.52.77-1.28-3.52-2.09V8z"/></svg>`,
        skip_forward: `<svg viewBox="0 0 24 24"><path fill="#4285f4" d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/></svg>`,
        skip_backward: `<svg viewBox="0 0 24 24"><path fill="#4285f4" d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/></svg>`,
        jump: `<svg viewBox="0 0 24 24"><path fill="#8ab4f8" d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>`,

        // White icons for light theme
        play_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M8 5v14l11-7z"/></svg>`,
        pause_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M6 19h4V5H6zm8-14v14h4V5z"/></svg>`,
        mute_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M3 10v4h4l5 5V5L7 10H3z"/></svg>`,
        volume_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M7 10H3v4h4l5 5V5z"/><path fill="white" d="M16.5 12c0-1.77-.77-3.29-2-4.31v8.62c1.23-1.02 2-2.54 2-4.31z"/></svg>`,
        fullscreen_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M7 14H5v5h5v-2H7v-3zm12 3h-3v2h5v-5h-2v3zM7 7h3V5H5v5h2V7zm12 3V5h-5v2h3v3h2z"/></svg>`,
        captions_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M19 4H5c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 10H7V8h4v2H9v2h2v2zm6 0h-4V8h4v2h-2v2h2v2z"/></svg>`,
        forward_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/></svg>`,
        rewind_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/></svg>`,
        speed_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M20.38 8.57l-1.23 1.85a8 8 0 0 1-.22 7.58H5.07A8 8 0 0 1 15.58 6.85l1.85-1.23A10 10 0 0 0 3.35 19a2 2 0 0 0 1.72 1h13.85a2 2 0 0 0 1.74-1 10 10 0 0 0-.27-10.44z"/><path fill="white" d="M10.59 15.41a2 2 0 0 0 2.83 0l5.66-8.49-8.49 5.66a2 2 0 0 0 0 2.83z"/></svg>`,
        normal_speed_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6a7 7 0 0 1 7-7 7 7 0 0 1 7 7 7 7 0 0 1-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.896 8.896 0 0 0 13 21a9 9 0 0 0 0-18z"/><path fill="white" d="M12 8v5l4.25 2.52.77-1.28-3.52-2.09V8z"/></svg>`,
        skip_forward_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/></svg>`,
        skip_backward_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/></svg>`,
        jump_mono: `<svg viewBox="0 0 24 24"><path fill="white" d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>`
    };

    // Get border styles
    function getBorderStyles(type, element = 'text') {
        const isText = element === 'text';
        const borderSetting = isText ? settings.textBorder : settings.iconBorder;

        switch (borderSetting) {
            case 'shadow':
                return isText ?
                    'text-shadow: 0 2px 4px rgba(0,0,0,0.8), 0 0 8px rgba(0,0,0,0.6);' :
                    'filter: drop-shadow(0 2px 4px rgba(0,0,0,0.8)) drop-shadow(0 0 8px rgba(0,0,0,0.6));';

            case 'solid':
                const borderColor = type === 'dark' ? 'rgba(255,255,255,0.8)' : 'rgba(0,0,0,0.8)';
                return isText ?
                    `background: rgba(0,0,0,0.7); padding: 4px 12px; border-radius: 6px; border: 2px solid ${borderColor};` :
                    `background: rgba(0,0,0,0.7); padding: 6px; border-radius: 8px; border: 2px solid ${borderColor};`;

            case 'glow':
                const glowColor = type === 'dark' ? 'rgba(255,255,255,0.8)' : 'rgba(66,133,244,0.8)';
                return isText ?
                    `text-shadow: 0 0 10px ${glowColor}, 0 0 20px ${glowColor}, 0 0 30px ${glowColor};` :
                    `filter: drop-shadow(0 0 10px ${glowColor}) drop-shadow(0 0 20px ${glowColor});`;

            case 'none':
            default:
                return isText ?
                    'text-shadow: 0 2px 4px rgba(0,0,0,0.5);' :
                    '';
        }
    }

    // Single settings window
    function showSettingsWindow() {
        // Create overlay
        const overlay = document.createElement('div');
        overlay.className = 'settings-overlay';

        // Create settings window
        const settingsWindow = document.createElement('div');
        settingsWindow.className = 'video-shortcuts-settings';
        settingsWindow.innerHTML = `
            <h3>🎬 Video Shortcuts Settings</h3>

            <div class="settings-group">
                <label class="settings-label">Theme</label>
                <select class="settings-select" id="themeSelect">
                    <option value="dark" ${settings.theme === 'dark' ? 'selected' : ''}>Dark (Colored Icons)</option>
                    <option value="light" ${settings.theme === 'light' ? 'selected' : ''}>Light (White Icons)</option>
                </select>
            </div>

            <div class="settings-group">
                <label class="settings-label">Background Shape</label>
                <select class="settings-select" id="shapeSelect">
                    <option value="rounded" ${settings.backgroundShape === 'rounded' ? 'selected' : ''}>Rounded</option>
                    <option value="circle" ${settings.backgroundShape === 'circle' ? 'selected' : ''}>Circle</option>
                    <option value="square" ${settings.backgroundShape === 'square' ? 'selected' : ''}>Square</option>
                </select>
            </div>

            <div class="settings-group">
                <label class="settings-label">Text Border Style</label>
                <div class="border-options">
                    <div class="border-option ${settings.textBorder === 'none' ? 'selected' : ''}" data-value="none">
                        <input type="radio" name="textBorder" value="none" ${settings.textBorder === 'none' ? 'checked' : ''} style="margin-right: 8px;">
                        None
                    </div>
                    <div class="border-option ${settings.textBorder === 'shadow' ? 'selected' : ''}" data-value="shadow">
                        <input type="radio" name="textBorder" value="shadow" ${settings.textBorder === 'shadow' ? 'checked' : ''} style="margin-right: 8px;">
                        Shadow
                    </div>
                    <div class="border-option ${settings.textBorder === 'solid' ? 'selected' : ''}" data-value="solid">
                        <input type="radio" name="textBorder" value="solid" ${settings.textBorder === 'solid' ? 'checked' : ''} style="margin-right: 8px;">
                        Solid Border
                    </div>
                    <div class="border-option ${settings.textBorder === 'glow' ? 'selected' : ''}" data-value="glow">
                        <input type="radio" name="textBorder" value="glow" ${settings.textBorder === 'glow' ? 'checked' : ''} style="margin-right: 8px;">
                        Glow Effect
                    </div>
                </div>
            </div>

            <div class="settings-group">
                <label class="settings-label">Icon Border Style</label>
                <div class="border-options">
                    <div class="border-option ${settings.iconBorder === 'none' ? 'selected' : ''}" data-value="none">
                        <input type="radio" name="iconBorder" value="none" ${settings.iconBorder === 'none' ? 'checked' : ''} style="margin-right: 8px;">
                        None
                    </div>
                    <div class="border-option ${settings.iconBorder === 'shadow' ? 'selected' : ''}" data-value="shadow">
                        <input type="radio" name="iconBorder" value="shadow" ${settings.iconBorder === 'shadow' ? 'checked' : ''} style="margin-right: 8px;">
                        Shadow
                    </div>
                    <div class="border-option ${settings.iconBorder === 'solid' ? 'selected' : ''}" data-value="solid">
                        <input type="radio" name="iconBorder" value="solid" ${settings.iconBorder === 'solid' ? 'checked' : ''} style="margin-right: 8px;">
                        Solid Border
                    </div>
                    <div class="border-option ${settings.iconBorder === 'glow' ? 'selected' : ''}" data-value="glow">
                        <input type="radio" name="iconBorder" value="glow" ${settings.iconBorder === 'glow' ? 'checked' : ''} style="margin-right: 8px;">
                        Glow Effect
                    </div>
                </div>
            </div>

            <div class="settings-row">
                <input type="checkbox" class="settings-checkbox" id="showLabels" ${settings.showLabels ? 'checked' : ''}>
                <label class="settings-label" for="showLabels">Show Text Labels</label>
            </div>

            <div class="settings-row">
                <input type="checkbox" class="settings-checkbox" id="showNotification" ${settings.showNotification ? 'checked' : ''}>
                <label class="settings-label" for="showNotification">Show Notifications</label>
            </div>

            <div class="settings-group">
                <label class="settings-label">
                    Background Opacity: <span class="range-value" id="opacityValue">${settings.backgroundOpacity}</span>
                    ${settings.backgroundOpacity == 0 ? ' (Transparent)' : ''}
                </label>
                <input type="range" class="settings-range" id="opacityRange" min="0" max="1" step="0.1" value="${settings.backgroundOpacity}">
            </div>

            <div class="settings-group">
                <label class="settings-label">Icon Size</label>
                <select class="settings-select" id="iconSizeSelect">
                    <option value="32" ${settings.iconSize === 32 ? 'selected' : ''}>Small (32px)</option>
                    <option value="42" ${settings.iconSize === 42 ? 'selected' : ''}>Medium (42px)</option>
                    <option value="52" ${settings.iconSize === 52 ? 'selected' : ''}>Large (52px)</option>
                </select>
            </div>

            <div class="settings-group">
                <label class="settings-label">Notification Duration (ms)</label>
                <input type="number" class="settings-input" id="durationInput" value="${settings.notificationDuration}" min="500" max="5000" step="100">
            </div>

            <div class="settings-buttons">
                <button class="settings-button settings-save" id="saveSettings">Save Settings</button>
                <button class="settings-button settings-cancel" id="cancelSettings">Cancel</button>
            </div>
        `;

        // Add event listeners
        overlay.addEventListener('click', closeSettings);
        settingsWindow.querySelector('#cancelSettings').addEventListener('click', closeSettings);
        settingsWindow.querySelector('#saveSettings').addEventListener('click', saveSettings);

        // Range value updates
        settingsWindow.querySelector('#opacityRange').addEventListener('input', function() {
            const value = this.value;
            settingsWindow.querySelector('#opacityValue').textContent = value + (value == 0 ? ' (Transparent)' : '');
        });

        // Border option selection
        settingsWindow.querySelectorAll('.border-option').forEach(option => {
            option.addEventListener('click', function() {
                const radio = this.querySelector('input[type="radio"]');
                radio.checked = true;

                // Update visual selection
                settingsWindow.querySelectorAll('.border-option').forEach(opt => {
                    opt.classList.remove('selected');
                });
                this.classList.add('selected');
            });
        });

        function closeSettings() {
            document.body.removeChild(overlay);
            document.body.removeChild(settingsWindow);
        }

        function saveSettings() {
            const newSettings = {
                theme: settingsWindow.querySelector('#themeSelect').value,
                backgroundShape: settingsWindow.querySelector('#shapeSelect').value,
                showLabels: settingsWindow.querySelector('#showLabels').checked,
                showNotification: settingsWindow.querySelector('#showNotification').checked,
                backgroundOpacity: parseFloat(settingsWindow.querySelector('#opacityRange').value),
                iconSize: parseInt(settingsWindow.querySelector('#iconSizeSelect').value),
                notificationDuration: parseInt(settingsWindow.querySelector('#durationInput').value),
                textBorder: settingsWindow.querySelector('input[name="textBorder"]:checked').value,
                iconBorder: settingsWindow.querySelector('input[name="iconBorder"]:checked').value
            };

            // Save all settings
            Object.keys(newSettings).forEach(key => {
                settings[key] = newSettings[key];
                GM_setValue(key, newSettings[key]);
            });

            closeSettings();
            if (settings.showNotification) {
                showNotification('Settings Saved!', getIcon('normal_speed'));
            }
        }

        document.body.appendChild(overlay);
        document.body.appendChild(settingsWindow);
    }

    // Get the appropriate icon based on theme
    function getIcon(iconName) {
        const iconSvg = settings.theme === 'dark' ? svgIcons[iconName] : svgIcons[iconName + '_mono'];
        const borderStyle = getBorderStyles(settings.theme, 'icon');
        return `<div style="${borderStyle}">${iconSvg.replace('<svg', `<svg width="${settings.iconSize}" height="${settings.iconSize}"`)}</div>`;
    }

    // Find the most relevant video element on the page
    function getVideo() {
        const videos = Array.from(document.querySelectorAll('video'));
        console.log(`🔍 Found ${videos.length} video(s) on page`);

        if (videos.length === 0) {
            console.log('❌ No video elements found');
            return null;
        }
        if (videos.length === 1) {
            console.log('✅ Using the only video element found');
            return videos[0];
        }

        // Prioritize videos that are playing, visible, or larger
        const scoredVideos = videos.map((video, index) => {
            let score = 0;

            if (!video.paused) {
                score += 100;
                console.log(`▶️ Video ${index} is playing (+100)`);
            }

            const rect = video.getBoundingClientRect();
            const area = rect.width * rect.height;
            console.log(`📏 Video ${index}: ${rect.width}x${rect.height} (area: ${area})`);

            // Size matters - larger videos are more likely to be main content
            if (area > 100000) {
                score += 50;
                console.log(`🔍 Video ${index}: Very large (+50)`);
            } else if (area > 50000) {
                score += 30;
                console.log(`🔍 Video ${index}: Large (+30)`);
            } else if (area > 10000) {
                score += 10;
                console.log(`🔍 Video ${index}: Medium (+10)`);
            }

            // Visibility check
            if (rect.top >= 0 && rect.left >= 0 &&
                rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
                rect.right <= (window.innerWidth || document.documentElement.clientWidth)) {
                score += 20;
                console.log(`👀 Video ${index}: Fully visible (+20)`);
            }

            // Check if video has controls
            if (video.controls) {
                score += 15;
                console.log(`🎛️ Video ${index}: Has controls (+15)`);
            }

            console.log(`📊 Video ${index} total score: ${score}`);
            return { video, score };
        });

        // Return the video with highest score
        scoredVideos.sort((a, b) => b.score - a.score);
        const selectedVideo = scoredVideos[0].video;
        console.log(`🎯 Selected video with score: ${scoredVideos[0].score}`);
        return selectedVideo;
    }

    // Check if we're on YouTube
    function isYouTube() {
        return window.location.hostname.includes('youtube.com');
    }

    // Toggle play/pause
    function togglePlay() {
        console.log('🎮 Toggle Play/Pause triggered');
        const video = getVideo();
        if (!video) {
            console.log('❌ No video found for play/pause');
            return;
        }

        console.log(`⏯️ Video current state: ${video.paused ? 'Paused' : 'Playing'}`);

        if (video.paused) {
            video.play().then(() => {
                console.log('✅ Video started playing');
                if (settings.showNotification) showNotification('Playing', getIcon('play'));
            }).catch(err => {
                console.log('❌ Play failed:', err);
            });
        } else {
            video.pause();
            console.log('⏸️ Video paused');
            if (settings.showNotification) showNotification('Paused', getIcon('pause'));
        }
    }

    // Skip forward/backward by seconds
    function skip(seconds) {
        console.log(`⏩ Skip triggered: ${seconds} seconds`);
        const video = getVideo();
        if (!video) {
            console.log('❌ No video found for skip');
            return;
        }

        const oldTime = video.currentTime;
        video.currentTime += seconds;
        console.log(`⏰ Time changed: ${oldTime.toFixed(1)}s → ${video.currentTime.toFixed(1)}s`);
        if (settings.showNotification) {
            showNotification(`${seconds > 0 ? '+' : ''}${seconds}s`, seconds > 0 ? getIcon('skip_forward') : getIcon('skip_backward'));
        }
    }

    // Change volume
    function changeVolume(delta) {
        console.log(`🔊 Volume change: ${delta > 0 ? '+' : ''}${delta}`);
        const video = getVideo();
        if (!video) {
            console.log('❌ No video found for volume change');
            return;
        }

        const oldVolume = video.volume;
        const newVolume = Math.max(0, Math.min(1, video.volume + delta));
        video.volume = newVolume;

        console.log(`🔊 Volume changed: ${Math.round(oldVolume * 100)}% → ${Math.round(newVolume * 100)}%`);

        if (settings.showNotification) {
            const volumeIcon = newVolume === 0 ? getIcon('mute') : getIcon('volume');
            showNotification(`Volume: ${Math.round(newVolume * 100)}%`, volumeIcon);
        }
    }

    // Toggle mute
    function toggleMute() {
        console.log('🔇 Toggle Mute triggered');
        const video = getVideo();
        if (!video) {
            console.log('❌ No video found for mute');
            return;
        }

        const wasMuted = video.muted;
        video.muted = !video.muted;
        console.log(`🔇 Mute changed: ${wasMuted ? 'Muted' : 'Unmuted'} → ${video.muted ? 'Muted' : 'Unmuted'}`);
        if (settings.showNotification) {
            showNotification(video.muted ? 'Muted' : 'Unmuted', video.muted ? getIcon('mute') : getIcon('volume'));
        }
    }

    // Toggle fullscreen
    function toggleFullscreen() {
        console.log('🖥️ Toggle Fullscreen triggered');
        const video = getVideo();
        if (!video) {
            console.log('❌ No video found for fullscreen');
            return;
        }

        if (!document.fullscreenElement) {
            console.log('🖥️ Entering fullscreen');
            (video.parentElement || video).requestFullscreen?.().then(() => {
                console.log('✅ Fullscreen entered successfully');
                if (settings.showNotification) showNotification('Fullscreen', getIcon('fullscreen'));
            }).catch(err => {
                console.log('❌ Fullscreen error:', err);
            });
        } else {
            console.log('🖥️ Exiting fullscreen');
            document.exitFullscreen?.().then(() => {
                console.log('✅ Fullscreen exited successfully');
                if (settings.showNotification) showNotification('Normal Screen', getIcon('fullscreen'));
            }).catch(err => {
                console.log('❌ Exit fullscreen error:', err);
            });
        }
    }

    // Jump to percentage of video
    function jumpToPercent(percent) {
        console.log(`⏭️ Jump to ${percent}% triggered`);
        const video = getVideo();
        if (!video || !video.duration) {
            console.log('❌ No video or duration for jump');
            return;
        }

        const newTime = (percent / 100) * video.duration;
        console.log(`⏰ Jumping to ${newTime.toFixed(1)}s (${percent}% of ${video.duration.toFixed(1)}s)`);
        video.currentTime = newTime;
        if (settings.showNotification) showNotification(`${percent}%`, getIcon('jump'));
    }

    // Change playback speed
    function changeSpeed(delta) {
        console.log(`⚡ Speed change: ${delta > 0 ? '+' : ''}${delta}`);
        const video = getVideo();
        if (video) {
            const oldSpeed = video.playbackRate;
            video.playbackRate = Math.max(0.1, Math.min(4, video.playbackRate + delta));
            console.log(`⚡ Speed changed: ${oldSpeed.toFixed(2)}x → ${video.playbackRate.toFixed(2)}x`);
            if (settings.showNotification) showNotification(`Speed: ${video.playbackRate.toFixed(2)}x`, getIcon('speed'));
        } else {
            console.log('❌ No video found for speed change');
        }
    }

    // Set normal speed
    function setNormalSpeed() {
        console.log('⏱️ Set normal speed triggered');
        const video = getVideo();
        if (video) {
            const oldSpeed = video.playbackRate;
            video.playbackRate = 1;
            console.log(`⏱️ Speed reset: ${oldSpeed.toFixed(2)}x → 1.00x`);
            if (settings.showNotification) showNotification('Speed: 1.00x', getIcon('normal_speed'));
        } else {
            console.log('❌ No video found for speed reset');
        }
    }

    // ✨ ENHANCED: Show notification overlay centered on video
    function showNotification(text, icon = '') {
        if (!settings.showNotification) return;

        console.log(`📢 Notification: ${text}`);

        const existing = document.querySelector('.universal-video-notification');
        if (existing) {
            console.log('🗑️ Removing existing notification');
            existing.remove();
        }

        // 🎯 ENHANCEMENT: Get the video element to center notification on it
        const video = getVideo();
        let topPosition = '50%';
        let leftPosition = '50%';

        if (video) {
            const rect = video.getBoundingClientRect();
            const videoCenterX = rect.left + (rect.width / 2);
            const videoCenterY = rect.top + (rect.height / 2);

            topPosition = `${videoCenterY}px`;
            leftPosition = `${videoCenterX}px`;

            console.log(`📍 Centering notification on video at (${videoCenterX.toFixed(0)}, ${videoCenterY.toFixed(0)})`);
        } else {
            console.log('⚠️ No video found, centering on viewport');
        }

        // Determine shape based on settings
        let borderRadius;
        let padding;

        switch(settings.backgroundShape) {
            case 'circle':
                borderRadius = '50%';
                padding = '30px 30px';
                break;
            case 'square':
                borderRadius = '0px';
                padding = '25px 35px';
                break;
            case 'rounded':
            default:
                borderRadius = '15px';
                padding = '25px 35px';
                break;
        }

        const displayText = settings.showLabels ? text : '';
        const textBorderStyle = getBorderStyles(settings.theme, 'text');

        const notification = document.createElement('div');
        notification.className = 'universal-video-notification';

        if (icon) {
            notification.innerHTML = `
                <div style="display: flex; justify-content: center; align-items: center; margin-bottom: ${settings.showLabels ? '10px' : '0'};">
                    ${icon}
                </div>
                ${settings.showLabels ? `<div style="color: white; font-size: 18px; font-weight: bold; ${textBorderStyle}">${displayText}</div>` : ''}
            `;
        } else if (settings.showLabels) {
            notification.innerHTML = `<div style="color: white; font-size: 18px; font-weight: bold; ${textBorderStyle}">${displayText}</div>`;
        }

        notification.style.cssText = `
            position: fixed;
            top: ${topPosition};
            left: ${leftPosition};
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, ${settings.backgroundOpacity});
            color: white;
            padding: ${padding};
            border-radius: ${borderRadius};
            font-size: 18px;
            font-family: 'Arial', 'Segoe UI', sans-serif;
            font-weight: bold;
            z-index: 10000;
            pointer-events: none;
            opacity: 1;
            transition: opacity 0.4s ease;
            text-align: center;
            border: ${settings.backgroundOpacity > 0 ? '3px solid rgba(255, 255, 255, 0.3)' : 'none'};
            backdrop-filter: ${settings.backgroundOpacity > 0 ? 'blur(15px)' : 'none'};
            box-shadow: ${settings.backgroundOpacity > 0 ? '0 10px 30px rgba(0, 0, 0, 0.3)' : 'none'};
            min-width: ${settings.backgroundShape === 'circle' ? '100px' : '180px'};
            min-height: ${settings.backgroundShape === 'circle' ? '100px' : 'auto'};
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        `;

        document.body.appendChild(notification);
        console.log('✅ Notification created and displayed');

        // Fade out and remove
        setTimeout(() => {
            notification.style.opacity = '0';
            setTimeout(() => {
                notification.remove();
                console.log('🗑️ Notification removed');
            }, 400);
        }, settings.notificationDuration);
    }

    // Handle keyboard events
    document.addEventListener('keydown', function(e) {
        // Don't trigger if typing in an input field
        if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) {
            console.log(`⌨️ Key ${e.key} ignored (input field)`);
            return;
        }

        const video = getVideo();
        if (!video) {
            console.log(`⌨️ Key ${e.key} ignored (no video)`);
            return;
        }

        console.log(`⌨️ Key pressed: ${e.key} (YouTube: ${isYouTube()})`);

        // On YouTube, only handle speed controls to avoid conflicts
        if (isYouTube()) {
            switch(e.key.toLowerCase()) {
                case 'a':
                    console.log('🎮 YouTube: Speed decrease (A)');
                    e.preventDefault();
                    changeSpeed(-0.25);
                    break;
                case 's':
                    console.log('🎮 YouTube: Normal speed (S)');
                    e.preventDefault();
                    setNormalSpeed();
                    break;
                case 'd':
                    console.log('🎮 YouTube: Speed increase (D)');
                    e.preventDefault();
                    changeSpeed(0.25);
                    break;
                default:
                    console.log(`🎮 YouTube: Key ${e.key} ignored (not A/S/D)`);
            }
            return;
        }

        // For non-YouTube sites, handle all shortcuts
        switch(e.key.toLowerCase()) {
            case 'k':
            case ' ':
                console.log('🎮 Play/Pause (K/Space)');
                e.preventDefault();
                togglePlay();
                break;
            case 'j':
                console.log('🎮 Rewind 10s (J)');
                e.preventDefault();
                skip(-10);
                break;
            case 'l':
                console.log('🎮 Forward 10s (L)');
                e.preventDefault();
                skip(10);
                break;
            case 'arrowleft':
                console.log('🎮 Rewind 5s (←)');
                e.preventDefault();
                skip(-5);
                break;
            case 'arrowright':
                console.log('🎮 Forward 5s (→)');
                e.preventDefault();
                skip(5);
                break;
            case '=':
                console.log('🎮 Volume up (↑)');
                e.preventDefault();
                changeVolume(0.05);
                break;
            case '+':
                console.log('🎮 Volume up (↑)');
                e.preventDefault();
                changeVolume(0.05);
                break;
            case '-':
                console.log('🎮 Volume down (↓)');
                e.preventDefault();
                changeVolume(-0.05);
                break;
            case 'm':
                console.log('🎮 Toggle mute (M)');
                e.preventDefault();
                toggleMute();
                break;
            case 'f':
                console.log('🎮 Toggle fullscreen (F)');
                e.preventDefault();
                toggleFullscreen();
                break;
            case 'a':
                console.log('🎮 Speed down (A)');
                e.preventDefault();
                changeSpeed(-0.25);
                break;
            case 's':
                console.log('🎮 Normal speed (S)');
                e.preventDefault();
                setNormalSpeed();
                break;
            case 'd':
                console.log('🎮 Speed up (D)');
                e.preventDefault();
                changeSpeed(0.25);
                break;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                console.log(`🎮 Jump to ${parseInt(e.key) * 10}% (${e.key})`);
                e.preventDefault();
                jumpToPercent(parseInt(e.key) * 10);
                break;
            case 'home':
                console.log('🎮 Jump to start (Home)');
                e.preventDefault();
                jumpToPercent(0);
                break;
            case 'end':
                console.log('🎮 Jump to end (End)');
                e.preventDefault();
                jumpToPercent(100);
                break;
            default:
                console.log(`🎮 Key ${e.key} not mapped to any action`);
        }
    });

    console.log('✅ Universal Video Shortcuts loaded! ✨ ENHANCED with video-centered notifications!');
    console.log('📋 Available shortcuts: K/Space (play/pause), J/L (skip), ←/→ (small skip), ↑/↓ (volume), M (mute), F (fullscreen), A/S/D (speed), 0-9 (jump to %)');
    console.log('⚙️  Click Tampermonkey icon → "Video Shortcuts Settings" to customize');
})();