🖼️🌄 Chess.com Background

🎨 Personalize o fundo do Chess.com com Imagens e Videos! 🖼️ Use vídeos e imagens personalizados, crie cenários incríveis e deixe seu xadrez com a sua identidade. 🚀✨

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

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

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

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

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

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

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

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

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

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

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

// ==UserScript==
// @name         🖼️🌄 Chess.com Background
// @namespace    http://tampermonkey.net/
// @version      7.7
// @description  🎨 Personalize o fundo do Chess.com com Imagens e Videos! 🖼️ Use vídeos e imagens personalizados, crie cenários incríveis e deixe seu xadrez com a sua identidade. 🚀✨
// @author       aerus15
// @match        *://*.chess.com/*
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript====

(function() {
    'use strict';

    const DB_NAME = 'ChessBgDB';
    const STORE_NAME = 'bgStore';

    function initDB() {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(DB_NAME, 1);
            request.onupgradeneeded = (e) => {
                const db = e.target.result;
                if (!db.objectStoreNames.contains(STORE_NAME)) {
                    db.createObjectStore(STORE_NAME);
                }
            };
            request.onsuccess = () => resolve(request.result);
            request.onerror = (e) => reject(e);
        });
    }

    async function saveImageToDB(file) {
        const db = await initDB();
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, 'readwrite');
            const store = tx.objectStore(STORE_NAME);
            const request = store.put(file, 'current_bg_image');
            request.onsuccess = () => resolve();
            request.onerror = (e) => reject(e);
        });
    }

    async function loadImageFromDB() {
        const db = await initDB();
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, 'readonly');
            const store = tx.objectStore(STORE_NAME);
            const request = store.get('current_bg_image');
            request.onsuccess = () => resolve(request.result);
            request.onerror = (e) => reject(e);
        });
    }

    const css = `
        .board-layout-sidebar,
        #board-layout-sidebar,
        .play-controller-sidebar,
        .computer-sidebar-component,
        .analysis-sidebar-component,
        .live-game-sidebar-component,
        .sidebar-component,
        [data-test-id="sidebar"] {
            display: none !important;
            width: 0 !important;
            visibility: hidden !important;
            opacity: 0 !important;
            pointer-events: none !important;
        }

        body.reveal-chess-ui .board-layout-sidebar,
        body.reveal-chess-ui #board-layout-sidebar,
        body.reveal-chess-ui .play-controller-sidebar,
        body.reveal-chess-ui .computer-sidebar-component,
        body.reveal-chess-ui .analysis-sidebar-component,
        body.reveal-chess-ui .live-game-sidebar-component,
        body.reveal-chess-ui .sidebar-component,
        body.reveal-chess-ui [data-test-id="sidebar"],
        body.reveal-chess-ui .layout-right,
        body.reveal-chess-ui [data-cy="analysis-panel"],
        body.reveal-chess-ui .game-overview,
        body.reveal-chess-ui .vertical-move-list,
        body.reveal-chess-ui .analysis-tools {
            display: flex !important;
            width: clamp(250px, 30vw, 350px) !important;
            min-width: 300px !important;
            max-width: 400px !important;
            visibility: visible !important;
            opacity: 1 !important;
            pointer-events: auto !important;
            background: rgba(30, 30, 30, 0.95) !important;
            backdrop-filter: blur(8px) !important;
            z-index: 2147483647 !important;
            position: fixed !important;
            right: 0 !important;
            top: 0 !important;
            bottom: 0 !important;
            height: 100vh !important;
            overflow-y: auto !important;
            box-shadow: -5px 0 20px rgba(0,0,0,0.8) !important;
            transform: none !important;
            clip: auto !important;
            clip-path: none !important;
            margin: 0 !important;
            padding: 0 !important;
        }

        .board-layout-main {
            margin: 0 auto !important;
        }

        body,
        html,
        #sb,
        .v5-section-content-wrapper,
        .v-board-wrapper,
        .layout-board,
        .layout-main,
        .board-layout {
            background: transparent !important;
            background-color: transparent !important;
            background-image: none !important;
        }

        #custom-bg-video,
        #custom-bg-img {
            position: fixed !important;
            top: 0 !important;
            left: 0 !important;
            width: 100vw !important;
            height: 100vh !important;
            object-fit: var(--bg-fit, cover) !important;
            filter: brightness(var(--bg-brightness, 100%)) contrast(var(--bg-contrast, 100%)) saturate(var(--bg-saturate, 100%)) hue-rotate(var(--bg-hue, 0deg)) !important;
            z-index: -9999 !important;
            pointer-events: none !important;
            transform: translateZ(0) !important;
            backface-visibility: hidden !important;
            will-change: transform !important;
            opacity: 0.85 !important;
            image-rendering: auto !important;
            display: none !important;
        }

        #custom-bg-video.active,
        #custom-bg-img.active {
            display: block !important;
        }

        #bg-main-toggle {
            position: fixed;
            left: 15px;
            bottom: 220px;
            z-index: 100000;
            background: rgba(0,0,0,0.6);
            color: white;
            border: 1px solid rgba(255,255,255,0.2);
            border-radius: 50%;
            width: 36px;
            height: 36px;
            cursor: pointer;
            font-size: 18px;
            display: flex;
            justify-content: center;
            align-items: center;
            box-shadow: 0 4px 10px rgba(0,0,0,0.5);
            transition: 0.3s;
        }

        #bg-main-toggle:hover {
            background: rgba(0,0,0,0.9);
            transform: scale(1.1);
        }

        #bg-main-menu {
            position: fixed;
            left: 15px;
            bottom: 265px;
            z-index: 99999;
            background: rgba(0,0,0,0.85);
            padding: 12px;
            border-radius: 8px;
            border: 1px solid rgba(255,255,255,0.2);
            display: none;
            flex-direction: column;
            gap: 10px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
            backdrop-filter: blur(5px);
            width: 170px;
        }

        #bg-main-menu.open {
            display: flex;
        }

        .bg-menu-btn {
            background: rgba(0,0,0,0.5);
            color: white;
            border: 1px solid rgba(255,255,255,0.2);
            padding: 8px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 12px;
            transition: 0.2s;
            text-align: center;
            width: 100%;
            box-sizing: border-box;
        }

        .bg-menu-btn:hover {
            background: rgba(255,255,255,0.2);
            transform: scale(1.03);
        }

        #bg-auto-prompt {
            width: 100%;
            background: rgba(0,0,0,0.6);
            color: white;
            border: 1px solid rgba(255,255,255,0.3);
            padding: 8px;
            border-radius: 6px;
            font-size: 12px;
            box-sizing: border-box;
            outline: none;
            text-align: center;
        }

        #bg-auto-prompt::placeholder {
            color: rgba(255,255,255,0.6);
        }

        #bg-auto-img-btn { font-weight: bold; color: #4CAF50; border-color: #4CAF50; }
        #bg-save-mural-btn { font-weight: bold; color: #FFD700; border-color: #FFD700; }
        #bg-mural-btn { font-weight: bold; color: #00BCD4; border-color: #00BCD4; }
        #bg-settings-btn { font-weight: bold; color: #FF9800; border-color: #FF9800; }

        .bg-menu-divider {
            height: 1px;
            background: rgba(255,255,255,0.2);
            margin: 2px 0;
            width: 100%;
        }

        #bg-settings-panel,
        #bg-mural-panel {
            position: fixed;
            left: 200px;
            bottom: 265px;
            background: rgba(0,0,0,0.95);
            color: white;
            padding: 15px;
            border-radius: 8px;
            border: 1px solid rgba(255,255,255,0.2);
            z-index: 99999;
            display: none;
            flex-direction: column;
            gap: 12px;
            font-family: sans-serif;
            font-size: 13px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
            backdrop-filter: blur(5px);
        }

        #bg-settings-panel { width: 220px; }
        #bg-mural-panel { width: 320px; max-height: 400px; overflow-y: auto; }

        #bg-settings-panel.open,
        #bg-mural-panel.open {
            display: flex;
        }

        #bg-settings-panel label {
            display: flex;
            justify-content: space-between;
            align-items: center;
            cursor: pointer;
        }

        #bg-settings-panel input[type="range"] { width: 120px; cursor: pointer; }
        #bg-settings-panel input[type="checkbox"] { cursor: pointer; width: 16px; height: 16px; }

        #bg-setting-reset {
            margin-top: 5px;
            background: #444;
            color: white;
            border: 1px solid rgba(255,255,255,0.2);
            padding: 8px;
            border-radius: 4px;
            cursor: pointer;
            transition: 0.2s;
            font-weight: bold;
        }

        #bg-setting-reset:hover { background: #555; }

        .mural-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
        }

        .mural-item {
            position: relative;
            border: 1px solid rgba(255,255,255,0.2);
            border-radius: 4px;
            overflow: hidden;
            background: #111;
            display: flex;
            flex-direction: column;
        }

        .mural-item img {
            width: 100%;
            height: 90px;
            object-fit: cover;
            cursor: pointer;
            transition: 0.2s;
        }

        .mural-item img:hover { transform: scale(1.05); }

        .mural-item-actions {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 6px 8px;
            background: rgba(0, 0, 0, 0.9);
            position: absolute;
            bottom: 0;
            width: 100%;
            box-sizing: border-box;
        }

        .mural-item-actions a,
        .mural-item-actions button {
            color: white;
            font-size: 11px;
            text-decoration: none;
            background: none;
            border: none;
            cursor: pointer;
            padding: 0;
            font-weight: bold;
        }

        .mural-item-actions a:hover { color: #00BCD4; text-decoration: underline; }
        .mural-item-actions button { color: #ff4444; }
        .mural-item-actions button:hover { color: #ff0000; transform: scale(1.1); }
    `;

    if (typeof GM_addStyle !== "undefined") {
        GM_addStyle(css);
    } else {
        const style = document.createElement('style');
        style.textContent = css;
        document.head.appendChild(style);
    }

    const STORAGE_KEY = 'chess_video_url_stream';
    const STORAGE_TYPE_KEY = 'chess_video_type';
    const PROMPT_KEY = 'chess_auto_prompt';
    const SEEDS_KEY = 'chess_used_seeds';
    const AI_MODE_KEY = 'chess_ai_mode';

    function optimizeVideo(video) {
        video.autoplay = true;
        video.loop = true;
        video.muted = true;
        video.playsInline = true;
        video.preload = "metadata";
        video.disablePictureInPicture = true;
        video.setAttribute('webkit-playsinline', 'true');
        video.style.contain = 'strict';
        video.playbackRate = 1.0;

        video.addEventListener('loadeddata', () => {
            video.play().catch(() => {});
        });

        video.addEventListener('canplay', () => {
            video.play().catch(() => {});
        });

        video.addEventListener('stalled', () => {});
        video.addEventListener('error', (e) => {});

        const attemptPlay = () => {
            const p = video.play();
            if (p !== undefined) {
                p.catch(() => {
                    setTimeout(attemptPlay, 1000);
                });
            }
        };

        attemptPlay();
    }

    function createVideoElement() {
        let video = document.getElementById('custom-bg-video');
        if (video) return video;
        video = document.createElement('video');
        video.id = 'custom-bg-video';
        optimizeVideo(video);
        document.body.appendChild(video);
        return video;
    }

    function createImageElement() {
        let img = document.getElementById('custom-bg-img');
        if (img) return img;
        img = document.createElement('img');
        img.id = 'custom-bg-img';
        img.style.contain = 'strict';
        document.body.appendChild(img);
        return img;
    }

    function setVideoURL(url) {
        const video = createVideoElement();
        const img = createImageElement();

        if (!url) return;

        img.classList.remove('active');
        video.classList.add('active');

        video.pause();
        video.src = '';
        video.removeAttribute('src');
        video.load();

        requestAnimationFrame(() => {
            video.src = url;
            video.load();

            const startPlayback = () => {
                const promise = video.play();
                if (promise !== undefined) {
                    promise.catch(() => {
                        setTimeout(startPlayback, 1000);
                    });
                }
            };

            startPlayback();
        });

        localStorage.setItem(STORAGE_KEY, url);
        localStorage.setItem(STORAGE_TYPE_KEY, 'video');
    }

    function setImageSource(url) {
        const img = createImageElement();
        const video = createVideoElement();

        video.classList.remove('active');
        video.pause();
        video.src = '';
        video.removeAttribute('src');
        video.load();

        img.src = url;
        img.classList.add('active');
    }

    function createUI() {
        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'bg-main-toggle';
        toggleBtn.innerHTML = '✦';
        toggleBtn.title = 'Menu de Fundo';

        const menu = document.createElement('div');
        menu.id = 'bg-main-menu';

        toggleBtn.addEventListener('click', () => {
            menu.classList.toggle('open');
            document.getElementById('bg-settings-panel')?.classList.remove('open');
            document.getElementById('bg-mural-panel')?.classList.remove('open');
        });

        const fileBtn = document.createElement('button');
        fileBtn.className = 'bg-menu-btn';
        fileBtn.textContent = 'Arquivo Local';

        const urlBtn = document.createElement('button');
        urlBtn.className = 'bg-menu-btn';
        urlBtn.textContent = 'URL Vídeo';

        const imgBtn = document.createElement('button');
        imgBtn.className = 'bg-menu-btn';
        imgBtn.textContent = 'Imagem URL';

        const div1 = document.createElement('div');
        div1.className = 'bg-menu-divider';

        const promptInput = document.createElement('input');
        promptInput.id = 'bg-auto-prompt';
        promptInput.type = 'text';
        promptInput.placeholder = 'Palavra chave (Ex: cars)';
        promptInput.value = localStorage.getItem(PROMPT_KEY) || '';
        promptInput.addEventListener('input', (e) => localStorage.setItem(PROMPT_KEY, e.target.value));

        const aiModeContainer = document.createElement('div');
        aiModeContainer.style.cssText = 'display:flex; align-items:center; gap:5px; color:white; font-size:12px; margin: 2px 0; justify-content:center;';
        
        const aiModeCheckbox = document.createElement('input');
        aiModeCheckbox.type = 'checkbox';
        aiModeCheckbox.id = 'bg-ai-mode';
        aiModeCheckbox.style.cssText = 'cursor:pointer; width:14px; height:14px; margin:0;';
        aiModeCheckbox.checked = localStorage.getItem(AI_MODE_KEY) === 'true';
        aiModeCheckbox.addEventListener('change', (e) => {
            localStorage.setItem(AI_MODE_KEY, e.target.checked);
        });
        
        const aiModeLabel = document.createElement('label');
        aiModeLabel.htmlFor = 'bg-ai-mode';
        aiModeLabel.textContent = 'Modo I.A (Pollinations)';
        aiModeLabel.style.cursor = 'pointer';

        aiModeContainer.appendChild(aiModeCheckbox);
        aiModeContainer.appendChild(aiModeLabel);

        const autoImgBtn = document.createElement('button');
        autoImgBtn.id = 'bg-auto-img-btn';
        autoImgBtn.className = 'bg-menu-btn';
        autoImgBtn.textContent = 'Gerar Auto Fundo';

        const input = document.createElement('input');
        input.type = 'file';
        input.accept = 'video/*';
        input.style.display = 'none';

        const inputImg = document.createElement('input');
        inputImg.type = 'file';
        inputImg.accept = 'image/*';
        inputImg.style.display = 'none';

        fileBtn.addEventListener('click', () => input.click());
        imgBtn.addEventListener('click', () => inputImg.click());

        input.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (!file) return;
            const blobURL = URL.createObjectURL(file);
            setVideoURL(blobURL);
        });

        inputImg.addEventListener('change', async (e) => {
            const file = e.target.files[0];
            if (!file) return;

            try {
                await saveImageToDB(file);
                const blobURL = URL.createObjectURL(file);
                setImageSource(blobURL);
                localStorage.setItem(STORAGE_KEY, 'indexeddb_image');
                localStorage.setItem(STORAGE_TYPE_KEY, 'image');
            } catch (error) {
                const reader = new FileReader();
                reader.onload = function(event) {
                    const result = event.target.result;
                    setImageSource(result);
                    try {
                        localStorage.setItem(STORAGE_KEY, result);
                        localStorage.setItem(STORAGE_TYPE_KEY, 'image');
                    } catch (err) {
                        const fallbackBlob = URL.createObjectURL(file);
                        setImageSource(fallbackBlob);
                        localStorage.setItem(STORAGE_KEY, fallbackBlob);
                        localStorage.setItem(STORAGE_TYPE_KEY, 'image');
                    }
                };
                reader.readAsDataURL(file);
            }
        });

        urlBtn.addEventListener('click', () => {
            const current = localStorage.getItem(STORAGE_KEY) || '';
            const url = prompt('Cole URL direta do vídeo (.mp4):', current);
            if (!url) return;
            setVideoURL(url);
        });

        let currentRequestId = 0;

        autoImgBtn.addEventListener('click', () => {
            const reqId = ++currentRequestId;
            const originalText = autoImgBtn.textContent;
            autoImgBtn.textContent = 'Carregando...';

            let usedSeeds = JSON.parse(localStorage.getItem(SEEDS_KEY) || '[]');
            let seed;
            do {
                seed = Math.floor(Math.random() * 999999999) + 1;
            } while (usedSeeds.includes(seed));

            usedSeeds.push(seed);
            if (usedSeeds.length > 1000) usedSeeds.shift();
            localStorage.setItem(SEEDS_KEY, JSON.stringify(usedSeeds));

            const promptVal = promptInput.value.trim();
            const isAiMode = aiModeCheckbox.checked;
            let url;

            if (isAiMode) {
                const finalPrompt = promptVal || 'beautiful landscape, 16:9, high resolution, masterpiece';
                url = `https://image.pollinations.ai/prompt/${encodeURIComponent(finalPrompt)}?width=1920&height=1080&nologo=true&seed=${seed}`;
            } else {
                if (promptVal) {
                    const formattedPrompt = promptVal.replace(/\s+/g, ',');
                    url = `https://loremflickr.com/1920/1080/${encodeURIComponent(formattedPrompt)}?lock=${seed}&cb=${Date.now()}`;
                } else {
                    url = `https://picsum.photos/seed/${seed}/1920/1080`;
                }
            }

            const tempImg = new Image();
            tempImg.onload = () => {
                if (reqId !== currentRequestId) return;
                setImageSource(url);
                localStorage.setItem(STORAGE_KEY, url);
                localStorage.setItem(STORAGE_TYPE_KEY, 'image');
                autoImgBtn.textContent = originalText;
            };

            tempImg.onerror = () => {
                if (reqId !== currentRequestId) return;
                autoImgBtn.textContent = 'Erro! Tentando de novo...';
                setTimeout(() => {
                    if (reqId === currentRequestId) {
                        autoImgBtn.textContent = originalText;
                        autoImgBtn.click();
                    }
                }, 1000);
            };

            tempImg.src = url;
        });

        menu.appendChild(fileBtn);
        menu.appendChild(urlBtn);
        menu.appendChild(imgBtn);
        menu.appendChild(div1);
        menu.appendChild(promptInput);
        menu.appendChild(aiModeContainer);
        menu.appendChild(autoImgBtn);

        document.body.appendChild(toggleBtn);
        document.body.appendChild(menu);
        document.body.appendChild(input);
        document.body.appendChild(inputImg);
    }

    function createMuralUI() {
        const menu = document.getElementById('bg-main-menu');
        
        const div2 = document.createElement('div');
        div2.className = 'bg-menu-divider';

        const saveMuralBtn = document.createElement('button');
        saveMuralBtn.id = 'bg-save-mural-btn';
        saveMuralBtn.className = 'bg-menu-btn';
        saveMuralBtn.textContent = 'Salvar Imagem';

        const muralBtn = document.createElement('button');
        muralBtn.id = 'bg-mural-btn';
        muralBtn.className = 'bg-menu-btn';
        muralBtn.textContent = 'Mural de Imagens';

        const muralPanel = document.createElement('div');
        muralPanel.id = 'bg-mural-panel';
        muralPanel.innerHTML = `
            <div style="font-weight:bold;margin-bottom:5px;border-bottom:1px solid rgba(255,255,255,0.2);padding-bottom:8px;text-align:center;position:relative;">
                Mural de Imagens Salvas
                <span id="close-mural" style="position:absolute;right:0;top:0;cursor:pointer;color:#ff4444;padding:0 5px;font-weight:bold;">X</span>
            </div>
            <div class="mural-grid" id="mural-grid"></div>
        `;

        menu.appendChild(div2);
        menu.appendChild(saveMuralBtn);
        menu.appendChild(muralBtn);
        document.body.appendChild(muralPanel);

        function renderMural() {
            const grid = document.getElementById('mural-grid');
            grid.innerHTML = '';
            let saved = JSON.parse(localStorage.getItem('chess_mural_images') || '[]');

            if(saved.length === 0) {
                grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#aaa;padding:20px 0;">Nenhuma imagem salva</div>';
                return;
            }

            saved.forEach((item, index) => {
                const div = document.createElement('div');
                div.className = 'mural-item';

                const isDB = (item.url === 'indexeddb_image');
                const imgSrc = isDB ? '' : item.url;

                div.innerHTML = `
                    <img src="${imgSrc}" title="Clique para aplicar como fundo">
                    <div class="mural-item-actions">
                        <a href="${isDB ? '#' : item.url}" target="_blank" title="${isDB ? 'Imagem Local (PC)' : 'Abrir imagem original para baixar'}">Fonte</a>
                        <button data-index="${index}" class="del-mural-btn" title="Remover do mural">Remover</button>
                    </div>
                `;
                grid.appendChild(div);

                const imgEl = div.querySelector('img');

                if (isDB) {
                    loadImageFromDB().then(file => {
                        if (file) {
                            const tempUrl = URL.createObjectURL(file);
                            imgEl.src = tempUrl;
                            div.querySelector('a').href = tempUrl;
                        }
                    });
                }

                imgEl.addEventListener('click', () => {
                    if (isDB) {
                        loadImageFromDB().then(file => {
                            if (file) {
                                setImageSource(URL.createObjectURL(file));
                                localStorage.setItem(STORAGE_KEY, 'indexeddb_image');
                                localStorage.setItem(STORAGE_TYPE_KEY, 'image');
                            }
                        });
                    } else {
                        setImageSource(item.url);
                        localStorage.setItem(STORAGE_KEY, item.url);
                        localStorage.setItem(STORAGE_TYPE_KEY, 'image');
                    }
                });
            });

            document.querySelectorAll('.del-mural-btn').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const idx = e.target.getAttribute('data-index');
                    let savedList = JSON.parse(localStorage.getItem('chess_mural_images') || '[]');
                    savedList.splice(idx, 1);
                    localStorage.setItem('chess_mural_images', JSON.stringify(savedList));
                    renderMural();
                });
            });
        }

        muralBtn.addEventListener('click', () => {
            renderMural();
            muralPanel.classList.toggle('open');
            const settingsPanel = document.getElementById('bg-settings-panel');
            if(settingsPanel) settingsPanel.classList.remove('open');
        });

        document.getElementById('close-mural').addEventListener('click', () => {
            muralPanel.classList.remove('open');
        });

        saveMuralBtn.addEventListener('click', () => {
            const currentUrl = localStorage.getItem(STORAGE_KEY);
            const currentType = localStorage.getItem(STORAGE_TYPE_KEY);

            if (currentType === 'image' && currentUrl) {
                let saved = JSON.parse(localStorage.getItem('chess_mural_images') || '[]');
                if (!saved.some(i => i.url === currentUrl)) {
                    saved.push({ url: currentUrl, timestamp: Date.now() });
                    localStorage.setItem('chess_mural_images', JSON.stringify(saved));

                    const originalText = saveMuralBtn.textContent;
                    saveMuralBtn.textContent = 'Salvo no Mural!';
                    saveMuralBtn.style.color = '#4CAF50';
                    saveMuralBtn.style.borderColor = '#4CAF50';

                    if (muralPanel.classList.contains('open')) renderMural();

                    setTimeout(() => {
                        saveMuralBtn.textContent = originalText;
                        saveMuralBtn.style.color = 'white';
                        saveMuralBtn.style.borderColor = 'rgba(255,255,255,0.2)';
                    }, 2000);
                } else {
                    const originalText = saveMuralBtn.textContent;
                    saveMuralBtn.textContent = 'Já está salvo!';
                    setTimeout(() => saveMuralBtn.textContent = originalText, 2000);
                }
            } else {
                const originalText = saveMuralBtn.textContent;
                saveMuralBtn.textContent = 'Apenas Imagens!';
                saveMuralBtn.style.color = 'red';
                saveMuralBtn.style.borderColor = 'red';
                setTimeout(() => {
                    saveMuralBtn.textContent = originalText;
                    saveMuralBtn.style.color = 'white';
                    saveMuralBtn.style.borderColor = 'rgba(255,255,255,0.2)';
                }, 2000);
            }
        });
    }

    function createSettingsUI() {
        const menu = document.getElementById('bg-main-menu');

        const div3 = document.createElement('div');
        div3.className = 'bg-menu-divider';

        const btn = document.createElement('button');
        btn.id = 'bg-settings-btn';
        btn.className = 'bg-menu-btn';
        btn.textContent = 'Ajustes';

        const panel = document.createElement('div');
        panel.id = 'bg-settings-panel';
        panel.innerHTML = `
            <div style="font-weight:bold;margin-bottom:5px;border-bottom:1px solid rgba(255,255,255,0.2);padding-bottom:8px;text-align:center;">Ajustes de Fundo</div>
            <label title="Estica a imagem para preencher 100% da tela sem cortar e sem bordas pretas.">
                Enquadrar Tela
                <input type="checkbox" id="bg-setting-fit" ${localStorage.getItem('chess_bg_fit') === 'fill' ? 'checked' : ''}>
            </label>
            <label>
                Brilho
                <input type="range" id="bg-setting-brightness" min="0" max="200" value="${localStorage.getItem('chess_bg_brightness') || '100'}">
            </label>
            <label>
                Contraste
                <input type="range" id="bg-setting-contrast" min="0" max="200" value="${localStorage.getItem('chess_bg_contrast') || '100'}">
            </label>
            <label>
                Saturação
                <input type="range" id="bg-setting-saturate" min="0" max="200" value="${localStorage.getItem('chess_bg_saturate') || '100'}">
            </label>
            <label>
                Matiz
                <input type="range" id="bg-setting-hue" min="0" max="360" value="${localStorage.getItem('chess_bg_hue') || '0'}">
            </label>
            <button id="bg-setting-reset">Restaurar Padrões</button>
        `;

        menu.appendChild(div3);
        menu.appendChild(btn);
        document.body.appendChild(panel);

        btn.addEventListener('click', () => {
            panel.classList.toggle('open');
            const muralPanel = document.getElementById('bg-mural-panel');
            if (muralPanel) muralPanel.classList.remove('open');
        });

        const fitInput = document.getElementById('bg-setting-fit');
        const brightInput = document.getElementById('bg-setting-brightness');
        const contrastInput = document.getElementById('bg-setting-contrast');
        const saturateInput = document.getElementById('bg-setting-saturate');
        const hueInput = document.getElementById('bg-setting-hue');
        const resetBtn = document.getElementById('bg-setting-reset');

        function applyFilters() {
            const root = document.documentElement;
            root.style.setProperty('--bg-fit', localStorage.getItem('chess_bg_fit') || 'cover');
            root.style.setProperty('--bg-brightness', (localStorage.getItem('chess_bg_brightness') || '100') + '%');
            root.style.setProperty('--bg-contrast', (localStorage.getItem('chess_bg_contrast') || '100') + '%');
            root.style.setProperty('--bg-saturate', (localStorage.getItem('chess_bg_saturate') || '100') + '%');
            root.style.setProperty('--bg-hue', (localStorage.getItem('chess_bg_hue') || '0') + 'deg');
        }

        fitInput.addEventListener('change', (e) => {
            localStorage.setItem('chess_bg_fit', e.target.checked ? 'fill' : 'cover');
            applyFilters();
        });

        const updateFilters = () => {
            localStorage.setItem('chess_bg_brightness', brightInput.value);
            localStorage.setItem('chess_bg_contrast', contrastInput.value);
            localStorage.setItem('chess_bg_saturate', saturateInput.value);
            localStorage.setItem('chess_bg_hue', hueInput.value);
            applyFilters();
        };

        brightInput.addEventListener('input', updateFilters);
        contrastInput.addEventListener('input', updateFilters);
        saturateInput.addEventListener('input', updateFilters);
        hueInput.addEventListener('input', updateFilters);

        resetBtn.addEventListener('click', () => {
            fitInput.checked = false;
            brightInput.value = 100;
            contrastInput.value = 100;
            saturateInput.value = 100;
            hueInput.value = 0;

            localStorage.setItem('chess_bg_fit', 'cover');
            updateFilters();
        });

        applyFilters();
    }

    function restoreSavedVideo() {
        const saved = localStorage.getItem(STORAGE_KEY);
        const type = localStorage.getItem(STORAGE_TYPE_KEY) || 'video';

        if (saved) {
            if (type === 'image') {
                if (saved === 'indexeddb_image') {
                    loadImageFromDB().then(file => {
                        if (file) {
                            setImageSource(URL.createObjectURL(file));
                        }
                    }).catch(e => console.error(e));
                } else {
                    if (saved.startsWith('blob:')) return;
                    setImageSource(saved);
                }
            } else {
                setVideoURL(saved);
            }
        }
    }

    function setupRevealHotkey() {
        let isIPressed = false;
        let revealInterval = null;

        const forceShow = () => {
            const els = document.querySelectorAll('.board-layout-sidebar, #board-layout-sidebar, .play-controller-sidebar, .computer-sidebar-component, .analysis-sidebar-component, .live-game-sidebar-component, .sidebar-component, [data-test-id="sidebar"], .layout-right, .game-overview, .vertical-move-list, [data-cy="analysis-panel"], .analysis-tools');

            els.forEach(el => {
                let parent = el.parentElement;
                while (parent && parent.tagName !== 'BODY' && parent.tagName !== 'HTML') {
                    if (parent.dataset.forcedVisibleByGemini !== 'true') {
                        const style = window.getComputedStyle(parent);
                        if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0' || style.transform !== 'none') {
                            parent.style.setProperty('display', 'block', 'important');
                            parent.style.setProperty('visibility', 'visible', 'important');
                            parent.style.setProperty('opacity', '1', 'important');
                            parent.style.setProperty('transform', 'none', 'important');
                            parent.dataset.forcedVisibleByGemini = 'true';
                        }
                    }
                    parent = parent.parentElement;
                }

                el.style.setProperty('display', 'flex', 'important');
                el.style.setProperty('visibility', 'visible', 'important');
                el.style.setProperty('opacity', '1', 'important');
                el.style.setProperty('pointer-events', 'auto', 'important');
                el.style.setProperty('z-index', '2147483647', 'important');
                el.style.setProperty('position', 'fixed', 'important');
                el.style.setProperty('right', '0', 'important');
                el.style.setProperty('top', '0', 'important');
                el.style.setProperty('bottom', '0', 'important');
                el.style.setProperty('height', '100vh', 'important');
                el.style.setProperty('width', 'clamp(250px, 30vw, 350px)', 'important');
                el.style.setProperty('min-width', '300px', 'important');
                el.style.setProperty('max-width', '400px', 'important');
                el.style.setProperty('transform', 'none', 'important');
                el.style.setProperty('clip', 'auto', 'important');
                el.style.setProperty('clip-path', 'none', 'important');
                el.style.setProperty('margin', '0', 'important');
                el.style.setProperty('padding', '0', 'important');
                el.style.setProperty('background', 'rgba(30, 30, 30, 0.95)', 'important');
            });
        };

        const forceHide = () => {
            const els = document.querySelectorAll('.board-layout-sidebar, #board-layout-sidebar, .play-controller-sidebar, .computer-sidebar-component, .analysis-sidebar-component, .live-game-sidebar-component, .sidebar-component, [data-test-id="sidebar"], .layout-right, .game-overview, .vertical-move-list, [data-cy="analysis-panel"], .analysis-tools');

            els.forEach(el => {
                let parent = el.parentElement;
                while (parent && parent.tagName !== 'BODY' && parent.tagName !== 'HTML') {
                    if (parent.dataset.forcedVisibleByGemini === 'true') {
                        parent.style.removeProperty('display');
                        parent.style.removeProperty('visibility');
                        parent.style.removeProperty('opacity');
                        parent.style.removeProperty('transform');
                        delete parent.dataset.forcedVisibleByGemini;
                    }
                    parent = parent.parentElement;
                }

                el.style.removeProperty('display');
                el.style.removeProperty('visibility');
                el.style.removeProperty('opacity');
                el.style.removeProperty('pointer-events');
                el.style.removeProperty('z-index');
                el.style.removeProperty('position');
                el.style.removeProperty('right');
                el.style.removeProperty('top');
                el.style.removeProperty('bottom');
                el.style.removeProperty('height');
                el.style.removeProperty('width');
                el.style.removeProperty('min-width');
                el.style.removeProperty('max-width');
                el.style.removeProperty('transform');
                el.style.removeProperty('clip');
                el.style.removeProperty('clip-path');
                el.style.removeProperty('margin');
                el.style.removeProperty('padding');
                el.style.removeProperty('background');
            });
        };

        document.addEventListener('keydown', (e) => {
            if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) {
                return;
            }

            if ((e.key === 'i' || e.key === 'I') && !isIPressed) {
                isIPressed = true;
                document.body.classList.add('reveal-chess-ui');
                forceShow();
                revealInterval = setInterval(forceShow, 50);
            }
        });

        document.addEventListener('keyup', (e) => {
            if (e.key === 'i' || e.key === 'I') {
                isIPressed = false;
                document.body.classList.remove('reveal-chess-ui');
                if (revealInterval) {
                    clearInterval(revealInterval);
                    revealInterval = null;
                }
                forceHide();
            }
        });
    }

    function init() {
        createVideoElement();
        createImageElement();
        createUI();
        createMuralUI();
        createSettingsUI();
        restoreSavedVideo();
        setupRevealHotkey();
    }

    if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();