您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Change Torn's background with predefined themes and custom colors
// ==UserScript== // @name Torn.com Background Theme Editor // @namespace http://tampermonkey.net/ // @version 1.5 // @description Change Torn's background with predefined themes and custom colors // @author TR0LL [2561502] // @match https://www.torn.com/* // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @license Proprietary // ==/UserScript== (function() { "use strict"; const CONFIG = { defaultBgColor: "#191919", darkModeBgColor: "#242424", selectorContentContainer: ".content.responsive-sidebar-container.logged-in", themes: { pureBlack: { name: "Pure Black", color: "#000000" }, midnightBlue: { name: "Midnight Blue", color: "#1a2a42" }, princess: { name: "Princess", color: "#c80e71" }, custom: { name: "Custom", color: null } } }; const state = { bgColor: GM_getValue("bgColor", "#191919"), currentTheme: GM_getValue("currentTheme", null), isObserving: false, isPanelVisible: false }; const domCache = { contentContainer: null, bodyElement: null }; function getContentContainer() { return domCache.contentContainer || (domCache.contentContainer = document.querySelector(CONFIG.selectorContentContainer)); } function getBodyElement() { return domCache.bodyElement || (domCache.bodyElement = document.getElementById('body') || document.body); } function throttle(func, delay) { let lastCall = 0; return function(...args) { const now = Date.now(); if (now - lastCall >= delay) { lastCall = now; func.apply(this, args); } }; } function isDarkModeActive() { const bodyElement = getBodyElement(); return bodyElement && bodyElement.classList.contains('dark-mode'); } function getAutoDetectedColor() { return isDarkModeActive() ? CONFIG.darkModeBgColor : CONFIG.defaultBgColor; } function applyBackgroundColor(color) { const contentContainer = getContentContainer(); if (contentContainer) { contentContainer.style.backgroundColor = color; return true; } return false; } function saveBackgroundColor(color, themeName = null) { if (!/^#[0-9A-F]{6}$/i.test(color)) return false; state.bgColor = color; GM_setValue("bgColor", color); if (themeName !== undefined) { state.currentTheme = themeName; GM_setValue("currentTheme", themeName); } return applyBackgroundColor(color); } function getCurrentThemeColor() { if (state.currentTheme === "custom") { return state.bgColor; } else if (state.currentTheme && CONFIG.themes[state.currentTheme]) { return CONFIG.themes[state.currentTheme].color; } else { return getAutoDetectedColor(); } } const observer = new MutationObserver((mutations) => { const shouldReapply = mutations.some(mutation => (mutation.type === 'childList' && mutation.addedNodes.length > 0) || (mutation.type === 'attributes' && (mutation.attributeName === 'style' || mutation.attributeName === 'class')) ); if (shouldReapply && state.currentTheme) { applyBackgroundColor(getCurrentThemeColor()); } }); function startObserving() { if (state.isObserving) return; const contentContainer = getContentContainer(); if (contentContainer) { observer.observe(contentContainer, { attributes: true, attributeFilter: ['style', 'class'], childList: true, subtree: false }); const bodyElement = getBodyElement(); if (bodyElement) { observer.observe(bodyElement, { attributes: true, attributeFilter: ['class'], subtree: false }); } state.isObserving = true; } } function createUI() { addStyles(); const toggleButton = document.createElement("div"); toggleButton.className = "bg-theme-toggle"; toggleButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>`; document.body.appendChild(toggleButton); const panel = document.createElement("div"); panel.id = "bg-theme-panel"; panel.className = "bg-theme-panel"; let panelHTML = ` <div class="bg-theme-header"> <span>Background Theme</span> <span class="bg-theme-close">×</span> </div> <div class="bg-theme-content"> <div class="bg-theme-group"> <label for="bg-theme-select">Theme:</label> <select id="bg-theme-select" class="bg-theme-select">`; Object.keys(CONFIG.themes).forEach(themeKey => { const selected = themeKey === state.currentTheme ? 'selected' : ''; panelHTML += `<option value="${themeKey}" ${selected}>${CONFIG.themes[themeKey].name}</option>`; }); panelHTML += ` </select> </div> <div id="custom-color-group" class="bg-theme-group" style="display: ${state.currentTheme === 'custom' ? 'block' : 'none'}"> <label for="bg-theme-color">Custom Color:</label> <div class="bg-theme-color-preview" id="color-preview"></div> <div class="bg-theme-color-inputs"> <input type="color" id="bg-theme-color-picker" value="${state.bgColor}"> <input type="text" id="bg-theme-hex" value="${state.bgColor}" placeholder="#RRGGBB"> </div> </div> <div class="bg-theme-buttons"> <button id="bg-theme-reset" class="bg-theme-button">Reset to Default</button> <button id="bg-theme-save" class="bg-theme-button bg-theme-save">Save</button> </div> <div id="bg-theme-save-indicator" class="bg-theme-save-indicator">Saved!</div> <div class="bg-theme-credit">TR0LL [2561502]</div> </div> `; panel.innerHTML = panelHTML; document.body.appendChild(panel); const themeSelect = document.getElementById('bg-theme-select'); const colorGroup = document.getElementById('custom-color-group'); const colorPreview = document.getElementById('color-preview'); const colorPicker = document.getElementById('bg-theme-color-picker'); const hexInput = document.getElementById('bg-theme-hex'); const resetButton = document.getElementById('bg-theme-reset'); const saveButton = document.getElementById('bg-theme-save'); const saveIndicator = document.getElementById('bg-theme-save-indicator'); colorPreview.style.backgroundColor = state.bgColor; toggleButton.addEventListener('click', () => { state.isPanelVisible = !state.isPanelVisible; panel.classList.toggle('visible', state.isPanelVisible); }); panel.querySelector('.bg-theme-close').addEventListener('click', () => { state.isPanelVisible = false; panel.classList.remove('visible'); }); themeSelect.addEventListener('change', function() { const selectedTheme = this.value; state.currentTheme = selectedTheme; colorGroup.style.display = selectedTheme === 'custom' ? 'block' : 'none'; if (selectedTheme === 'custom') { colorPicker.value = state.bgColor; hexInput.value = state.bgColor; colorPreview.style.backgroundColor = state.bgColor; applyBackgroundColor(state.bgColor); } else if (selectedTheme && CONFIG.themes[selectedTheme]) { const themeColor = CONFIG.themes[selectedTheme].color; colorPicker.value = themeColor; hexInput.value = themeColor; colorPreview.style.backgroundColor = themeColor; applyBackgroundColor(themeColor); } }); const throttledColorApply = throttle((newColor) => { state.bgColor = newColor; hexInput.value = newColor; colorPreview.style.backgroundColor = newColor; applyBackgroundColor(newColor); }, 50); colorPicker.addEventListener('input', function() { throttledColorApply(this.value); }); colorPicker.addEventListener('change', function() { const newColor = this.value; state.bgColor = newColor; hexInput.value = newColor; colorPreview.style.backgroundColor = newColor; applyBackgroundColor(newColor); }); hexInput.addEventListener('input', function() { let value = this.value; if (!value.startsWith('#') && value.length > 0) { value = '#' + value; this.value = value; } if (/^#[0-9A-Fa-f]{6}$/i.test(value)) { colorPicker.value = value; colorPreview.style.backgroundColor = value; state.bgColor = value; applyBackgroundColor(value); } }); resetButton.addEventListener('click', () => { applyBackgroundColor(''); state.currentTheme = null; GM_setValue("currentTheme", null); const themeSelect = document.getElementById('bg-theme-select'); if (themeSelect) { themeSelect.selectedIndex = -1; } const colorGroup = document.getElementById('custom-color-group'); if (colorGroup) { colorGroup.style.display = 'none'; } const saveIndicator = document.getElementById('bg-theme-save-indicator'); if (saveIndicator) { saveIndicator.textContent = "Reset! Using default background."; saveIndicator.classList.add('visible'); setTimeout(() => { saveIndicator.textContent = "Saved!"; saveIndicator.classList.remove('visible'); }, 2000); } }); saveButton.addEventListener('click', () => { if (state.currentTheme === 'custom') { saveBackgroundColor(colorPicker.value, 'custom'); } else if (state.currentTheme && CONFIG.themes[state.currentTheme]) { saveBackgroundColor(CONFIG.themes[state.currentTheme].color, state.currentTheme); } saveIndicator.classList.add('visible'); setTimeout(() => { saveIndicator.classList.remove('visible'); }, 2000); state.isPanelVisible = false; panel.classList.remove('visible'); }); return panel; } function addStyles() { const styleElement = document.createElement('style'); styleElement.textContent = `.bg-theme-toggle{position:fixed;right:10px;top:100px;width:32px;height:32px;background-color:#333;border-radius:50%;color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:9998;box-shadow:0 2px 5px rgba(0,0,0,.3);transition:transform .2s}.bg-theme-toggle:hover{transform:scale(1.1)}.bg-theme-panel{position:fixed;right:-250px;top:100px;width:220px;background-color:#222;border-radius:5px;z-index:9999;box-shadow:0 4px 10px rgba(0,0,0,.3);color:#eee;font-family:Arial,sans-serif;font-size:13px;transition:right .3s ease}.bg-theme-panel.visible{right:10px}.bg-theme-header{display:flex;justify-content:space-between;align-items:center;padding:10px 15px;border-bottom:1px solid #444;font-weight:700}.bg-theme-close{cursor:pointer;font-size:20px;width:20px;height:20px;line-height:20px;text-align:center}.bg-theme-close:hover{color:#f44}.bg-theme-content{padding:15px}.bg-theme-group{margin-bottom:15px}.bg-theme-group label{display:block;margin-bottom:5px;font-weight:700;color:#ccc}.bg-theme-select{width:100%;padding:7px;background-color:#333;border:1px solid #444;color:#eee;border-radius:3px}.bg-theme-color-preview{height:25px;width:100%;margin-bottom:8px;border:1px solid #444;border-radius:3px}.bg-theme-color-inputs{display:flex;gap:8px}#bg-theme-color-picker{width:40px;height:30px;padding:0;border:1px solid #444;cursor:pointer}#bg-theme-hex{flex:1;padding:6px 8px;background-color:#333;border:1px solid #444;color:#eee;border-radius:3px;font-family:monospace}.bg-theme-buttons{display:flex;gap:10px;margin-top:15px}.bg-theme-button{flex:1;padding:8px 0;background-color:#444;border:none;border-radius:3px;color:#eee;font-weight:700;cursor:pointer;transition:background-color .2s}.bg-theme-button:hover{background-color:#555}.bg-theme-save{background-color:#4caf50}.bg-theme-save:hover{background-color:#3e8e41}.bg-theme-save-indicator{text-align:center;margin-top:10px;color:#4caf50;opacity:0;transition:opacity .3s;font-weight:700}.bg-theme-save-indicator.visible{opacity:1}.bg-theme-credit{margin-top:10px;text-align:center;font-size:11px;color:#777}@media (max-width:768px){.bg-theme-toggle{width:28px;height:28px;right:5px;top:70px}.bg-theme-panel{width:190px}.bg-theme-panel.visible{right:5px}}`; document.head.appendChild(styleElement); } function init() { if (state.currentTheme) { const currentColor = getCurrentThemeColor(); if (!applyBackgroundColor(currentColor)) { window.addEventListener("DOMContentLoaded", () => { applyBackgroundColor(getCurrentThemeColor()); startObserving(); }); } else { startObserving(); } } else { startObserving(); } const currentUrl = window.location.href; if (currentUrl.includes("/preferences.php") || currentUrl.includes("/profiles.php?XID=")) { if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", createUI); } else { createUI(); } } } init(); })();