您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
命运2工具网站 light.gg 的增强脚本,将物品名显示为双语,并可选择性设置tooltip语言。
// ==UserScript== // @name Light.gg Bilingual Display Tool // @version 3.0 // @description 命运2工具网站 light.gg 的增强脚本,将物品名显示为双语,并可选择性设置tooltip语言。 // @author Eliver // @match https://www.light.gg/* // @grant GM_setValue // @grant GM_getValue // @license MIT // @namespace https://greasyfork.org/users/1267935 // ==/UserScript== (function () { 'use strict'; const CACHE_KEY = 'lightgg_item_list'; const LAST_UPDATE_KEY = 'lightgg_last_update'; const TOOLTIP_LANG_SETTING_KEY = 'lightgg_tooltip_lang_setting'; const ITEM_LIST_URL = 'https://20xiji.github.io/Destiny-item-list/item-list-8-2-0.json'; let setTooltipLang = GM_getValue(TOOLTIP_LANG_SETTING_KEY, true); let originalLang; // 性能优化:缓存和查找映射 let cachedItemList = null; let itemLookupMap = new Map(); let processedElements = new WeakSet(); let isDataReady = false; // 性能优化:节流函数替代防抖 function throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } // 构建O(1)查找的映射表 function buildLookupMap(itemList) { itemLookupMap.clear(); Object.keys(itemList).forEach(key => { const item = itemList[key]; if (item.en) { itemLookupMap.set(item.en.toLowerCase(), { key, item }); } if (item['zh-chs']) { itemLookupMap.set(item['zh-chs'].toLowerCase(), { key, item }); } }); console.log(`构建查找映射表完成,包含 ${itemLookupMap.size} 个条目`); } // 创建通知系统 function createNotification(message, type = 'info', duration = 3000) { const notification = document.createElement('div'); notification.className = 'lightgg-notification'; notification.textContent = message; const colors = { success: '#4CAF50', error: '#f44336', info: '#2196F3', warning: '#ff9800' }; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: ${colors[type]}; color: white; padding: 12px 20px; border-radius: 8px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; font-weight: 500; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000; transform: translateX(100%); transition: transform 0.3s ease; max-width: 300px; word-wrap: break-word; `; document.body.appendChild(notification); // 动画进入 setTimeout(() => { notification.style.transform = 'translateX(0)'; }, 10); // 自动消失 setTimeout(() => { notification.style.transform = 'translateX(100%)'; setTimeout(() => notification.remove(), 300); }, duration); } function createSettingsUI() { // 创建可折叠的设置面板 const container = document.createElement('div'); container.className = 'lightgg-settings-container'; container.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 9999; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; `; // 切换按钮 const toggleButton = document.createElement('button'); toggleButton.className = 'lightgg-toggle-btn'; toggleButton.innerHTML = '⚙️'; toggleButton.title = 'Light.gg 双语工具设置'; toggleButton.style.cssText = ` width: 44px; height: 44px; border-radius: 50%; border: none; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-size: 18px; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.15); transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; `; // 设置面板 const settingsPanel = document.createElement('div'); settingsPanel.className = 'lightgg-settings-panel'; settingsPanel.style.cssText = ` position: absolute; top: 54px; right: 0; background: white; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.12); padding: 20px; min-width: 280px; transform: translateY(-10px); opacity: 0; visibility: hidden; transition: all 0.3s ease; border: 1px solid #e1e5e9; `; // 面板标题 const title = document.createElement('h3'); title.textContent = 'Light.gg 双语工具'; title.style.cssText = ` margin: 0 0 16px 0; font-size: 16px; font-weight: 600; color: #1a1a1a; display: flex; align-items: center; gap: 8px; `; title.innerHTML = '🌐 Light.gg 双语工具'; // 语言切换选项 const langOption = document.createElement('div'); langOption.style.cssText = ` display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; padding: 12px; background: #f8f9fa; border-radius: 8px; `; const langLabel = document.createElement('label'); langLabel.style.cssText = ` display: flex; flex-direction: column; gap: 4px; cursor: pointer; flex: 1; `; const langTitle = document.createElement('span'); langTitle.textContent = '中文 Perk 提示'; langTitle.style.cssText = ` font-weight: 500; color: #1a1a1a; font-size: 14px; `; const langDesc = document.createElement('span'); langDesc.textContent = '将Perk提示框显示为中文'; langDesc.style.cssText = ` font-size: 12px; color: #6c757d; `; const toggleSwitch = document.createElement('div'); toggleSwitch.className = 'lightgg-switch'; toggleSwitch.style.cssText = ` position: relative; width: 48px; height: 24px; background: ${setTooltipLang ? '#007bff' : '#dee2e6'}; border-radius: 12px; cursor: pointer; transition: background 0.3s ease; `; const switchHandle = document.createElement('div'); switchHandle.style.cssText = ` position: absolute; top: 2px; left: ${setTooltipLang ? '26px' : '2px'}; width: 20px; height: 20px; background: white; border-radius: 50%; transition: left 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.2); `; toggleSwitch.appendChild(switchHandle); langLabel.appendChild(langTitle); langLabel.appendChild(langDesc); langOption.appendChild(langLabel); langOption.appendChild(toggleSwitch); // 更新按钮 const updateButton = document.createElement('button'); updateButton.innerHTML = '🔄 更新数据'; updateButton.style.cssText = ` width: 100%; background: linear-gradient(135deg, #28a745 0%, #20c997 100%); border: none; color: white; padding: 12px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; gap: 8px; `; // 状态指示器 const statusIndicator = document.createElement('div'); statusIndicator.style.cssText = ` display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 8px 12px; background: #e8f5e8; border-radius: 6px; font-size: 12px; color: #155724; `; statusIndicator.innerHTML = '✅ 数据已加载'; // 事件处理 let isOpen = false; toggleButton.addEventListener('click', () => { isOpen = !isOpen; if (isOpen) { settingsPanel.style.opacity = '1'; settingsPanel.style.visibility = 'visible'; settingsPanel.style.transform = 'translateY(0)'; toggleButton.style.transform = 'rotate(180deg)'; } else { settingsPanel.style.opacity = '0'; settingsPanel.style.visibility = 'hidden'; settingsPanel.style.transform = 'translateY(-10px)'; toggleButton.style.transform = 'rotate(0deg)'; } }); // 点击外部关闭 document.addEventListener('click', (e) => { if (!container.contains(e.target) && isOpen) { isOpen = false; settingsPanel.style.opacity = '0'; settingsPanel.style.visibility = 'hidden'; settingsPanel.style.transform = 'translateY(-10px)'; toggleButton.style.transform = 'rotate(0deg)'; } }); toggleSwitch.addEventListener('click', () => { setTooltipLang = !setTooltipLang; GM_setValue(TOOLTIP_LANG_SETTING_KEY, setTooltipLang); if (setTooltipLang) { lggTooltip.lang = "zh-chs"; toggleSwitch.style.background = '#007bff'; switchHandle.style.left = '26px'; createNotification('已启用中文 Perk 提示', 'success'); } else { lggTooltip.lang = originalLang; toggleSwitch.style.background = '#dee2e6'; switchHandle.style.left = '2px'; createNotification('已关闭中文 Perk 提示', 'info'); } }); updateButton.addEventListener('click', async () => { updateButton.disabled = true; updateButton.innerHTML = '⏳ 更新中...'; updateButton.style.opacity = '0.7'; statusIndicator.innerHTML = '🔄 正在更新数据...'; statusIndicator.style.background = '#fff3cd'; statusIndicator.style.color = '#856404'; try { GM_setValue(CACHE_KEY, ''); GM_setValue(LAST_UPDATE_KEY, ''); cachedItemList = null; isDataReady = false; itemListPromise = loadItemList(); await itemListPromise; optimizedTransformReviewItems(); createNotification('数据更新成功!', 'success'); statusIndicator.innerHTML = '✅ 数据已更新'; statusIndicator.style.background = '#e8f5e8'; statusIndicator.style.color = '#155724'; } catch (error) { createNotification('更新失败:' + error.message, 'error'); statusIndicator.innerHTML = '❌ 更新失败'; statusIndicator.style.background = '#f8d7da'; statusIndicator.style.color = '#721c24'; } finally { updateButton.disabled = false; updateButton.innerHTML = '🔄 更新数据'; updateButton.style.opacity = '1'; } }); // 组装UI settingsPanel.appendChild(title); settingsPanel.appendChild(langOption); settingsPanel.appendChild(updateButton); settingsPanel.appendChild(statusIndicator); container.appendChild(toggleButton); container.appendChild(settingsPanel); document.body.appendChild(container); // 悬停效果 toggleButton.addEventListener('mouseenter', () => { toggleButton.style.transform = 'scale(1.1)'; toggleButton.style.boxShadow = '0 6px 20px rgba(0,0,0,0.25)'; }); toggleButton.addEventListener('mouseleave', () => { if (!isOpen) { toggleButton.style.transform = 'scale(1)'; toggleButton.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; } }); updateButton.addEventListener('mouseenter', () => { if (!updateButton.disabled) { updateButton.style.transform = 'translateY(-1px)'; updateButton.style.boxShadow = '0 4px 12px rgba(40, 167, 69, 0.3)'; } }); updateButton.addEventListener('mouseleave', () => { updateButton.style.transform = 'translateY(0)'; updateButton.style.boxShadow = 'none'; }); } async function loadItemList() { const now = new Date().toDateString(); const lastUpdate = GM_getValue(LAST_UPDATE_KEY, ''); if (lastUpdate !== now) { try { const response = await fetch(ITEM_LIST_URL); const data = await response.json(); GM_setValue(CACHE_KEY, JSON.stringify(data.data)); GM_setValue(LAST_UPDATE_KEY, now); cachedItemList = data.data; } catch (error) { console.error('更新失败:', error); cachedItemList = JSON.parse(GM_getValue(CACHE_KEY) || '{}'); } } else { cachedItemList = JSON.parse(GM_getValue(CACHE_KEY) || '{}'); } buildLookupMap(cachedItemList); isDataReady = true; return cachedItemList; } let itemListPromise = loadItemList(); // 性能优化:只处理新元素,使用O(1)查找 function processElements(elements, lang) { const newElements = Array.from(elements).filter(el => !processedElements.has(el)); if (newElements.length === 0) return; newElements.forEach(element => { const originalText = element.textContent.trim(); const lookupResult = itemLookupMap.get(originalText.toLowerCase()); if (lookupResult) { const { item } = lookupResult; const translatedName = lang === 'zh-chs' ? item.en : item['zh-chs']; if (translatedName) { element.textContent = `${originalText} | ${translatedName}`; processedElements.add(element); } } }); console.log(`处理了 ${newElements.length} 个新元素`); } function optimizedTransformReviewItems() { const elements = document.querySelectorAll('.item-name h2, .item-name a, .key-perk strong'); const lang = window.location.pathname.includes('/zh-chs/') ? 'zh-chs' : 'en'; // 性能优化:如果数据已准备好,直接同步处理 if (isDataReady && itemLookupMap.size > 0) { processElements(elements, lang); } else { itemListPromise.then(() => { processElements(elements, lang); }); } } // 性能优化:XHR拦截使用节流 const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function() { const url = arguments[1]; if (/api\.light\.gg\/items\/\d*\/?/.test(url)) { this.addEventListener('load', throttle(optimizedTransformReviewItems, 200)); } originalOpen.apply(this, arguments); }; // 性能优化:更智能的DOM观察者 const observer = new MutationObserver(throttle((mutations) => { let shouldProcess = false; // 只在添加了相关元素时才处理 for (const mutation of mutations) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { for (const node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches?.('.item-name, .key-perk') || node.querySelector?.('.item-name, .key-perk')) { shouldProcess = true; break; } } } if (shouldProcess) break; } } if (shouldProcess) { optimizedTransformReviewItems(); } }, 200)); observer.observe(document.body, { childList: true, subtree: true }); // 初始化 window.addEventListener('load', () => { createSettingsUI(); originalLang = lggTooltip.lang; if (setTooltipLang) lggTooltip.lang = "zh-chs"; // 只在主界面显示欢迎通知 if (window.location.pathname === '/' || window.location.pathname === '') { setTimeout(() => { createNotification('Light.gg 双语工具已启动 🚀', 'success', 2000); }, 1000); } const reviewTab = document.getElementById('review-tab'); reviewTab?.click(); optimizedTransformReviewItems(); }); })();