您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds chat translation buttons
// ==UserScript== // @name Torn Translator (Chat Fix) // @namespace http://tampermonkey.net/ // @version 0.1 // @description Adds chat translation buttons // @author JeffBezas // @match https://www.torn.com/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_setClipboard // @connect translate.googleapis.com // @license MIT // ==/UserScript== (function() { 'use strict'; // Load saved position or set default let posX = GM_getValue("translatorPosX", 50); let posY = GM_getValue("translatorPosY", 50); // Add custom styles GM_addStyle(` #translator-container { position: fixed; left: ${posX}px; top: ${posY}px; width: 300px; background: rgba(0, 0, 0, 0.8); padding: 10px; border-radius: 5px; color: white; font-size: 14px; z-index: 9999; cursor: grab; } #translator-header { background: rgba(255, 255, 255, 0.2); padding: 5px; text-align: center; font-weight: bold; cursor: grab; user-select: none; } #translator-container select, #translator-container textarea, #translator-container button { width: 100%; margin-top: 5px; } #translator-container textarea { height: 50px; } #translated-text { margin-top: 10px; background: white; color: black; padding: 5px; border-radius: 3px; } .translate-btn { margin-left: 5px; background: #4CAF50; color: white; border: none; padding: 2px 5px; font-size: 12px; cursor: pointer; border-radius: 3px; } .translate-btn:hover { background: #45a049; } `); // Create the translation UI const translatorDiv = document.createElement('div'); translatorDiv.id = 'translator-container'; translatorDiv.innerHTML = ` <div id="translator-header">Drag Me</div> <label>Translate from:</label> <select id="sourceLang"> <option value="auto">Auto</option> <option value="en">English</option> <option value="es">Spanish</option> <option value="fr">French</option> <option value="de">German</option> </select> <label>To:</label> <select id="targetLang"> <option value="en">English</option> <option value="es">Spanish</option> <option value="fr">French</option> <option value="de">German</option> </select> <textarea id="textToTranslate" placeholder="Enter text here..."></textarea> <div style="display: flex; justify-content: space-between;"> <button id="copyText">📋 Copy</button> <button id="pasteText">📥 Paste</button> </div> <div id="translated-text">Translation will appear here...</div> `; document.body.appendChild(translatorDiv); // Enable dragging let isDragging = false, startX, startY; document.getElementById('translator-header').addEventListener('mousedown', function(e) { isDragging = true; startX = e.clientX - translatorDiv.offsetLeft; startY = e.clientY - translatorDiv.offsetTop; translatorDiv.style.cursor = "grabbing"; }); document.addEventListener('mousemove', function(e) { if (isDragging) { let newX = e.clientX - startX; let newY = e.clientY - startY; translatorDiv.style.left = newX + "px"; translatorDiv.style.top = newY + "px"; } }); document.addEventListener('mouseup', function() { if (isDragging) { GM_setValue("translatorPosX", translatorDiv.offsetLeft); GM_setValue("translatorPosY", translatorDiv.offsetTop); isDragging = false; translatorDiv.style.cursor = "grab"; } }); // Copy to clipboard document.getElementById('copyText').addEventListener('click', function() { const translatedText = document.getElementById('translated-text').innerText; GM_setClipboard(translatedText); }); // Paste from clipboard document.getElementById('pasteText').addEventListener('click', function() { navigator.clipboard.readText().then(text => { document.getElementById('textToTranslate').value = text; translateText(text); }).catch(err => { console.error("Failed to read clipboard: ", err); }); }); // Auto-translate on input let timeout; document.getElementById('textToTranslate').addEventListener('input', function() { clearTimeout(timeout); timeout = setTimeout(() => { const text = document.getElementById('textToTranslate').value; translateText(text); }, 500); }); // Function to fetch translation function translateText(text) { const sourceLang = document.getElementById('sourceLang').value; const targetLang = document.getElementById('targetLang').value; if (text.trim() === "") { document.getElementById('translated-text').innerText = "Translation will appear here..."; return; } const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}`; GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { try { const result = JSON.parse(response.responseText); const translatedText = result[0].map(item => item[0]).join(""); document.getElementById('translated-text').innerText = translatedText; } catch (e) { document.getElementById('translated-text').innerText = "Translation error."; } } }); } // Add translation buttons to chat messages function addTranslationButtons() { document.querySelectorAll('.chat-box-message__message___SldE8').forEach(message => { if (!message.querySelector('.translate-btn')) { const translateBtn = document.createElement('button'); translateBtn.innerText = "Translate"; translateBtn.classList.add('translate-btn'); // Get clean message text (remove button and emoji) translateBtn.addEventListener('click', function() { const text = message.querySelector('.text-message___gcG6e')?.innerText.trim() || ""; // Extract only message text document.getElementById('textToTranslate').value = text; translateText(text); }); message.appendChild(translateBtn); } }); } // Observe chat for new messages const chatObserver = new MutationObserver(addTranslationButtons); chatObserver.observe(document.body, { childList: true, subtree: true }); })();