图片隐藏

单张或者全局图片隐藏与显示

// ==UserScript==
// @name         图片隐藏
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  单张或者全局图片隐藏与显示
// @match        *://*/*
// @author       eternal5130
// @license      MIT
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// ==/UserScript==


(function() {
    'use strict';
 
    // 默认快捷键配置
    const DEFAULT_SHORTCUT = {
        single: {
            keys: ['MouseMiddle']
        },
        global: {
            keys: ['AltLeft', 'KeyH']
        }
    };
 
    // 存储图片状态
    const imageStates = new Map();
    const currentPressedKeys = new Set();
    let currentHoverTarget = null;
    let configModal = null;
    let globalImageCounter = 0;
 
    // 获取快捷键配置
    function getShortcutConfig() {
        try {
            const savedConfig = GM_getValue('imageHiderShortcut');
            return savedConfig ? JSON.parse(savedConfig) : { ...DEFAULT_SHORTCUT };
        } catch (error) {
            console.error('获取快捷键配置失败,使用默认配置', error);
            return { ...DEFAULT_SHORTCUT };
        }
    }
 
    // 保存快捷键配置
    function saveShortcutConfig(config) {
        try {
            GM_setValue('imageHiderShortcut', JSON.stringify(config));
        } catch (error) {
            console.error('保存快捷键配置失败', error);
            alert('保存配置时出错,请重试');
        }
    }
 
    // 将按键码转换为可读名称
    function getKeyDisplayName(code) {
        const keyNameMap = {
            'AltLeft': 'Alt (左)', 'AltRight': 'Alt (右)',
            'ControlLeft': 'Ctrl (左)', 'ControlRight': 'Ctrl (右)',
            'ShiftLeft': 'Shift (左)', 'ShiftRight': 'Shift (右)',
            'MetaLeft': 'Meta (左)', 'MetaRight': 'Meta (右)',
            'MouseLeft': '鼠标左键', 'MouseMiddle': '鼠标中键', 'MouseRight': '鼠标右键',
            'KeyA': 'A', 'KeyB': 'B', 'KeyC': 'C', 'KeyD': 'D', 'KeyE': 'E',
            'KeyF': 'F', 'KeyG': 'G', 'KeyH': 'H', 'KeyI': 'I', 'KeyJ': 'J',
            'KeyK': 'K', 'KeyL': 'L', 'KeyM': 'M', 'KeyN': 'N', 'KeyO': 'O',
            'KeyP': 'P', 'KeyQ': 'Q', 'KeyR': 'R', 'KeyS': 'S', 'KeyT': 'T',
            'KeyU': 'U', 'KeyV': 'V', 'KeyW': 'W', 'KeyX': 'X', 'KeyY': 'Y', 'KeyZ': 'Z',
            'Digit0': '0', 'Digit1': '1', 'Digit2': '2', 'Digit3': '3',
            'Digit4': '4', 'Digit5': '5', 'Digit6': '6', 'Digit7': '7',
            'Digit8': '8', 'Digit9': '9'
        };
        return keyNameMap[code] || code;
    }
 
    // 检查快捷键是否匹配
    function isShortcutMatch(config) {
        const { keys = [] } = config;
        return keys.every(key => currentPressedKeys.has(key));
    }
 
    // 创建模态框样式
    function createModalStyles() {
        const style = document.createElement('style');
        style.textContent = `
            .image-hider-modal {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: #fff;
                border-radius: 12px;
                box-shadow: 0 10px 25px rgba(0,0,0,0.1);
                padding: 24px;
                z-index: 10000;
                width: 500px;
                max-height: 80vh;
                overflow-y: auto;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
                position: relative;
            }
            .image-hider-modal h2 {
                color: #333;
                margin-bottom: 16px;
                font-weight: 600;
            }
            .image-hider-modal button {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 10px 16px;
                margin: 8px;
                border-radius: 6px;
                cursor: pointer;
                transition: background-color 0.3s;
            }
            .image-hider-modal button:hover {
                background-color: #45a049;
            }
            .image-hider-modal button.cancel {
                background-color: #f44336;
            }
            .image-hider-modal .current-shortcut {
                background-color: #f0f0f0;
                padding: 10px;
                margin-bottom: 16px;
                border-radius: 6px;
                text-align: center;
            }
            .image-hider-modal .shortcut-input {
                width: 100%;
                padding: 10px;
                margin: 10px 0;
                border: 1px solid #ddd;
                border-radius: 6px;
                font-size: 16px;
                text-align: center;
            }
            .image-hider-modal .close-btn {
                position: absolute;
                right: 16px;
                top: 16px;
                width: 24px;
                height: 24px;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                border-radius: 50%;
                background: #f5f5f5;
                border: none;
                padding: 0;
            }
            .image-hider-modal .close-btn:hover {
                background: #e0e0e0;
            }
            .image-hider-modal .close-btn::before,
            .image-hider-modal .close-btn::after {
                content: '';
                position: absolute;
                width: 14px;
                height: 2px;
                background: #666;
            }
            .image-hider-modal .close-btn::before {
                transform: rotate(45deg);
            }
            .image-hider-modal .close-btn::after {
                transform: rotate(-45deg);
            }
            .image-hider-modal .shortcut-section {
                background: #f8f9fa;
                border-radius: 8px;
                padding: 16px;
                margin-bottom: 16px;
            }
            .image-hider-modal .shortcut-section h3 {
                color: #2c3e50;
                margin: 0 0 12px 0;
                font-size: 1.1em;
                font-weight: 500;
            }
            .image-hider-modal .shortcut-section .current-shortcut {
                background-color: #fff;
                margin-bottom: 12px;
            }
            .image-hider-modal .shortcut-section button {
                margin: 8px 0;
                width: 100%;
            }
            .image-hider-modal .button-group {
                margin-top: 24px;
            }
            .settings-item {
                display: flex;
                align-items: center;
                margin: 16px 0;
                padding: 8px;
                background: #fff;
                border-radius: 8px;
            }
 
            .settings-label {
                margin-left: 12px;
                color: #495057;
            }
 
            .image-hider-switch {
                position: relative;
                display: inline-block;
                width: 60px;
                height: 34px;
            }
 
            .image-hider-switch input {
                opacity: 0;
                width: 0;
                height: 0;
            }
 
            .image-hider-slider {
                position: absolute;
                cursor: pointer;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background-color: #ccc;
                transition: background-color 0.4s, transform 0.4s;
                border-radius: 34px;
                box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
            }
 
            .image-hider-slider:before {
                position: absolute;
                content: "";
                height: 26px;
                width: 26px;
                left: 4px;
                bottom: 4px;
                background-color: white;
                transition: transform 0.4s;
                border-radius: 50%;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            }
 
            .image-hider-switch input:checked + .image-hider-slider {
                background-color: #4CAF50;
            }
 
            .image-hider-switch input:checked + .image-hider-slider:before {
                transform: translateX(26px);
            }
 
            .image-hider-slider:hover {
                background-color: #b3b3b3;
            }
 
            .settings-item {
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 16px 20px;
                transition: background-color 0.2s ease;
            }
 
            .settings-content {
                flex: 1;
                margin-right: 16px;
            }
 
            .settings-title {
                font-size: 14px;
                font-weight: 500;
                color: #303133;
                margin-bottom: 4px;
            }
 
            .settings-description {
                font-size: 12px;
                color: #909399;
                line-height: 1.4;
            }
        `;
        document.head.appendChild(style);
    }
 
    // 添加全局状态存储
    function getGlobalHideState() {
        return GM_getValue('globalHideState', false);
    }
 
    function setGlobalHideState(state) {
        GM_setValue('globalHideState', state);
    }
 
    // 修改 toggleAllImages 函数
    function toggleAllImages() {
        const images = document.getElementsByTagName('img');
 
        Array.from(images).forEach(img => {
            if (!img.dataset.imageId) {
                img.dataset.imageId = `img_${++globalImageCounter}`;
                imageStates.set(img.dataset.imageId, new ImageState(img));
            }
        });
 
        const visibleImages = Array.from(images).filter(img => {
            const state = imageStates.get(img.dataset.imageId);
            return !state?.isHidden;
        });
 
        const shouldHide = visibleImages.length > 0;
 
        // 更新全局状态
        setGlobalHideState(shouldHide);
 
        requestAnimationFrame(() => {
            Array.from(images).forEach(img => {
                toggleImageVisibility(img, shouldHide, false);
            });
        });
    }
 
    // 修改初始化函数
    function initAutoHide() {
        const shouldHide = getGlobalHideState();
        if (shouldHide) {
            // 立即处理当前可见的图片
            const processImages = () => {
                const images = document.getElementsByTagName('img');
                Array.from(images).forEach(img => {
                    if (!img.dataset.imageId) {
                        img.dataset.imageId = `img_${++globalImageCounter}`;
                        imageStates.set(img.dataset.imageId, new ImageState(img));
                    }
                    
                    // 立即设置初始样式,防止图片闪现
                    img.style.cssText = `
                        opacity: 0 !important;
                        pointer-events: none !important;
                        transition: none !important;
                    `;
                    
                    if (img.complete) {
                        toggleImageVisibility(img, true, true);
                    } else {
                        // 在图片加载前就开始监听
                        img.addEventListener('load', () => toggleImageVisibility(img, true, true), { once: true });
                    }
                });
            };

            // 首次处理
            processImages();

            // 使用 MutationObserver 监听 DOM 变化
            const observer = new MutationObserver((mutations) => {
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.tagName === 'IMG') {
                            // 立即设置初始样式
                            node.style.cssText = `
                                opacity: 0 !important;
                                pointer-events: none !important;
                                transition: none !important;
                            `;
                            toggleImageVisibility(node, true, true);
                        } else if (node.getElementsByTagName) {
                            const images = node.getElementsByTagName('img');
                            Array.from(images).forEach(img => {
                                // 立即设置初始样式
                                img.style.cssText = `
                                    opacity: 0 !important;
                                    pointer-events: none !important;
                                    transition: none !important;
                                `;
                                toggleImageVisibility(img, true, true);
                            });
                        }
                    });
                });
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['src']
            });

            // 添加 DOM 内容加载完成的处理
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', processImages);
            }

            // 添加页面完全加载完成的处理
            window.addEventListener('load', processImages);

            // 清理函数
            const cleanup = () => {
                observer.disconnect();
            };

            // 页面卸载时清理
            window.addEventListener('unload', cleanup);
        }
    }
 
    // 修改配置弹窗,移除自动隐藏开关相关代码
    function createConfigModal() {
        if (!document.querySelector('#image-hider-modal-styles')) {
            const style = document.createElement('style');
            style.id = 'image-hider-modal-styles';
            style.textContent = `
                .image-hider-modal {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background: #fff;
                    border-radius: 12px;
                    box-shadow: 0 10px 25px rgba(0,0,0,0.15);
                    padding: 28px;
                    z-index: 10000;
                    width: 480px;
                    max-height: 80vh;
                    overflow-y: auto;
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                    animation: modalFadeIn 0.2s ease-out;
                    box-sizing: border-box;
                }

                .image-hider-modal * {
                    box-sizing: border-box;
                }

                @keyframes modalFadeIn {
                    from {
                        opacity: 0;
                        transform: translate(-50%, -48%);
                    }
                    to {
                        opacity: 1;
                        transform: translate(-50%, -50%);
                    }
                }

                .image-hider-modal h2 {
                    color: #2c3e50;
                    margin: 0 0 20px 0;
                    font-size: 1.5em;
                    font-weight: 600;
                    line-height: 1.4;
                }

                .image-hider-modal .shortcut-section {
                    background: #f8f9fa;
                    border-radius: 8px;
                    padding: 20px;
                    margin-bottom: 20px;
                    border: 1px solid #e9ecef;
                }

                .image-hider-modal .shortcut-section h3 {
                    color: #2c3e50;
                    margin: 0 0 16px 0;
                    font-size: 1.1em;
                    font-weight: 500;
                    line-height: 1.4;
                }

                .image-hider-modal .current-shortcut {
                    background-color: #fff;
                    padding: 12px 16px;
                    margin-bottom: 16px;
                    border-radius: 8px;
                    text-align: center;
                    border: 1px solid #e9ecef;
                    color: #495057;
                    line-height: 1.5;
                    font-size: 14px;
                }

                .image-hider-modal .shortcut-input {
                    width: 100%;
                    height: 42px;
                    padding: 8px 16px;
                    margin: 10px 0;
                    border: 2px solid #e9ecef;
                    border-radius: 8px;
                    font-size: 14px;
                    text-align: center;
                    background: #fff;
                    transition: all 0.2s ease;
                    color: #495057;
                    line-height: 1.5;
                    display: block;
                }

                .image-hider-modal .shortcut-input:focus {
                    border-color: #4CAF50;
                    outline: none;
                    box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1);
                }

                .image-hider-modal .shortcut-input.recording {
                    background: #e8f5e9;
                    border-color: #4CAF50;
                }

                .image-hider-modal .shortcut-input::placeholder {
                    color: #adb5bd;
                }

                .image-hider-modal .button-wrapper {
                    display: flex;
                    justify-content: center;
                    margin: 12px 0;
                }

                .image-hider-modal button {
                    padding: 10px 20px;
                    border-radius: 8px;
                    border: none;
                    cursor: pointer;
                    font-size: 14px;
                    font-weight: 500;
                    transition: all 0.2s ease;
                    min-width: 120px;
                    height: 40px;
                    line-height: 20px;
                    display: inline-flex;
                    align-items: center;
                    justify-content: center;
                    margin: 0;
                }

                .image-hider-modal button#setShortcutBtn,
                .image-hider-modal button#setSingleShortcutBtn,
                .image-hider-modal button#setGlobalShortcutBtn {
                    background-color: #f8f9fa;
                    color: #495057;
                    border: 1px solid #dee2e6;
                    width: 100%;
                }

                .image-hider-modal button#setShortcutBtn:hover,
                .image-hider-modal button#setSingleShortcutBtn:hover,
                .image-hider-modal button#setGlobalShortcutBtn:hover {
                    background-color: #e9ecef;
                }

                .image-hider-modal button#setShortcutBtn.recording,
                .image-hider-modal button#setSingleShortcutBtn.recording,
                .image-hider-modal button#setGlobalShortcutBtn.recording {
                    background-color: #4CAF50;
                    color: white;
                    border: none;
                }

                .image-hider-modal .button-group {
                    display: flex;
                    gap: 12px;
                    margin-top: 24px;
                    justify-content: center;
                }

                .image-hider-modal button#saveConfigBtn {
                    background-color: #4CAF50;
                    color: white;
                    min-width: 140px;
                }

                .image-hider-modal button#saveConfigBtn:hover {
                    background-color: #43a047;
                }

                .image-hider-modal .close-btn {
                    position: absolute;
                    right: 16px;
                    top: 16px;
                    width: 32px;
                    height: 32px;
                    border-radius: 16px;
                    background: #f8f9fa;
                    border: none;
                    cursor: pointer;
                    transition: all 0.2s ease;
                    padding: 0;
                    min-width: unset;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }

                .image-hider-modal .close-btn:hover {
                    background: #e9ecef;
                }

                .image-hider-modal .close-btn::before,
                .image-hider-modal .close-btn::after {
                    content: '';
                    position: absolute;
                    width: 16px;
                    height: 2px;
                    background: #495057;
                    transition: background 0.2s;
                }

                .image-hider-modal .close-btn::before {
                    transform: rotate(45deg);
                }

                .image-hider-modal .close-btn::after {
                    transform: rotate(-45deg);
                }

                .image-hider-modal .hint {
                    color: #6c757d;
                    font-size: 13px;
                    margin-top: 20px;
                    line-height: 1.6;
                    padding: 16px;
                    background: #f8f9fa;
                    border-radius: 8px;
                    border: 1px solid #e9ecef;
                }

                .image-hider-modal .success-message {
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background: rgba(76, 175, 80, 0.9);
                    color: white;
                    padding: 16px 32px;
                    border-radius: 8px;
                    font-weight: 500;
                    opacity: 0;
                    transition: opacity 0.3s ease;
                    pointer-events: none;
                }

                .image-hider-modal .success-message.show {
                    opacity: 1;
                }

                .image-hider-modal.closing {
                    opacity: 0;
                    transform: translate(-50%, -48%);
                    transition: all 0.3s ease;
                }
            `;
            document.head.appendChild(style);
        }
 
        if (configModal) {
            configModal.remove();
        }
 
        configModal = document.createElement('div');
        configModal.className = 'image-hider-modal';
 
        const shortcutConfig = getShortcutConfig();
        const singleShortcutDisplay = (shortcutConfig.single.keys || DEFAULT_SHORTCUT.single.keys)
            .map(key => getKeyDisplayName(key))
            .join(' + ');
        const globalShortcutDisplay = (shortcutConfig.global.keys || DEFAULT_SHORTCUT.global.keys)
            .map(key => getKeyDisplayName(key))
            .join(' + ');
 
        configModal.innerHTML = `
            <button class="close-btn" id="closeConfigBtn"></button>
            <h2>图片隐藏快捷键配置</h2>
 
            <div class="shortcut-section">
                <h3>单个图片快捷键</h3>
                <div class="current-shortcut">
                    <strong>当前快捷键:</strong>${singleShortcutDisplay}
                </div>
                <input type="text" readonly class="shortcut-input" id="singleShortcutInput"
                       placeholder="点击"设置快捷键"开始录制">
                <div class="button-wrapper">
                    <button id="setSingleShortcutBtn">设置快捷键</button>
                </div>
            </div>
 
            <div class="shortcut-section">
                <h3>全局图片快捷键</h3>
                <div class="current-shortcut">
                    <strong>当前快捷键:</strong>${globalShortcutDisplay}
                </div>
                <input type="text" readonly class="shortcut-input" id="globalShortcutInput"
                       placeholder="点击"设置快捷键"开始录制">
                <div class="button-wrapper">
                    <button id="setGlobalShortcutBtn">设置快捷键</button>
                </div>
            </div>
 
            <div class="button-group">
                <button id="saveConfigBtn">保存设置</button>
            </div>
 
            <div class="hint">
                <strong>使用说明:</strong><br>
                1. 单个图片快捷键:悬停在图片上时触发隐藏/显示<br>
                2. 全局图片快捷键:一键切换所有图片的显示状态,状态会在新页面保持<br>
                3. 点击对应的"设置快捷键"开始录制<br>
                4. 完成设置后点击"保存设置"确认更改
            </div>
        `;
 
        document.body.appendChild(configModal);
 
        const setSingleShortcutBtn = configModal.querySelector('#setSingleShortcutBtn');
        const setGlobalShortcutBtn = configModal.querySelector('#setGlobalShortcutBtn');
        const saveConfigBtn = configModal.querySelector('#saveConfigBtn');
        const closeConfigBtn = configModal.querySelector('#closeConfigBtn');
        const singleShortcutInput = configModal.querySelector('#singleShortcutInput');
        const globalShortcutInput = configModal.querySelector('#globalShortcutInput');
 
        let isRecording = false;
        let currentRecordingType = null;
        let singlePressedKeys = new Set();
        let globalPressedKeys = new Set();
 
        function startRecording(type, input, button) {
            if (isRecording) return;
 
            isRecording = true;
            currentRecordingType = type;
            const keysSet = type === 'single' ? singlePressedKeys : globalPressedKeys;
            keysSet.clear();
 
            input.value = '请按下快捷键组合...';
            input.classList.add('recording');
            button.classList.add('recording');
            button.textContent = '正在录制...';
 
            const keydownHandler = (e) => {
                e.preventDefault();
                keysSet.add(e.code);
                updateShortcutDisplay(input, keysSet);
            };
 
            const keyupHandler = (e) => {
                e.preventDefault();
                if (keysSet.size > 0) {
                    finishRecording(input, button);
                }
            };
 
            const mousedownHandler = (e) => {
                e.preventDefault();
                if (e.button === 1) {
                    keysSet.add('MouseMiddle');
                    updateShortcutDisplay(input, keysSet);
                }
            };
 
            const mouseupHandler = (e) => {
                e.preventDefault();
                if (e.button === 1 && keysSet.size > 0) {
                    finishRecording(input, button);
                }
            };
 
            document.addEventListener('keydown', keydownHandler);
            document.addEventListener('keyup', keyupHandler);
            document.addEventListener('mousedown', mousedownHandler);
            document.addEventListener('mouseup', mouseupHandler);
 
            // 保存清理函数
            button.cleanup = () => {
                document.removeEventListener('keydown', keydownHandler);
                document.removeEventListener('keyup', keyupHandler);
                document.removeEventListener('mousedown', mousedownHandler);
                document.removeEventListener('mouseup', mouseupHandler);
            };
        }
 
        function updateShortcutDisplay(input, keysSet) {
            input.value = Array.from(keysSet)
                .map(getKeyDisplayName)
                .join(' + ');
        }
 
        function finishRecording(input, button) {
            isRecording = false;
            currentRecordingType = null;
            input.classList.remove('recording');
            button.classList.remove('recording');
            button.textContent = '设置快捷键';
 
            if (button.cleanup) {
                button.cleanup();
                button.cleanup = null;
            }
        }
 
        setSingleShortcutBtn.addEventListener('click', () => {
            startRecording('single', singleShortcutInput, setSingleShortcutBtn);
        });
 
        setGlobalShortcutBtn.addEventListener('click', () => {
            startRecording('global', globalShortcutInput, setGlobalShortcutBtn);
        });
 
        saveConfigBtn.addEventListener('click', () => {
            const shortcutConfig = getShortcutConfig();
            const settings = getSettings();
            let hasChanges = false;
 
            // 检查并保存单个图片快捷键
            if (singleShortcutInput.value && singleShortcutInput.value !== '请按下快捷键组合...') {
                shortcutConfig.single.keys = Array.from(singlePressedKeys);
                hasChanges = true;
            }
 
            // 检查并保存全局快捷键
            if (globalShortcutInput.value && globalShortcutInput.value !== '请按下快捷键组合...') {
                shortcutConfig.global.keys = Array.from(globalPressedKeys);
                hasChanges = true;
            }
 
            if (hasChanges) {
                saveShortcutConfig(shortcutConfig);
 
                // 创建成功提示
                const successMessage = document.createElement('div');
                successMessage.className = 'success-message';
                successMessage.textContent = '快捷键设置已保存';
                configModal.appendChild(successMessage);
 
                // 添加过渡效果
                requestAnimationFrame(() => {
                    successMessage.classList.add('show');
                    setTimeout(() => {
                        configModal.classList.add('closing');
                        setTimeout(() => {
                            configModal.remove();
                            configModal = null;
                        }, 300);
                    }, 500);
                });
            } else {
                alert('请先设置至少一个快捷键');
            }
        });
 
        closeConfigBtn.addEventListener('click', () => {
            if (isRecording) {
                const button = currentRecordingType === 'single' ? setSingleShortcutBtn : setGlobalShortcutBtn;
                const input = currentRecordingType === 'single' ? singleShortcutInput : globalShortcutInput;
                finishRecording(input, button);
            }
            configModal.remove();
            configModal = null;
        });
 
        // 添加点击外部关闭功能
        document.addEventListener('mousedown', (e) => {
            if (configModal && !configModal.contains(e.target)) {
                closeConfigBtn.click();
            }
        });
    }
 
    // 添加用户操作标记
    function ImageState(imgElement) {
        this.element = imgElement;
        this.originalOpacity = getComputedStyle(imgElement).opacity;
        this.originalPointerEvents = getComputedStyle(imgElement).pointerEvents;
        this.isHidden = false;
        this.overlay = null;
        this.observers = new Set();
        this.lastToggleTime = 0;
        this.userManuallyShown = false;
        this.toggleDebounceDelay = 300;
        this.isProcessing = false;
    }
 
    ImageState.prototype.cleanup = function() {
        this.observers.forEach(observer => observer.disconnect());
        this.observers.clear();
        if (this.overlay) {
            this.overlay.cleanup?.();
            this.overlay.remove();
            this.overlay = null;
        }
    };
 
    // 优化覆盖层创建
    function createOverlay(imgElement) {
        if (!imgElement || !imgElement.parentNode) return null;

        const overlay = document.createElement('div');
        const state = imageStates.get(imgElement.dataset.imageId);
        if (!state) return null;

        const updatePosition = throttle(() => {
            if (!imgElement.parentNode) {
                overlay.remove();
                return;
            }

            const rect = imgElement.getBoundingClientRect();
            if (rect.width === 0 || rect.height === 0) return;

            Object.assign(overlay.style, {
                position: 'absolute',
                left: `${rect.left + window.scrollX}px`,
                top: `${rect.top + window.scrollY}px`,
                width: `${rect.width}px`,
                height: `${rect.height}px`,
                backgroundColor: 'transparent',
                pointerEvents: 'auto',
                zIndex: '9999'
            });
        }, 16);

        updatePosition();
        overlay.dataset.linkedImage = imgElement.dataset.imageId;

        const intersectionObserver = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    updatePosition();
                }
            });
        }, {
            threshold: [0, 1]
        });

        intersectionObserver.observe(imgElement);
        state.observers.add(intersectionObserver);

        const resizeObserver = new ResizeObserver(updatePosition);
        resizeObserver.observe(imgElement);
        state.observers.add(resizeObserver);

        const scrollHandler = () => requestAnimationFrame(updatePosition);
        window.addEventListener('scroll', scrollHandler, { passive: true });

        overlay.addEventListener('mouseover', () => currentHoverTarget = imgElement);
        overlay.addEventListener('mouseout', () => currentHoverTarget = null);

        overlay.cleanup = () => {
            window.removeEventListener('scroll', scrollHandler);
            intersectionObserver.disconnect();
            resizeObserver.disconnect();
        };

        document.body.appendChild(overlay);
        return overlay;
    }
 
    // 修改 toggleImageVisibility 函数
    function toggleImageVisibility(imgElement, forceHide = false, isAutoHide = false) {
        if (!imgElement || !imgElement.parentNode) return;

        if (!imgElement.dataset.imageId) {
            imgElement.dataset.imageId = `img_${++globalImageCounter}`;
            imageStates.set(imgElement.dataset.imageId, new ImageState(imgElement));
        }

        const state = imageStates.get(imgElement.dataset.imageId);
        if (!state) return;

        const currentTime = Date.now();
        if (currentTime - state.lastToggleTime < state.toggleDebounceDelay || state.isProcessing) {
            return;
        }

        state.isProcessing = true;
        state.lastToggleTime = currentTime;

        if (isAutoHide && state.userManuallyShown) {
            state.isProcessing = false;
            return;
        }

        if (!isAutoHide) {
            state.userManuallyShown = !state.isHidden;
        }

        const shouldHide = forceHide || !state.isHidden;

        try {
            requestAnimationFrame(() => {
                if (shouldHide) {
                    if (!state.overlay) {
                        state.overlay = createOverlay(imgElement);
                    }
                    imgElement.style.cssText = `
                        opacity: 0 !important;
                        pointer-events: none !important;
                        transition: opacity 0.2s ease !important;
                    `;
                } else {
                    imgElement.style.cssText = `
                        opacity: ${state.originalOpacity || '1'} !important;
                        pointer-events: ${state.originalPointerEvents || 'auto'} !important;
                        transition: opacity 0.2s ease !important;
                    `;
                    state.cleanup();
                }
                state.isHidden = shouldHide;
                
                setTimeout(() => {
                    state.isProcessing = false;
                    
                    if (!shouldHide && parseFloat(getComputedStyle(imgElement).opacity) === 0) {
                        imgElement.style.cssText = `
                            opacity: ${state.originalOpacity || '1'} !important;
                            pointer-events: ${state.originalPointerEvents || 'auto'} !important;
                        `;
                    }
                }, 250);
            });
        } catch (error) {
            console.error('Toggle image visibility error:', error);
            state.isProcessing = false;
        }
    }
 
    // 添加节流函数
    function throttle(func, limit) {
        let inThrottle;
        return function(...args) {
            if (!inThrottle) {
                func.apply(this, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        }
    }
 
    // 键盘按下事件
    function handleKeyDown(event) {
        currentPressedKeys.add(event.code);
        checkShortcut();
    }
 
    // 键盘抬起事件
    function handleKeyUp(event) {
        currentPressedKeys.delete(event.code);
    }
 
    // 鼠标悬停处理
    function handleMouseOver(event) {
        if (event.target.tagName.toLowerCase() === 'img') {
            currentHoverTarget = event.target;
        }
    }
 
    // 鼠标移出处理
    function handleMouseOut(event) {
        if (event.target.tagName.toLowerCase() === 'img') {
            currentHoverTarget = null;
        }
    }
 
    // 重置状态的函数
    function resetState() {
        currentPressedKeys.clear();
        currentHoverTarget = null;
    }
 
    // 注册事件监听
    document.addEventListener('mouseover', handleMouseOver);
    document.addEventListener('mouseout', handleMouseOut);
    document.addEventListener('keydown', handleKeyDown);
    document.addEventListener('keyup', handleKeyUp);
 
    // 页面刷新/切换时重置按键状态
    window.addEventListener('beforeunload', resetState);
 
    // 注册菜单命令
    GM_registerMenuCommand('配置快捷键', createConfigModal);
 
    // 增加鼠标事件处理函数
    function handleMouseDown(event) {
        if (event.button === 1) {
            event.preventDefault();
            currentPressedKeys.add('MouseMiddle');
            checkShortcut();
        }
    }
 
    function handleMouseUp(event) {
        if (event.button === 1) {
            currentPressedKeys.delete('MouseMiddle');
        }
    }
 
    // 检查快捷键组合是否匹配
    function checkShortcut() {
        const shortcutConfig = getShortcutConfig();
 
        // 检查单个图片快捷键
        if (isShortcutMatch(shortcutConfig.single) &&
            currentHoverTarget &&
            currentHoverTarget.tagName.toLowerCase() === 'img') {
            toggleImageVisibility(currentHoverTarget);
        }
 
        // 检查全局快捷键
        if (isShortcutMatch(shortcutConfig.global)) {
            toggleAllImages();
        }
    }
 
    // 在主函数中添加鼠标事件监听
    document.addEventListener('mousedown', handleMouseDown);
    document.addEventListener('mouseup', handleMouseUp);
 
    // 修改页面加载事件监听
    document.addEventListener('DOMContentLoaded', initAutoHide);
    if (document.readyState !== 'loading') {
        initAutoHide();
    }
})();