Subtitle Overlay Tool 字幕遮挡工具

Create a draggable, resizable overlay to cover subtitles on any website

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @license MIT
// @name         Subtitle Overlay Tool 字幕遮挡工具
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Create a draggable, resizable overlay to cover subtitles on any website
// @author       Fei
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    let overlay = null;
    let isVisible = false;
    let isDragging = false;
    let isResizing = false;
    let currentResizeHandle = null;
    let dragOffset = { x: 0, y: 0 };
    let resizeStartSize = { width: 0, height: 0 };
    let resizeStartPos = { left: 0, top: 0 };
    let resizeStartMouse = { x: 0, y: 0 };
    let opacity = 1.0; // Start fully opaque
	let minOpacity = 0.05;

    // Shortcut configuration
    let currentShortcut = {
        key: 'b',
        ctrlKey: true,
        shiftKey: false,
        altKey: false
    };

    // Load saved shortcut configuration
    function loadShortcutConfig() {
        const saved = GM_getValue('shortcut_config', null);
        if (saved) {
            try {
                currentShortcut = JSON.parse(saved);
            } catch (e) {
                console.log('Error loading shortcut config, using default');
            }
        }
    }

    // Save shortcut configuration
    function saveShortcutConfig() {
        GM_setValue('shortcut_config', JSON.stringify(currentShortcut));
    }

    // Get shortcut display string
    function getShortcutDisplay() {
        let parts = [];
        if (currentShortcut.ctrlKey) parts.push('Ctrl');
        if (currentShortcut.shiftKey) parts.push('Shift');
        if (currentShortcut.altKey) parts.push('Alt');
        parts.push(currentShortcut.key.toUpperCase());
        return parts.join('+');
    }

    // Show shortcut configuration dialog
    function showShortcutConfig() {
        // Remove existing dialog if any
        const existingDialog = document.getElementById('shortcut-config-dialog');
        if (existingDialog) {
            existingDialog.remove();
        }

        // Create dialog overlay
        const dialogOverlay = document.createElement('div');
        dialogOverlay.id = 'shortcut-config-dialog';
        dialogOverlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.7);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 2147483648;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
        `;

        // Create dialog content
        const dialog = document.createElement('div');
        dialog.style.cssText = `
            background: linear-gradient(135deg, rgba(30, 30, 30, 0.95), rgba(20, 20, 20, 0.98));
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 16px;
            padding: 32px;
            max-width: 400px;
            width: 90%;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
            color: white;
        `;

        dialog.innerHTML = `
            <h2 style="margin: 0 0 24px 0; font-size: 20px; font-weight: 600; color: rgba(255, 255, 255, 0.9);">
                Customize Keyboard Shortcut
            </h2>

            <div style="margin-bottom: 24px;">
                <p style="margin: 0 0 16px 0; color: rgba(255, 255, 255, 0.7); font-size: 14px;">
                    Current shortcut: <strong>${getShortcutDisplay()}</strong>
                </p>

                <div style="margin-bottom: 16px;">
                    <label style="display: block; margin-bottom: 8px; color: rgba(255, 255, 255, 0.8); font-size: 14px;">
                        Key:
                    </label>
                    <input type="text" id="key-input" maxlength="1" value="${currentShortcut.key}"
                           style="width: 60px; padding: 8px 12px; border: 1px solid rgba(255, 255, 255, 0.2);
                                  border-radius: 8px; background: rgba(255, 255, 255, 0.1); color: white;
                                  font-size: 16px; text-align: center; text-transform: uppercase;">
                </div>

                <div style="display: flex; gap: 16px; margin-bottom: 16px;">
                    <label style="display: flex; align-items: center; gap: 8px; color: rgba(255, 255, 255, 0.8); font-size: 14px; cursor: pointer;">
                        <input type="checkbox" id="ctrl-check" ${currentShortcut.ctrlKey ? 'checked' : ''}
                               style="width: 16px; height: 16px;">
                        Ctrl
                    </label>
                    <label style="display: flex; align-items: center; gap: 8px; color: rgba(255, 255, 255, 0.8); font-size: 14px; cursor: pointer;">
                        <input type="checkbox" id="shift-check" ${currentShortcut.shiftKey ? 'checked' : ''}
                               style="width: 16px; height: 16px;">
                        Shift
                    </label>
                    <label style="display: flex; align-items: center; gap: 8px; color: rgba(255, 255, 255, 0.8); font-size: 14px; cursor: pointer;">
                        <input type="checkbox" id="alt-check" ${currentShortcut.altKey ? 'checked' : ''}
                               style="width: 16px; height: 16px;">
                        Alt
                    </label>
                </div>

                <div id="preview-shortcut" style="padding: 12px; background: rgba(99, 102, 241, 0.2);
                     border: 1px solid rgba(99, 102, 241, 0.3); border-radius: 8px; text-align: center;
                     color: rgba(255, 255, 255, 0.9); font-weight: 500; font-size: 14px;">
                    Preview: ${getShortcutDisplay()}
                </div>
            </div>

            <div style="display: flex; gap: 12px; justify-content: flex-end;">
                <button id="cancel-btn" style="padding: 10px 20px; border: 1px solid rgba(255, 255, 255, 0.2);
                        border-radius: 8px; background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.8);
                        cursor: pointer; font-size: 14px; transition: all 0.2s;">
                    Cancel
                </button>
                <button id="save-btn" style="padding: 10px 20px; border: none; border-radius: 8px;
                        background: linear-gradient(135deg, rgba(99, 102, 241, 0.8), rgba(168, 85, 247, 0.8));
                        color: white; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s;">
                    Save
                </button>
            </div>
        `;

        dialogOverlay.appendChild(dialog);
        document.body.appendChild(dialogOverlay);

        // Add event listeners for dialog
        const keyInput = dialog.querySelector('#key-input');
        const ctrlCheck = dialog.querySelector('#ctrl-check');
        const shiftCheck = dialog.querySelector('#shift-check');
        const altCheck = dialog.querySelector('#alt-check');
        const previewDiv = dialog.querySelector('#preview-shortcut');
        const cancelBtn = dialog.querySelector('#cancel-btn');
        const saveBtn = dialog.querySelector('#save-btn');

        // Update preview function
        function updatePreview() {
            const tempShortcut = {
                key: keyInput.value.toLowerCase() || 'b',
                ctrlKey: ctrlCheck.checked,
                shiftKey: shiftCheck.checked,
                altKey: altCheck.checked
            };

            let parts = [];
            if (tempShortcut.ctrlKey) parts.push('Ctrl');
            if (tempShortcut.shiftKey) parts.push('Shift');
            if (tempShortcut.altKey) parts.push('Alt');
            parts.push(tempShortcut.key.toUpperCase());

            previewDiv.textContent = 'Preview: ' + parts.join('+');
        }

        // Key input validation
        keyInput.addEventListener('input', (e) => {
            const value = e.target.value.toLowerCase();
            if (value && /^[a-z0-9]$/.test(value)) {
                e.target.value = value;
                updatePreview();
            } else if (value) {
                e.target.value = '';
            }
        });

        keyInput.addEventListener('keydown', (e) => {
            const key = e.key.toLowerCase();
            if (key.length === 1 && /^[a-z0-9]$/.test(key)) {
                e.preventDefault();
                keyInput.value = key;
                updatePreview();
            } else if (key === 'backspace') {
                e.preventDefault();
                keyInput.value = '';
                updatePreview();
            }
        });

        // Checkbox listeners
        [ctrlCheck, shiftCheck, altCheck].forEach(checkbox => {
            checkbox.addEventListener('change', updatePreview);
        });

        // Button listeners
        cancelBtn.addEventListener('click', () => {
            dialogOverlay.remove();
        });

        saveBtn.addEventListener('click', () => {
            const newKey = keyInput.value.toLowerCase() || 'b';

            // Validate that at least one modifier or a single key is selected
            if (!ctrlCheck.checked && !shiftCheck.checked && !altCheck.checked && newKey.length === 1) {
                // Single key shortcut is fine
            } else if (ctrlCheck.checked || shiftCheck.checked || altCheck.checked) {
                // Modifier + key is fine
            } else {
                alert('Please select at least one modifier key (Ctrl, Shift, or Alt) or use a single key.');
                return;
            }

            currentShortcut = {
                key: newKey,
                ctrlKey: ctrlCheck.checked,
                shiftKey: shiftCheck.checked,
                altKey: altCheck.checked
            };

            saveShortcutConfig();
            updateOverlayInstructions();
            dialogOverlay.remove();

            // Show confirmation
            showNotification(`Shortcut changed to: ${getShortcutDisplay()}`);
        });

        // Close dialog when clicking outside
        dialogOverlay.addEventListener('click', (e) => {
            if (e.target === dialogOverlay) {
                dialogOverlay.remove();
            }
        });

        // Focus the key input
        setTimeout(() => keyInput.focus(), 100);
    }

    // Show notification
    function showNotification(message) {
        const notification = document.createElement('div');
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 16px 24px;
            background: linear-gradient(135deg, rgba(34, 197, 94, 0.9), rgba(16, 185, 129, 0.9));
            color: white;
            border-radius: 12px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
            font-size: 14px;
            font-weight: 500;
            z-index: 2147483648;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
            border: 1px solid rgba(255, 255, 255, 0.2);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            transform: translateX(100%);
            transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
        `;
        notification.textContent = message;

        document.body.appendChild(notification);

        // Animate in
        setTimeout(() => {
            notification.style.transform = 'translateX(0)';
        }, 100);

        // Remove after delay
        setTimeout(() => {
            notification.style.transform = 'translateX(100%)';
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.remove();
                }
            }, 300);
        }, 3000);
    }

    // Update overlay instructions with current shortcut
    function updateOverlayInstructions() {
        if (overlay) {
            const instructionsDiv = overlay.querySelector('.instructions');
            if (instructionsDiv) {
                instructionsDiv.innerHTML = `
                    <span class="instruction-item">🔀 Drag to move</span>
                    <span class="instruction-item">📐 Resize from corners</span>
                    <span class="instruction-item">🎚️ Scroll to adjust opacity</span>
                    <span class="instruction-item">⌨️ ${getShortcutDisplay()} to toggle</span>
                `;
            }
        }
    }

    // Register Tampermonkey menu command
    function registerMenuCommands() {
        GM_registerMenuCommand('⚙️ Configure Shortcut', showShortcutConfig);
        GM_registerMenuCommand(`🔄 Toggle Overlay (${getShortcutDisplay()})`, toggleOverlay);
    }

    // Create the overlay element
    function createOverlay() {
        overlay = document.createElement('div');
        overlay.id = 'subtitle-overlay';
        overlay.style.cssText = `
            position: fixed;
            bottom: 60px;
            left: 50%;
            transform: translateX(-50%);
            width: 800px;
            height: 200px;
            background: linear-gradient(135deg, rgba(20, 20, 20, 0.95), rgba(10, 10, 10, 0.98));
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 16px;
            cursor: move;
            z-index: 2147483647;
            display: none;
            user-select: none;
            box-sizing: border-box;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4),
                        0 8px 16px rgba(0, 0, 0, 0.2),
                        inset 0 1px 0 rgba(255, 255, 255, 0.05);
            transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
        `;

        // Create resize handles for all four corners
        const resizeHandles = [
            { position: 'top-left', cursor: 'nw-resize', style: 'top: -4px; left: -4px; border-radius: 50% 0 50% 0;' },
            { position: 'top-right', cursor: 'ne-resize', style: 'top: -4px; right: -4px; border-radius: 0 50% 0 50%;' },
            { position: 'bottom-left', cursor: 'sw-resize', style: 'bottom: -4px; left: -4px; border-radius: 50% 0 50% 0;' },
            { position: 'bottom-right', cursor: 'se-resize', style: 'bottom: -4px; right: -4px; border-radius: 0 50% 0 50%;' }
        ];

        resizeHandles.forEach(handle => {
            const resizeHandle = document.createElement('div');
            resizeHandle.className = 'resize-handle';
            resizeHandle.dataset.position = handle.position;
            resizeHandle.style.cssText = `
                position: absolute;
                width: 16px;
                height: 16px;
                background: linear-gradient(135deg, rgba(99, 102, 241, 0.6), rgba(168, 85, 247, 0.6));
                border: 2px solid rgba(255, 255, 255, 0.2);
                cursor: ${handle.cursor};
                ${handle.style}
                transition: all 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
                opacity: 0;
                transform: scale(0.8);
            `;

            overlay.appendChild(resizeHandle);
        });

        // Create settings button
        const settingsButton = document.createElement('div');
        settingsButton.innerHTML = '⚙️';
        settingsButton.className = 'settings-button';
        settingsButton.style.cssText = `
            position: absolute;
            top: 12px;
            left: 12px;
            width: 32px;
            height: 32px;
            color: rgba(255, 255, 255, 0.7);
            font-size: 14px;
            cursor: pointer;
            text-align: center;
            line-height: 32px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.08);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            opacity: 0.7;
            transition: all 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
            z-index: 10;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
        `;
        settingsButton.onmouseover = () => {
            settingsButton.style.opacity = '1';
            settingsButton.style.background = 'rgba(99, 102, 241, 0.2)';
            settingsButton.style.color = 'rgba(255, 255, 255, 0.9)';
            settingsButton.style.transform = 'scale(1.05)';
        };
        settingsButton.onmouseout = () => {
            settingsButton.style.opacity = '0.7';
            settingsButton.style.background = 'rgba(255, 255, 255, 0.08)';
            settingsButton.style.color = 'rgba(255, 255, 255, 0.7)';
            settingsButton.style.transform = 'scale(1)';
        };
        settingsButton.onclick = (e) => {
            e.stopPropagation();
            showShortcutConfig();
        };
        overlay.appendChild(settingsButton);

        // Create close button
        const closeButton = document.createElement('div');
        closeButton.innerHTML = '✕';
        closeButton.className = 'close-button';
        closeButton.style.cssText = `
            position: absolute;
            top: 12px;
            right: 12px;
            width: 32px;
            height: 32px;
            color: rgba(255, 255, 255, 0.7);
            font-size: 14px;
            font-weight: 500;
            cursor: pointer;
            text-align: center;
            line-height: 32px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.08);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            opacity: 0.7;
            transition: all 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
            z-index: 10;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
        `;
        closeButton.onmouseover = () => {
            closeButton.style.opacity = '1';
            closeButton.style.background = 'rgba(239, 68, 68, 0.2)';
            closeButton.style.color = 'rgba(255, 255, 255, 0.9)';
            closeButton.style.transform = 'scale(1.05)';
        };
        closeButton.onmouseout = () => {
            closeButton.style.opacity = '0.7';
            closeButton.style.background = 'rgba(255, 255, 255, 0.08)';
            closeButton.style.color = 'rgba(255, 255, 255, 0.7)';
            closeButton.style.transform = 'scale(1)';
        };
        closeButton.onclick = hideOverlay;
        overlay.appendChild(closeButton);

        // Create info text
        const infoText = document.createElement('div');
        infoText.innerHTML = `
            <div class="title">Subtitle Blocker</div>
            <div class="instructions">
                <span class="instruction-item">🔀 Drag to move</span>
                <span class="instruction-item">📐 Resize from corners</span>
                <span class="instruction-item">🎚️ Scroll to adjust opacity</span>
                <span class="instruction-item">⌨️ ${getShortcutDisplay()} to toggle</span>
            </div>
        `;
        infoText.className = 'info-text';
        infoText.style.cssText = `
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
            pointer-events: none;
            opacity: 0; /* Initially hidden */
            transition: opacity 0.3s ease-in-out; /* Smooth transition */
        `;

        // Add styles for title and instructions
        const style = document.createElement('style');
        style.textContent = `
            #subtitle-overlay .title {
                color: rgba(255, 255, 255, 0.9);
                font-size: 18px;
                font-weight: 600;
                margin-bottom: 12px;
                letter-spacing: 0.5px;
            }

            #subtitle-overlay .instructions {
                display: flex;
                flex-wrap: wrap;
                justify-content: center;
                gap: 16px;
                max-width: 400px;
                margin: 0 auto;
            }

            #subtitle-overlay .instruction-item {
                color: rgba(255, 255, 255, 0.6);
                font-size: 12px;
                font-weight: 400;
                display: flex;
                align-items: center;
                gap: 6px;
                padding: 4px 8px;
                background: rgba(255, 255, 255, 0.05);
                border-radius: 8px;
                border: 1px solid rgba(255, 255, 255, 0.05);
                backdrop-filter: blur(5px);
                -webkit-backdrop-filter: blur(5px);
            }

            @media (max-width: 600px) {
                #subtitle-overlay .instructions {
                    flex-direction: column;
                    gap: 8px;
                }

                #subtitle-overlay .instruction-item {
                    font-size: 10px;
                    padding: 3px 6px;
                }

                #subtitle-overlay .title {
                    font-size: 16px;
                    margin-bottom: 8px;
                }
            }
        `;
        document.head.appendChild(style);

        overlay.appendChild(infoText);

        document.body.appendChild(overlay);
        attachEventListeners();
        handleFullscreenEvents();

        // Show resize handles and info text on hover
        overlay.addEventListener('mouseenter', () => {
            overlay.querySelectorAll('.resize-handle').forEach(handle => {
                handle.style.opacity = '1';
                handle.style.transform = 'scale(1)';
            });
            const infoTextElement = overlay.querySelector('.info-text');
            if (infoTextElement) {
                infoTextElement.style.opacity = '0.8'; // Make text visible on hover
            }
        });

        overlay.addEventListener('mouseleave', () => {
            if (!isResizing && !isDragging) {
                overlay.querySelectorAll('.resize-handle').forEach(handle => {
                    handle.style.opacity = '0';
                    handle.style.transform = 'scale(0.8)';
                });
                const infoTextElement = overlay.querySelector('.info-text');
                if (infoTextElement) {
                    infoTextElement.style.opacity = '0'; // Hide text when mouse leaves
                }
            }
        });
    }

    function updateOpacity() {
        if (overlay) {
            // Create a more sophisticated opacity system with glassmorphism
            const alpha = Math.max(minOpacity, opacity);
            const gradientAlpha1 = Math.max(minOpacity, alpha * 0.95);
            const gradientAlpha2 = Math.max(minOpacity, alpha * 0.98);

            overlay.style.background = `linear-gradient(135deg, rgba(20, 20, 20, ${gradientAlpha1}), rgba(10, 10, 10, ${gradientAlpha2}))`;

            // Adjust border and shadow opacity based on main opacity
            const borderOpacity = Math.max(0.02, alpha * 0.1);
            const shadowOpacity = Math.max(minOpacity, alpha * 0.4);

            overlay.style.borderColor = `rgba(255, 255, 255, ${borderOpacity})`;
            overlay.style.boxShadow = `
                0 20px 40px rgba(0, 0, 0, ${shadowOpacity}),
                0 8px 16px rgba(0, 0, 0, ${shadowOpacity * 0.5}),
                inset 0 1px 0 rgba(255, 255, 255, ${borderOpacity * 0.5})
            `;
        }
    }

    function showOpacityFeedback(percentage) {
        // Remove existing feedback if any
        const existingFeedback = document.getElementById('opacity-feedback');
        if (existingFeedback) {
            existingFeedback.remove();
        }

        // Create opacity feedback indicator
        const feedback = document.createElement('div');
        feedback.id = 'opacity-feedback';
        feedback.innerHTML = `${percentage}%`;
        feedback.style.cssText = `
            position: absolute;
            top: 12px;
            left: 50px;
            padding: 6px 12px;
            background: rgba(0, 0, 0, 0.8);
            color: white;
            border-radius: 8px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
            font-size: 12px;
            font-weight: 500;
            z-index: 10;
            pointer-events: none;
            border: 1px solid rgba(255, 255, 255, 0.2);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            opacity: 0;
            transform: scale(0.8);
            transition: all 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
        `;

        overlay.appendChild(feedback);

        // Animate in
        requestAnimationFrame(() => {
            feedback.style.opacity = '1';
            feedback.style.transform = 'scale(1)';
        });

        // Remove after delay
        setTimeout(() => {
            if (feedback && feedback.parentNode) {
                feedback.style.opacity = '0';
                feedback.style.transform = 'scale(0.8)';
                setTimeout(() => {
                    if (feedback && feedback.parentNode) {
                        feedback.remove();
                    }
                }, 200);
            }
        }, 1500);
    }

    function handleFullscreenEvents() {
        // Listen for fullscreen changes
        document.addEventListener('fullscreenchange', handleFullscreenChange);
        document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
        document.addEventListener('mozfullscreenchange', handleFullscreenChange);
        document.addEventListener('MSFullscreenChange', handleFullscreenChange);
    }

    function handleFullscreenChange() {
        if (!overlay) return;

        // Get the fullscreen element
        const fullscreenElement = document.fullscreenElement ||
                                document.webkitFullscreenElement ||
                                document.mozFullScreenElement ||
                                document.msFullscreenElement;

        if (fullscreenElement) {
            // Entering fullscreen - move overlay to fullscreen element
            try {
                fullscreenElement.appendChild(overlay);
                // Ensure overlay maintains its properties in fullscreen
                overlay.style.position = 'absolute';
                overlay.style.zIndex = '2147483647';

                // If overlay was visible before fullscreen, keep it visible
                if (isVisible) {
                    overlay.style.display = 'block';
                }
            } catch (e) {
                // Fallback: keep in body but ensure maximum z-index
                overlay.style.position = 'fixed';
                overlay.style.zIndex = '2147483647';
                if (isVisible) {
                    overlay.style.display = 'block';
                }
            }
        } else {
            // Exiting fullscreen - move overlay back to body
            if (overlay.parentNode !== document.body) {
                document.body.appendChild(overlay);
            }
            overlay.style.position = 'fixed';
            overlay.style.zIndex = '2147483647';

            // Ensure overlay remains visible if it was visible before
            if (isVisible) {
                overlay.style.display = 'block';
            }
        }
    }

    function attachEventListeners() {
        const resizeHandles = overlay.querySelectorAll('.resize-handle');
        const closeButton = overlay.querySelector('.close-button');
        const settingsButton = overlay.querySelector('.settings-button');

        // Mouse down on overlay
        overlay.addEventListener('mousedown', function(e) {
            // Check if clicking on a resize handle
            const resizeHandle = e.target.closest('.resize-handle');
            if (resizeHandle) {
                startResize(e, resizeHandle.dataset.position);
            } else if (e.target !== closeButton && !e.target.closest('.close-button') &&
                      e.target !== settingsButton && !e.target.closest('.settings-button')) {
                startDrag(e);
            }
        });

        // Mouse move
        document.addEventListener('mousemove', function(e) {
            if (isDragging) {
                drag(e);
            } else if (isResizing) {
                resize(e);
            }
        });

        // Mouse up
        document.addEventListener('mouseup', function() {
            isDragging = false;
            isResizing = false;
            currentResizeHandle = null;
            if (overlay) {
                overlay.style.cursor = 'move';
            }
        });

        // Prevent text selection while dragging
        document.addEventListener('selectstart', function(e) {
            if (isDragging || isResizing) {
                e.preventDefault();
            }
        });

        // Scroll wheel opacity adjustment
        overlay.addEventListener('wheel', function(e) {
            e.preventDefault();
            e.stopPropagation();

            const delta = e.deltaY > 0 ? -0.05 : 0.05;
            opacity = Math.max(minOpacity, Math.min(1.0, opacity + delta));
            updateOpacity();

            // Visual feedback - briefly show current opacity
            showOpacityFeedback(Math.round(opacity * 100));
        }, { passive: false });
    }

    function startDrag(e) {
        isDragging = true;
        const rect = overlay.getBoundingClientRect();
        dragOffset.x = e.clientX - rect.left;
        dragOffset.y = e.clientY - rect.top;
        overlay.style.cursor = 'grabbing';
    }

    function drag(e) {
        if (!isDragging) return;

        const x = e.clientX - dragOffset.x;
        const y = e.clientY - dragOffset.y;

        // Keep overlay within viewport bounds
        const maxX = window.innerWidth - overlay.offsetWidth;
        const maxY = window.innerHeight - overlay.offsetHeight;

        const boundedX = Math.max(0, Math.min(x, maxX));
        const boundedY = Math.max(0, Math.min(y, maxY));

        overlay.style.left = boundedX + 'px';
        overlay.style.top = boundedY + 'px';
        overlay.style.transform = 'none';
    }

    function startResize(e, position) {
        e.stopPropagation();
        isResizing = true;
        currentResizeHandle = position;

        const rect = overlay.getBoundingClientRect();
        resizeStartSize.width = rect.width;
        resizeStartSize.height = rect.height;
        resizeStartPos.left = rect.left;
        resizeStartPos.top = rect.top;
        resizeStartMouse.x = e.clientX;
        resizeStartMouse.y = e.clientY;

        // Set appropriate cursor
        const cursors = {
            'top-left': 'nw-resize',
            'top-right': 'ne-resize',
            'bottom-left': 'sw-resize',
            'bottom-right': 'se-resize'
        };
        overlay.style.cursor = cursors[position];
    }

    function resize(e) {
        if (!isResizing || !currentResizeHandle) return;

        const deltaX = e.clientX - resizeStartMouse.x;
        const deltaY = e.clientY - resizeStartMouse.y;

        let newWidth = resizeStartSize.width;
        let newHeight = resizeStartSize.height;
        let newLeft = resizeStartPos.left;
        let newTop = resizeStartPos.top;

        // Apply resize logic based on which handle is being dragged
        switch (currentResizeHandle) {
            case 'top-left':
                newWidth = Math.max(200, resizeStartSize.width - deltaX);
                newHeight = Math.max(100, resizeStartSize.height - deltaY);
                newLeft = resizeStartPos.left + (resizeStartSize.width - newWidth);
                newTop = resizeStartPos.top + (resizeStartSize.height - newHeight);
                break;
            case 'top-right':
                newWidth = Math.max(200, resizeStartSize.width + deltaX);
                newHeight = Math.max(100, resizeStartSize.height - deltaY);
                newTop = resizeStartPos.top + (resizeStartSize.height - newHeight);
                break;
            case 'bottom-left':
                newWidth = Math.max(200, resizeStartSize.width - deltaX);
                newHeight = Math.max(100, resizeStartSize.height + deltaY);
                newLeft = resizeStartPos.left + (resizeStartSize.width - newWidth);
                break;
            case 'bottom-right':
                newWidth = Math.max(200, resizeStartSize.width + deltaX);
                newHeight = Math.max(100, resizeStartSize.height + deltaY);
                break;
        }

        // Apply bounds checking
        newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - newWidth));
        newTop = Math.max(0, Math.min(newTop, window.innerHeight - newHeight));

        overlay.style.width = newWidth + 'px';
        overlay.style.height = newHeight + 'px';
        overlay.style.left = newLeft + 'px';
        overlay.style.top = newTop + 'px';
        overlay.style.transform = 'none';
    }

    function showOverlay() {
        if (!overlay) createOverlay();
        overlay.style.display = 'block';
        isVisible = true;
        console.log('Subtitle overlay shown');
    }

    function hideOverlay() {
        if (overlay) {
            overlay.style.display = 'none';
            overlay.style.cursor = 'move';
        }
        isVisible = false;
        isDragging = false;
        isResizing = false;
        currentResizeHandle = null;

        // Hide resize handles and info text when overlay is hidden
        if (overlay) {
            overlay.querySelectorAll('.resize-handle').forEach(handle => {
                handle.style.opacity = '0';
                handle.style.transform = 'scale(0.8)';
            });
            const infoTextElement = overlay.querySelector('.info-text');
            if (infoTextElement) {
                infoTextElement.style.opacity = '0'; // Hide text when overlay is hidden
            }
        }

        console.log('Subtitle overlay hidden');
    }

    function toggleOverlay() {
        if (isVisible) {
            hideOverlay();
        } else {
            showOverlay();
        }
    }

    // Enhanced keyboard shortcut listener with multiple approaches
    function setupKeyboardListeners() {
        // Method 1: Standard keydown event
        document.addEventListener('keydown', handleKeyDown, true);

        // Method 2: Window-level keydown event (for fullscreen)
        window.addEventListener('keydown', handleKeyDown, true);

        // Method 3: Body-level keydown event
        if (document.body) {
            document.body.addEventListener('keydown', handleKeyDown, true);
        }

        // Method 4: Document element keydown event
        if (document.documentElement) {
            document.documentElement.addEventListener('keydown', handleKeyDown, true);
        }
    }

    function handleKeyDown(e) {
        // Check for the configured shortcut combination
        const keyMatch = e.key.toLowerCase() === currentShortcut.key ||
                        e.keyCode === currentShortcut.key.toUpperCase().charCodeAt(0);

        const ctrlMatch = e.ctrlKey === currentShortcut.ctrlKey;
        const shiftMatch = e.shiftKey === currentShortcut.shiftKey;
        const altMatch = e.altKey === currentShortcut.altKey;

        if (keyMatch && ctrlMatch && shiftMatch && altMatch) {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();

            console.log(`${getShortcutDisplay()} detected, toggling overlay`);
            toggleOverlay();
            return false;
        }
    }

    // Initialize keyboard listeners when DOM is ready
    function initializeKeyboardListeners() {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', setupKeyboardListeners);
        } else {
            setupKeyboardListeners();
        }

        // Also setup on window load as backup
        window.addEventListener('load', setupKeyboardListeners);

        // Set up a periodic check to re-establish listeners (for dynamic content)
        setInterval(() => {
            setupKeyboardListeners();
        }, 5000);
    }

    // YouTube-specific handling
    function handleYouTubeSpecifics() {
        if (window.location.hostname.includes('youtube.com')) {
            // YouTube often captures keyboard events, so we need to be more aggressive
            const ytPlayer = document.getElementById('movie_player') ||
                           document.querySelector('.html5-video-player') ||
                           document.querySelector('video');

            if (ytPlayer) {
                ytPlayer.addEventListener('keydown', handleKeyDown, true);

                // Also listen on the video element itself
                const video = ytPlayer.querySelector('video') || ytPlayer;
                if (video && video.tagName === 'VIDEO') {
                    video.addEventListener('keydown', handleKeyDown, true);
                }
            }

            // Listen for YouTube's navigation changes
            let lastUrl = location.href;
            new MutationObserver(() => {
                const url = location.href;
                if (url !== lastUrl) {
                    lastUrl = url;
                    setTimeout(setupKeyboardListeners, 1000); // Re-setup after navigation
                }
            }).observe(document, { subtree: true, childList: true });
        }
    }

    // Initialize everything
    function initialize() {
        console.log(`Subtitle Overlay Tool loaded. Press ${getShortcutDisplay()} to toggle overlay. Scroll over overlay to adjust opacity.`);

        // Load saved configuration
        loadShortcutConfig();

        // Register menu commands
        registerMenuCommands();

        initializeKeyboardListeners();
        handleYouTubeSpecifics();

        // Create overlay initially (hidden)
        createOverlay();
        hideOverlay();
    }

    // Start initialization
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }
})();