Telegram 输入框翻译并发送 ( Gemini模型 缅甸语)

v3.1.2基础: 更换模型为Gemini, 更新翻译提示词以更好地处理缅甸语和格式要求, 区分标准和缩写模式的处理流程。

// ==UserScript==
// @name         Telegram 输入框翻译并发送 ( Gemini模型 缅甸语)
// @namespace    http://tampermonkey.net/
// @version      3.99V333
// @description  v3.1.2基础: 更换模型为Gemini, 更新翻译提示词以更好地处理缅甸语和格式要求, 区分标准和缩写模式的处理流程。
// @author       Your Name / AI Assistant
// @match        https://web.telegram.org/k/*
// @match        https://web.telegram.org/a/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect      api.lhfcb.com
// @icon         https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Telegram_logo.svg/48px-Telegram_logo.svg.png
// ==/UserScript==

(function() {
'use strict';

// --- 配置 ---
const SCRIPT_VERSION = '3.2.0'; // << MODIFIED v3.2.0 >> 脚本版本
const OHMYGPT_API_KEY = "sk-deviWoSNZcRVJcIwK5mRKw4iGo8RizKUpwxfXnYRZLAub0KN"; // 如有不同,请替换为你的 API Key (如果需要,根据新模型调整)
const OHMYGPT_API_ENDPOINT = "https://api.lhfcb.com/v1/chat/completions"; // 保持不变,假设此端点是代理或支持Gemini
const INPUT_TRANSLATE_MODEL = "gemini-2.5-flash-preview-04-17-nothinking"; // << MODIFIED v3.2.0 >> 使用的模型
const MAX_CACHE_SIZE = 100; // 最大缓存条目数
const STORAGE_KEY_AUTOSEND = 'telegramTranslateAutoSendPref'; // 自动发送设置的 localStorage 键名
const STORAGE_KEY_MODE = 'telegramTranslateModePref';     // 翻译模式设置的 localStorage 键名

// --- 翻译模式常量 ---
const MODE_ABBREVIATED = 'abbreviated';
const MODE_STANDARD = 'standard';

// --- 缅甸语 UI 文本常量 ---
const MODE_TEXT_ABBREVIATED_MY = 'တိုတောင်း'; // 缩写模式
const MODE_TEXT_STANDARD_MY = 'စံမူ';       // 标准模式
const AUTO_SEND_ON_MY = "အော်တို: ဖွင့်";
const AUTO_SEND_OFF_MY = "အော်တို: ပိတ်";
const RETRY_ORIGINAL_MY = "မူရင်းအတိုင်း ပြန်ကြိုးစားမည်";
const RETRY_PROCESSING_MY = "လုပ်ဆောင်မှုကို ပြန်ကြိုးစားမည်";
const STATUS_AUTO_SEND_ENABLED_MY = "အော်တို ပို့ခြင်းကို ဖွင့်ထားသည်";
const STATUS_AUTO_SEND_DISABLED_MY = "အော်တို ပို့ခြင်းကို ပိတ်ထားသည်";
const STATUS_MODE_SWITCHED_TO_MY = "မုဒ်ကို %MODE% သို့ ပြောင်းထားသည်"; // %MODE% will be replaced
const ERROR_NO_INPUT_OR_SEND_BUTTON_MY = "အမှား: စာရိုက်အကွက် သို့မဟုတ် ပို့ရန်ခလုတ်ကို ရှာမတွေ့ပါ";
const INFO_LOADED_FROM_CACHE_MY = "[%MODE%] ကက်ရှ်မှ ရယူပြီးပါပြီ ✓";
const STATUS_PROCESSING_DONE_MANUAL_SEND_MY = "[%MODE%] ပြုလုပ်မှု ပြီးစီးပါပြီ ✓ (ကျေးဇူးပြု၍ ကိုယ်တိုင် ပို့ပါ)";
const ERROR_SEND_FAILED_BUTTON_MY = "ပို့ရန် မအောင်မြင်ပါ (ခလုတ် မရနိုင်ပါလား?)";
const STATUS_TRANSLATING_MY = "[%MODE%] ဘာသာပြန်နေသည်...";
const ERROR_PROCESSING_FAILED_MY = "လုပ်ဆောင်မှု မအောင်မြင်ပါ: %ERROR%";
const ERROR_NO_SEND_BUTTON_MY = "အမှား: ပို့ရန်ခလုတ်ကို ရှာမတွေ့ပါ!";
const ERROR_SEND_BUTTON_DISABLED_MY = "အမှား: ပို့ရန်ခလုတ် မရနိုင်ပါ!";
const ERROR_RETRY_UI_ELEMENTS_MISSING_MY = "ပြန်ကြိုးစားရန် မအောင်မြင်ပါ: UI အစိတ်အပိုင်းများ ပျောက်ဆုံးနေသည်";
const ERROR_RETRY_SEND_BUTTON_DISABLED_MY = "ပြန်ကြိုးစားရန် မအောင်မြင်ပါ: ပို့ရန်ခလုတ် မရနိုင်ပါ";
const ERROR_CANNOT_SAVE_AUTO_SEND_MY = "အော်တို ပို့ခြင်း ဆက်တင်ကို သိမ်းဆည်း၍မရပါ";
const ERROR_CANNOT_SAVE_MODE_MY = "မုဒ် ဆက်တင်ကို သိမ်းဆည်း၍မရပါ";
const SUCCESS_ABBREVIATION_APPLIED_MY = "အတိုချုပ် အစားထည့်ခြင်း အောင်မြင်ပါပြီ";
const INFO_STATUS_MY = "အခြေအနေ"; // Generic status, if needed
const INFO_INFO_MY = "အချက်အလက်";   // Generic info, if needed
const INFO_ERROR_MY = "အမှား";    // Generic error, if needed
const INFO_SUCCESS_MY = "အောင်မြင်သည်"; // Generic success, if needed


// --- << MODIFIED v3.2.0 >> 翻译提示词 (Gemini 优化) ---
// 基础翻译提示词 (用于API调用,缩写模式在此基础上进行脚本后处理)
const TRANSLATION_PROMPT = `
Translate the following Burmese (Myanmar language) text into English
Be mindful of the formality or informality of the original text and reflect that tone in your English translation
Consider whether the Burmese text uses honorifics, colloquialisms, or slang and ensure your English translation conveys a similar level of formality or informality
Pay attention to verb conjugations and sentence structures in Burmese that might indicate politeness or casualness and find appropriate equivalents in English
Choose vocabulary and sentence structures that appropriately match the original style and avoid overly literal translations that do not capture the intended level of formality or informality
Do not end the translated sentence with a period
If parts of the input are untranslatable (like codes, specific IDs, numbers, proper nouns), keep them unchanged
If the entire input is untranslatable (e.g., just numbers, code, already valid English, emojis), return the original text
Return only the final translated text. No explanations, no notes. Just the translation.
Input Text:
{text_to_translate}
`;


// --- 选择器 (保持不变) ---
const INPUT_SELECTOR = 'div.input-message-input[contenteditable="true"]';
const SEND_BUTTON_SELECTOR = 'button.btn-send';
const INPUT_AREA_CONTAINER_SELECTOR = '.chat-input-main';

// --- UI 元素 ID (保持不变) ---
const STATUS_BAR_ID = 'custom-input-status-bar';
const CONTROLS_CONTAINER_ID = 'custom-input-controls-container';
const AUTO_SEND_TOGGLE_ID = 'custom-auto-send-toggle';
const MODE_SELECTOR_CONTAINER_ID = 'custom-mode-selector';
const MODE_BUTTON_ABBR_ID = 'custom-mode-button-abbr';
const MODE_BUTTON_STD_ID = 'custom-mode-button-std';
const RETRY_BUTTON_ID = 'custom-translate-retry-button';
const RETRY_PROCESSING_BUTTON_ID = 'custom-processing-retry-button';

// --- 语言检测正则 (保持不变) ---
const CHINESE_REGEX = /[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]/;
const BURMESE_REGEX = /[\u1000-\u109F]/; // 缅甸语 Unicode 范围

// --- 状态变量 (保持不变) ---
let statusBarElement = null;
let controlsContainerElement = null;
let autoSendToggleElement = null;
let modeSelectorContainerElement = null;
let currentInputApiXhr = null;
let isTranslatingAndSending = false;
let sendButtonClickListenerAttached = false;
let lastOriginalText = null;
const translationCache = new Map();
let justTranslated = false;

// --- 自动发送状态 (保持不变) ---
let autoSendEnabled = true;
const savedAutoSendState = localStorage.getItem(STORAGE_KEY_AUTOSEND);
if (savedAutoSendState !== null) {
    autoSendEnabled = savedAutoSendState === 'true';
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 已加载自动发送偏好: ${autoSendEnabled ? '开启' : '关闭'}`);
} else {
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 未找到自动发送偏好,使用默认值: ${autoSendEnabled ? '开启' : '关闭'}`);
}

// --- 翻译模式状态 (保持不变) ---
let currentTranslationMode = MODE_ABBREVIATED; // 默认缩写模式
const savedModeState = localStorage.getItem(STORAGE_KEY_MODE);
if (savedModeState === MODE_STANDARD || savedModeState === MODE_ABBREVIATED) {
    currentTranslationMode = savedModeState;
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 已加载翻译模式偏好: ${currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准'}`);
} else {
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 未找到翻译模式偏好,使用默认值: 缩写`);
}

// --- CSS 样式 (保持不变) ---
GM_addStyle(`
    ${INPUT_AREA_CONTAINER_SELECTOR} { position: relative !important; overflow: visible !important; }
    #${STATUS_BAR_ID} { position: absolute; bottom: 2px; left: 8px; right: 8px; display: none; padding: 4px 8px; font-size: 12px; color: #ccc; background-color: rgba(20, 20, 20, 0.85); backdrop-filter: blur(2px); border-top: 1px solid rgba(255, 255, 255, 0.1); border-radius: 4px; z-index: 149; line-height: 1.3; text-align: left; transition: opacity 0.2s ease-in-out, bottom 0.2s ease-in-out; opacity: 0; pointer-events: none; }
    #${STATUS_BAR_ID}.visible { display: flex; justify-content: space-between; align-items: center; opacity: 1; pointer-events: auto; }
    #${STATUS_BAR_ID} .status-text { flex-grow: 1; margin-right: 8px; }
    #${STATUS_BAR_ID} .status-buttons { display: flex; gap: 5px; flex-shrink: 0; }
    #${STATUS_BAR_ID} .status { font-style: italic; color: #a0a0a0; }
    #${STATUS_BAR_ID} .info { font-style: italic; color: #87cefa; }
    #${STATUS_BAR_ID} .error { font-weight: bold; color: #ff8a8a; }
    #${STATUS_BAR_ID} .success { font-weight: bold; color: #8ade8a; }
    #${RETRY_BUTTON_ID}, #${RETRY_PROCESSING_BUTTON_ID} { padding: 2px 6px; font-size: 11px; font-weight: bold; color: #d0d0d0; background-color: rgba(80, 80, 80, 0.9); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 3px; cursor: pointer; flex-shrink: 0; transition: background-color 0.2s ease, color 0.2s ease; white-space: nowrap; }
    #${RETRY_BUTTON_ID}:hover, #${RETRY_PROCESSING_BUTTON_ID}:hover { background-color: rgba(100, 100, 100, 0.9); color: #fff; }
    #${RETRY_BUTTON_ID}:active, #${RETRY_PROCESSING_BUTTON_ID}:active { background-color: rgba(60, 60, 60, 0.9); }
    #${CONTROLS_CONTAINER_ID} { position: absolute; top: 0; right: 10px; display: flex; align-items: flex-end; gap: 0px; z-index: 151; pointer-events: none; height: 26px; }
    #${MODE_SELECTOR_CONTAINER_ID} { display: flex; margin-right: 5px; pointer-events: auto; border: 1px solid rgba(255, 255, 255, 0.2); border-bottom: none; border-radius: 6px 6px 0 0; overflow: hidden; background-color: rgba(80, 80, 80, 0.9); }
    #${MODE_BUTTON_ABBR_ID}, #${MODE_BUTTON_STD_ID} { padding: 4px 8px; font-size: 12px; font-weight: bold; color: #ccc; background-color: transparent; border: none; cursor: pointer; user-select: none; transition: background-color 0.2s ease, color 0.2s ease; line-height: 16px; height: 24px; box-sizing: border-box; }
    #${MODE_BUTTON_ABBR_ID}.active, #${MODE_BUTTON_STD_ID}.active { background-color: rgba(70, 130, 180, 0.95); color: #fff; }
    #${MODE_BUTTON_ABBR_ID}:hover:not(.active), #${MODE_BUTTON_STD_ID}:hover:not(.active) { background-color: rgba(100, 100, 100, 0.9); }
    #${AUTO_SEND_TOGGLE_ID} { padding: 4px 10px; font-size: 12px; font-weight: bold; background-color: rgba(80, 80, 80, 0.9); color: #ccc; border: 1px solid rgba(255, 255, 255, 0.2); border-bottom: none; border-radius: 6px 6px 0 0; cursor: pointer; user-select: none; transition: background-color 0.2s ease, color 0.2s ease; pointer-events: auto; line-height: 16px; height: 24px; box-sizing: border-box; }
    #${AUTO_SEND_TOGGLE_ID}.autosend-on { background-color: rgba(70, 130, 180, 0.95); color: #fff; }
    #${AUTO_SEND_TOGGLE_ID}:hover { filter: brightness(1.1); }
`);

// --- 辅助函数 (大部分保持不变) ---
function detectLanguage(text) { if (!text) return null; if (BURMESE_REGEX.test(text)) return 'Burmese'; if (CHINESE_REGEX.test(text)) return 'Chinese'; return 'Other'; } // 优先检测缅甸语
function setCursorToEnd(element) { try { const range = document.createRange(); const sel = window.getSelection(); range.selectNodeContents(element); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); element.focus(); } catch (e) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 设置光标时出错:`, e); } }
function ensureControlsExist() {
    const inputMainContainer = document.querySelector(INPUT_AREA_CONTAINER_SELECTOR);
    if (!inputMainContainer) return;
    if (window.getComputedStyle(inputMainContainer).position !== 'relative') { inputMainContainer.style.position = 'relative'; }
    if (!controlsContainerElement || !inputMainContainer.contains(controlsContainerElement)) {
        controlsContainerElement = document.createElement('div');
        controlsContainerElement.id = CONTROLS_CONTAINER_ID;
        inputMainContainer.appendChild(controlsContainerElement);
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 控制按钮容器已创建。`);
    }
    if (!modeSelectorContainerElement || !controlsContainerElement.contains(modeSelectorContainerElement)) {
        modeSelectorContainerElement = document.createElement('div');
        modeSelectorContainerElement.id = MODE_SELECTOR_CONTAINER_ID;
        const abbrButton = document.createElement('button'); abbrButton.id = MODE_BUTTON_ABBR_ID; abbrButton.textContent = 'တိုတောင်း'; abbrButton.type = 'button'; abbrButton.addEventListener('click', () => switchMode(MODE_ABBREVIATED)); modeSelectorContainerElement.appendChild(abbrButton);
        const stdButton = document.createElement('button'); stdButton.id = MODE_BUTTON_STD_ID; stdButton.textContent = 'စံမူ'; stdButton.type = 'button'; stdButton.addEventListener('click', () => switchMode(MODE_STANDARD)); modeSelectorContainerElement.appendChild(stdButton);
        controlsContainerElement.insertBefore(modeSelectorContainerElement, controlsContainerElement.firstChild);
        updateModeButtonVisuals();
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 模式选择按钮已创建。`);
    }
    if (!autoSendToggleElement || !controlsContainerElement.contains(autoSendToggleElement)) {
        autoSendToggleElement = document.createElement('button'); autoSendToggleElement.id = AUTO_SEND_TOGGLE_ID; autoSendToggleElement.type = 'button'; autoSendToggleElement.addEventListener('click', toggleAutoSend);
        controlsContainerElement.appendChild(autoSendToggleElement);
        updateAutoSendButtonVisual();
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 自动发送开关按钮已创建。`);
    }
    if (!statusBarElement || !inputMainContainer.contains(statusBarElement)) {
        statusBarElement = document.createElement('div'); statusBarElement.id = STATUS_BAR_ID;
        inputMainContainer.appendChild(statusBarElement);
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 状态栏元素已创建。`);
    }
}
function updateStatusDisplay(content, type = 'status', duration = 0, showRetryButton = false, showRetryProcessingButton = false) {
    ensureControlsExist();
    if (!statusBarElement) { console.error(`[输入翻译 v${SCRIPT_VERSION}] 更新状态时未找到状态栏元素。`); return; }
    let buttonsHtml = '';
    if (showRetryButton && lastOriginalText) { buttonsHtml += `<button id="${RETRY_BUTTON_ID}" type="button">${RETRY_ORIGINAL_MY}</button>`; }
    if (showRetryProcessingButton) { buttonsHtml += `<button id="${RETRY_PROCESSING_BUTTON_ID}" type="button">${RETRY_PROCESSING_MY}</button>`; }
    statusBarElement.innerHTML = `<span class="status-text ${type}">${content}</span>${buttonsHtml ? `<div class="status-buttons">${buttonsHtml}</div>` : ''}`;
    statusBarElement.classList.add('visible');
    if (showRetryButton && lastOriginalText) { const retryBtn = statusBarElement.querySelector(`#${RETRY_BUTTON_ID}`); if (retryBtn) retryBtn.addEventListener('click', handleRetryOriginalClick); }
    if (showRetryProcessingButton) { const retryProcBtn = statusBarElement.querySelector(`#${RETRY_PROCESSING_BUTTON_ID}`); if (retryProcBtn) retryProcBtn.addEventListener('click', handleRetryProcessingClick); }
    if (statusBarElement.hideTimeout) clearTimeout(statusBarElement.hideTimeout);
    statusBarElement.hideTimeout = duration > 0 ? setTimeout(hideStatusDisplay, duration) : null;
 }
function hideStatusDisplay() {
    if (statusBarElement) { if (statusBarElement.hideTimeout) clearTimeout(statusBarElement.hideTimeout); statusBarElement.hideTimeout = null; statusBarElement.classList.remove('visible'); setTimeout(() => { if (statusBarElement && !statusBarElement.classList.contains('visible')) { statusBarElement.innerHTML = ''; } }, 250); }
}
// --- << MODIFIED v3.2.0 >> 缩写处理函数 (仅在缩写模式下由脚本调用) ---
function fixNumberAbbreviations(text) {
    if (!text) return text; let originalText = text;
    // 严格应用提示词中提到的规则(示例,保持不变)
    text = text.replace(/\b2\b/gi, "to"); text = text.replace(/\b4\b/gi, "for"); text = text.replace(/\b(be?|b)4\b/gi, "before"); text = text.replace(/\b2day\b/gi, "today"); text = text.replace(/\b2nite\b/gi, "tonight"); text = text.replace(/\b2night\b/gi, "tonight"); text = text.replace(/\b2mrw\b/gi, "tomorrow"); text = text.replace(/\b2moro\b/gi, "tomorrow"); text = text.replace(/\bgr8\b/gi, "great"); text = text.replace(/\bl8r\b/gi, "later"); text = text.replace(/\bw8\b/gi, "wait"); text = text.replace(/\bh8\b/gi, "hate"); text = text.replace(/\bsk8\b/gi, "skate"); text = text.replace(/\bm8\b/gi, "mate");
    if (text !== originalText) { console.log(`[输入翻译 v${SCRIPT_VERSION}][缩写后处理] 应用了数字/组合缩写修正: "${originalText}" -> "${text}"`); } return text;
}
function applyLetterAbbreviations(text) {
    if (!text) return text;
    text = text.replace(/\b[Tt]hank you\b/g, m => m.charAt(0) === 'T' ? 'Thx u' : 'thx u');
    let originalText = text; let modifiedText = text; let initialCapitalizationApplied = false; let changesMade = false;
    // 严格应用提示词中提到的规则 (示例,保持不变)
    const abbrMap = { "you": "u", "your": "ur", "yours": "urs", "yourself": "urself", "are": "r", "thanks": "thx", "thank": "thx", "and": "&", "before": "bfr", "first": "frst", "tomorrow": "tmrw", "next": "nxt" };
    const capitalizeAtStart = ["u", "ur", "urs","r", "thx", "bfr", "frst", "tmrw", "nxt", "urself"];
    // (代码逻辑保持不变, 确保能正确应用缩写)
    let firstWordIndex = -1; let firstWord = ""; let leadingChars = ""; const match = modifiedText.match(/^(\s*[^a-zA-Z\s]*)?([a-zA-Z]+)/);
    if (match) { leadingChars = match[1] || ""; firstWord = match[2]; firstWordIndex = leadingChars.length; const lowerFirstWord = firstWord.toLowerCase();
        if (abbrMap.hasOwnProperty(lowerFirstWord)) { const abbreviation = abbrMap[lowerFirstWord]; let replacementMade = false;
            if (capitalizeAtStart.includes(abbreviation)) { const capitalizedAbbr = abbreviation.charAt(0).toUpperCase() + abbreviation.slice(1); modifiedText = leadingChars + capitalizedAbbr + modifiedText.substring(firstWordIndex + firstWord.length); initialCapitalizationApplied = true; replacementMade = true; }
            else if (abbreviation === '&') { modifiedText = leadingChars + abbreviation + modifiedText.substring(firstWordIndex + firstWord.length); initialCapitalizationApplied = true; replacementMade = true; } // Handle '&' at start
            if (replacementMade) changesMade = true;
        }
    }
    const replaceRemaining = (fullWord, abbr) => { const regexLower = new RegExp(`\\b${fullWord}\\b`, 'g'); const regexUpper = new RegExp(`\\b${fullWord.charAt(0).toUpperCase() + fullWord.slice(1)}\\b`, 'g'); let startIndex = 0; if (initialCapitalizationApplied && firstWord.toLowerCase() === fullWord) { startIndex = firstWordIndex + (abbrMap[fullWord] ? abbrMap[fullWord].length : firstWord.length); } let targetStringPart = modifiedText.substring(startIndex); let prefix = modifiedText.substring(0, startIndex); let replacedPart = targetStringPart; let currentChangesMade = false; const originalLength = replacedPart.length; if (abbr === '&') { replacedPart = replacedPart.replace(/\b[Aa]nd\b/g, '&'); } else { replacedPart = replacedPart.replace(regexLower, abbr); replacedPart = replacedPart.replace(regexUpper, abbr); } if(replacedPart.length !== originalLength || replacedPart !== targetStringPart) currentChangesMade = true; modifiedText = prefix + replacedPart; if (currentChangesMade) changesMade = true; };
    for (const word in abbrMap) { replaceRemaining(word, abbrMap[word]); }
    if (/^\s*&/.test(modifiedText)) {
        modifiedText = modifiedText.replace(/^(\s*)&/, '$1And');
    }
    if (changesMade) { console.log(`[输入翻译 v${SCRIPT_VERSION}][缩写后处理] 应用了字母缩写。\n    输入: "${originalText}"\n    输出: "${modifiedText}"`); } else { console.log(`[输入翻译 v${SCRIPT_VERSION}][缩写后处理] 未应用字母缩写。\n    输入: "${originalText}"`); } return modifiedText;
}
// --- 重试处理函数 (保持不变, 但日志会反映当前模式) ---
function handleRetryOriginalClick(event) {
     event.preventDefault(); event.stopPropagation(); console.log(`[输入翻译 v${SCRIPT_VERSION}] "重试原文"按钮被点击。`); if (isTranslatingAndSending) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 正在处理中,忽略"重试原文"点击。`); return; } if (!lastOriginalText) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 没有存储原文可供重试。`); hideStatusDisplay(); return; } const inputElement = document.querySelector(INPUT_SELECTOR); const sendButton = document.querySelector(SEND_BUTTON_SELECTOR); if (!inputElement || !sendButton) { updateStatusDisplay(ERROR_RETRY_UI_ELEMENTS_MISSING_MY, 'error', 4000, true, true); return; } if (sendButton.disabled) { updateStatusDisplay(ERROR_RETRY_SEND_BUTTON_DISABLED_MY, 'error', 4000, true, true); return; }
     const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
     console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在使用 [${currentModeText}] 模式重试原文翻译: "${lastOriginalText}"`);
     translateAndSend(lastOriginalText, inputElement, sendButton, true); // forceApi = true
}
function handleRetryProcessingClick(event) {
    event.preventDefault(); event.stopPropagation(); console.log(`[输入翻译 v${SCRIPT_VERSION}] "重试处理"按钮被点击。`); if (isTranslatingAndSending) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 正在处理中,忽略"重试处理"点击。`); return; } const inputElement = document.querySelector(INPUT_SELECTOR); const sendButton = document.querySelector(SEND_BUTTON_SELECTOR); if (!inputElement || !sendButton) { updateStatusDisplay(ERROR_RETRY_UI_ELEMENTS_MISSING_MY, 'error', 4000, true, true); return; } const currentText = inputElement.textContent?.trim(); if (!currentText) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 输入框为空,无法重试处理。`); hideStatusDisplay(); return; } if (sendButton.disabled) { updateStatusDisplay(ERROR_RETRY_SEND_BUTTON_DISABLED_MY, 'error', 4000, true, true); return; }
    const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在使用 [${currentModeText}] 模式对当前文本重试处理: "${currentText}"`);
    translateAndSend(currentText, inputElement, sendButton, true); // forceApi = true
}
// --- UI 控制函数 (保持不变) ---
function updateAutoSendButtonVisual() {
    if (!autoSendToggleElement) return; autoSendToggleElement.textContent = autoSendEnabled ? AUTO_SEND_ON_MY : AUTO_SEND_OFF_MY; autoSendToggleElement.className = autoSendEnabled ? 'autosend-on' : '';
}
function toggleAutoSend() {
    autoSendEnabled = !autoSendEnabled; const statusTextMy = autoSendEnabled ? STATUS_AUTO_SEND_ENABLED_MY : STATUS_AUTO_SEND_DISABLED_MY; console.log(`[输入翻译 v${SCRIPT_VERSION}] 自动发送切换为: ${autoSendEnabled ? '开启' : '关闭'}`); updateAutoSendButtonVisual(); updateStatusDisplay(statusTextMy, 'status', 2000); try { localStorage.setItem(STORAGE_KEY_AUTOSEND, autoSendEnabled.toString()); console.log(`[输入翻译 v${SCRIPT_VERSION}] 已将自动发送偏好 (${autoSendEnabled ? '开启' : '关闭'}) 保存到 localStorage。`); } catch (e) { console.error(`[输入翻译 v${SCRIPT_VERSION}] 保存自动发送偏好到 localStorage 时出错:`, e); updateStatusDisplay(ERROR_CANNOT_SAVE_AUTO_SEND_MY, 'error', 3000); }
}
function updateModeButtonVisuals() {
    const abbrButton = document.getElementById(MODE_BUTTON_ABBR_ID); const stdButton = document.getElementById(MODE_BUTTON_STD_ID); if (!abbrButton || !stdButton) return; if (currentTranslationMode === MODE_ABBREVIATED) { abbrButton.classList.add('active'); stdButton.classList.remove('active'); } else { abbrButton.classList.remove('active'); stdButton.classList.add('active'); }
}
function switchMode(newMode) {
    if (newMode === currentTranslationMode) return;
    const oldModeTextMy = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
    currentTranslationMode = newMode;
    const newModeTextMy = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 翻译模式切换为: ${newModeTextMy}`);
    updateModeButtonVisuals();
    updateStatusDisplay(STATUS_MODE_SWITCHED_TO_MY.replace('%MODE%', newModeTextMy), 'status', 2000);
    try {
        localStorage.setItem(STORAGE_KEY_MODE, currentTranslationMode);
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 已将翻译模式偏好 (${newModeTextMy}) 保存到 localStorage。`);
    } catch (e) {
        console.error(`[输入翻译 v${SCRIPT_VERSION}] 保存翻译模式偏好到 localStorage 时出错:`, e);
        updateStatusDisplay(ERROR_CANNOT_SAVE_MODE_MY, 'error', 3000);
    }
}

// --- << MODIFIED v3.2.0 >> 主要翻译逻辑 (适配新提示词和模式处理) ---
function translateAndSend(textToProcess, inputElement, sendButton, forceApi = false) {
    if (isTranslatingAndSending) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 已在处理中,忽略新的处理请求。`); return; }
    if (!inputElement || !sendButton) { updateStatusDisplay(ERROR_NO_INPUT_OR_SEND_BUTTON_MY, 'error', 4000, true, true); return; }
    isTranslatingAndSending = true;
    hideStatusDisplay();
    const detectedLang = detectLanguage(textToProcess);
    const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
    // 英文缩写仅模式
    if (currentTranslationMode === MODE_ABBREVIATED && detectedLang !== 'Chinese' && detectedLang !== 'Burmese') {
        let finalText = applyLetterAbbreviations(fixNumberAbbreviations(textToProcess));
        inputElement.textContent = finalText;
        setCursorToEnd(inputElement);
        inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
        updateStatusDisplay(SUCCESS_ABBREVIATION_APPLIED_MY, 'success', 2000);
        showInlineStatus(inputElement, SUCCESS_ABBREVIATION_APPLIED_MY);
        // 英文缩写模式始终自动发送
        setTimeout(() => {
            justTranslated = true;
            if (sendButton && sendButton.isConnected && !sendButton.disabled) {
                sendButton.click();
            }
            isTranslatingAndSending = false;
            hideStatusDisplay();
        }, 50);
        return;
    }
    if (detectedLang === 'Chinese' || detectedLang === 'Burmese') { lastOriginalText = textToProcess; }

    // --- 缓存检查 ---
    const useCache = !forceApi && (detectedLang === 'Chinese' || detectedLang === 'Burmese');
    // << MODIFIED v3.2.0 >> 缓存键包含模式,因为后处理不同
    const cacheKey = `${currentTranslationMode}::${textToProcess}`;

    if (useCache && translationCache.has(cacheKey)) { // 检查包含模式的缓存键
        const cachedProcessedTranslation = translationCache.get(cacheKey); // 获取已处理过的翻译结果
        console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存命中] 找到原文 "${textToProcess.substring(0,30)}..." 在 [${currentModeText}] 模式下的缓存结果: "${cachedProcessedTranslation}"`);
        updateStatusDisplay(INFO_LOADED_FROM_CACHE_MY.replace('%MODE%', currentModeText), 'info', 3000, false, !autoSendEnabled);

        // 直接使用缓存中已经处理好的文本
        const finalText = cachedProcessedTranslation;

        inputElement.textContent = finalText;
        setCursorToEnd(inputElement);
        inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));

        if (autoSendEnabled) {
            const sendDelay = 50;
            console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存][自动发送] 自动发送已开启。将在 ${sendDelay}ms 后模拟点击发送。`);
            setTimeout(() => {
                if (!isTranslatingAndSending) {
                    console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存][发送超时] 发送已中止 (可能被新操作打断)。`);
                    return;
                }
                if (sendButton && sendButton.isConnected && !sendButton.disabled) {
                     console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存][自动发送] 重置状态并尝试发送...`);
                     isTranslatingAndSending = false;
                     sendButton.click();
                     hideStatusDisplay();
                } else {
                    console.error(`[输入翻译 v${SCRIPT_VERSION}][缓存][自动发送] 发送失败,按钮不可用或已消失。`);
                    updateStatusDisplay(ERROR_SEND_FAILED_BUTTON_MY, 'error', 4000, true, true);
                    isTranslatingAndSending = false;
                }
            }, sendDelay);
        } else {
            console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存] 自动发送已关闭。`);
            updateStatusDisplay(STATUS_PROCESSING_DONE_MANUAL_SEND_MY.replace('%MODE%', currentModeText), 'success', 5000, true, true);
            isTranslatingAndSending = false;
            justTranslated = true;
        }
        return; // 缓存命中,结束函数
    }
    // --- 缓存检查结束 ---

    // --- API 调用 ---
    // << MODIFIED v3.2.0 >> 使用统一的基础翻译提示词
    const finalPrompt = TRANSLATION_PROMPT.replace('{text_to_translate}', textToProcess);
    console.log(`[输入翻译 v${SCRIPT_VERSION}] ${forceApi ? '强制 API 调用' : '缓存未命中'}。使用 [${currentModeText}] 模式调用 API (${INPUT_TRANSLATE_MODEL}) 处理: "${textToProcess.substring(0, 30)}..."`);
    updateStatusDisplay(STATUS_TRANSLATING_MY.replace('%MODE%', currentModeText), 'status');

    // << MODIFIED v3.2.0 >> model 使用新配置
    const requestBody = { model: INPUT_TRANSLATE_MODEL, messages: [{"role": "user", "content": finalPrompt }], temperature: 0.6 }; // Temperature 可以根据模型调整
    if (currentInputApiXhr && typeof currentInputApiXhr.abort === 'function') { currentInputApiXhr.abort(); console.log(`[输入翻译 v${SCRIPT_VERSION}] 中止了之前的 API 请求。`);}

    currentInputApiXhr = GM_xmlhttpRequest({
        method: "POST", url: OHMYGPT_API_ENDPOINT,
        headers: { "Content-Type": "application/json", "Authorization": `Bearer ${OHMYGPT_API_KEY}` },
        data: JSON.stringify(requestBody),
        onload: function(response) {
            currentInputApiXhr = null;
            try {
                if (response.status >= 200 && response.status < 300) {
                    const data = JSON.parse(response.responseText);
                    const rawTranslation = data.choices?.[0]?.message?.content?.trim();
                    if (rawTranslation) {
                        console.log(`[输入翻译 v${SCRIPT_VERSION}][API 成功] 收到原始结果: "${rawTranslation}"`);

                        let finalProcessedText;
                        // << MODIFIED v3.2.0 >> 根据模式进行后处理
                        if (currentTranslationMode === MODE_ABBREVIATED) {
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API 后处理] 应用缩写模式处理...`);
                            finalProcessedText = applyLetterAbbreviations(fixNumberAbbreviations(rawTranslation));
                        } else {
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API 后处理] 标准模式,直接使用翻译结果。`);
                            finalProcessedText = rawTranslation.trim(); // 提示词已要求不加句号,trim即可
                        }
                        console.log(`[输入翻译 v${SCRIPT_VERSION}][API 处理后] 最终文本: "${finalProcessedText}"`);

                        // << MODIFIED v3.2.0 >> 缓存处理后的结果,使用包含模式的键
                        if (!forceApi && (detectedLang === 'Chinese' || detectedLang === 'Burmese')) {
                             if (translationCache.size >= MAX_CACHE_SIZE) { const oldestKey = translationCache.keys().next().value; translationCache.delete(oldestKey); }
                             translationCache.set(cacheKey, finalProcessedText); // 缓存处理后的结果
                             console.log(`[输入翻译 v${SCRIPT_VERSION}] 已缓存 [${currentModeText}] 模式处理结果: "${textToProcess.substring(0,30)}..." -> "${finalProcessedText}"`);
                        }


                        inputElement.textContent = finalProcessedText;
                        setCursorToEnd(inputElement);
                        inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));

                        if (autoSendEnabled) {
                            const sendDelay = 150; // API 延迟稍长
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API][自动发送] 自动发送已开启。将在 ${sendDelay}ms 后模拟点击发送。`);
                            setTimeout(() => {
                                if (!isTranslatingAndSending) {
                                    console.log(`[输入翻译 v${SCRIPT_VERSION}][API][发送超时] 发送已中止。`);
                                    return;
                                }
                                if (sendButton && sendButton.isConnected && !sendButton.disabled) {
                                    console.log(`[输入翻译 v${SCRIPT_VERSION}][API][自动发送] 重置状态并尝试发送...`);
                                    isTranslatingAndSending = false;
                                    sendButton.click();
                                    hideStatusDisplay();
                                } else {
                                    console.error(`[输入翻译 v${SCRIPT_VERSION}][API][自动发送] 发送失败,按钮不可用或已消失。`);
                                    updateStatusDisplay(ERROR_SEND_FAILED_BUTTON_MY, 'error', 4000, true, true);
                                    isTranslatingAndSending = false;
                                }
                            }, sendDelay);
                        } else {
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API] 自动发送已关闭。`);
                            updateStatusDisplay(STATUS_PROCESSING_DONE_MANUAL_SEND_MY.replace('%MODE%', currentModeText), 'success', 5000, true, true);
                            isTranslatingAndSending = false;
                            justTranslated = true;
                        }
                    } else { throw new Error(`API 返回空内容 (结束原因: ${data.choices?.[0]?.finish_reason || '未知'})`); }
                } else { let errorDetail = `HTTP ${response.status}: ${response.statusText}`; try { const errData = JSON.parse(response.responseText); errorDetail = errData.error?.message || errorDetail; } catch (e) { /* 忽略解析错误 */ } throw new Error(errorDetail); }
            } catch (e) { console.error(`[输入翻译 v${SCRIPT_VERSION}][API 错误] 处理 API 响应时出错:`, e); updateStatusDisplay(ERROR_PROCESSING_FAILED_MY.replace('%ERROR%', e.message.substring(0, 60)), 'error', 5000, true, true); isTranslatingAndSending = false; }
        },
        onerror: function(response) { currentInputApiXhr = null; console.error(`[输入翻译 v${SCRIPT_VERSION}][网络错误] 请求失败:`, response); updateStatusDisplay(ERROR_PROCESSING_FAILED_MY.replace('%ERROR%', `网络错误 (${response.status || 'N/A'})`), 'error', 5000, true, true); isTranslatingAndSending = false; },
        ontimeout: function() { currentInputApiXhr = null; console.error(`[输入翻译 v${SCRIPT_VERSION}][超时错误] API 请求超时。`); updateStatusDisplay(ERROR_PROCESSING_FAILED_MY.replace('%ERROR%', "တောင်းဆိုမှု အချိန်ကုန်သွားသည်"), 'error', 5000, true, true); isTranslatingAndSending = false; },
        onabort: function() { currentInputApiXhr = null; console.log(`[输入翻译 v${SCRIPT_VERSION}] API 请求已中止。`); hideStatusDisplay(); isTranslatingAndSending = false; },
        timeout: 45000 // << MODIFIED v3.2.0 >> 稍微增加超时时间以适应潜在较慢的模型
    });
}

// --- 事件监听器 (保持 v3.1.2 修复的手动发送逻辑) ---
function handleInputKeyDown(event) {
    const inputElement = event.target;
    if (!inputElement || !inputElement.matches(INPUT_SELECTOR)) return;

    if (event.key === 'Enter' && justTranslated) {
        justTranslated = false;
        return; // allow default send behavior
    }

    // 回车键逻辑
    if (event.key === 'Enter' && !event.shiftKey && !event.altKey && !event.ctrlKey) {
         // 检查是否允许手动发送 (仅当自动发送关闭且上次操作成功完成时)
         if (statusBarElement && statusBarElement.classList.contains('visible') && !isTranslatingAndSending && !autoSendEnabled) {
              const nonBlockingStatus = statusBarElement.querySelector('span.success, span.info');
              if (nonBlockingStatus) {
                  // 获取当前输入框的文本并检测语言
                  const currentText = inputElement.textContent?.trim() || "";
                  const currentLang = detectLanguage(currentText);

                  // 只有当当前文本 *不需要* 翻译时,才允许默认的回车发送行为
                  if (currentLang !== 'Chinese' && currentLang !== 'Burmese') {
                      console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 检测到非阻塞状态 (${nonBlockingStatus.textContent}) 且当前文本无需翻译 ("${currentText.substring(0,30)}..."),允许手动发送。`);
                      hideStatusDisplay(); // 清除旧状态
                      return; // 允许浏览器默认的回车行为
                  } else {
                      // 当前文本需要翻译,即使状态栏显示上次成功,也要阻止默认行为并继续处理
                      console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 检测到非阻塞状态,但当前文本 ("${currentText.substring(0,30)}...") 需要翻译,将继续处理。`);
                      hideStatusDisplay(); // 清除旧状态,准备显示新状态
                      // **不执行 return**,让代码继续向下执行语言检测和翻译逻辑
                  }
              }
         }

         // 如果正在翻译或处理中,阻止回车
         if (isTranslatingAndSending) {
             console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 正在处理中,阻止发送。`);
             event.preventDefault(); event.stopPropagation();
             return;
         }

         // 检查当前文本是否需要翻译 (现在这个检查总会执行,除非上面允许了手动发送非待翻译文本)
         const text = inputElement.textContent?.trim() || ""; // 重新获取一次以防万一
         const detectedLang = detectLanguage(text);
         if (text && ((detectedLang === 'Chinese' || detectedLang === 'Burmese') || (currentTranslationMode === MODE_ABBREVIATED && detectedLang !== 'Chinese' && detectedLang !== 'Burmese'))) {
             const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
             console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 检测到 ${detectedLang} 文本。将使用 [${currentModeText}] 模式处理...`);
             event.preventDefault(); event.stopPropagation(); // 阻止默认发送,进行翻译
             const sendButton = document.querySelector(SEND_BUTTON_SELECTOR);
             if (!sendButton) { updateStatusDisplay(ERROR_NO_SEND_BUTTON_MY, 'error', 5000, true, true); return; }
             if (sendButton.disabled) { updateStatusDisplay(ERROR_SEND_BUTTON_DISABLED_MY, 'error', 5000, true, true); return; }
             translateAndSend(text, inputElement, sendButton); // 调用翻译处理函数
         } else {
             // 如果是其他语言或空文本,并且没有被上面的手动发送逻辑处理掉,允许正常发送
             console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 无需翻译的文本 ("${text.substring(0,30)}...") 或空内容,允许正常发送。`);
             hideStatusDisplay(); // 清除可能存在的旧状态
         }
    }
    // 其他按键逻辑 (打断处理 - 保持不变)
    else if (isTranslatingAndSending && !['Shift', 'Control', 'Alt', 'Meta', 'Enter', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Escape', 'Tab'].includes(event.key)) {
         console.log(`[输入翻译 v${SCRIPT_VERSION}][输入打断] 检测到输入,中止当前处理... (按键: ${event.key})`);
         hideStatusDisplay();
         if (currentInputApiXhr && typeof currentInputApiXhr.abort === 'function') { currentInputApiXhr.abort(); }
         else { isTranslatingAndSending = false; console.log(`[输入翻译 v${SCRIPT_VERSION}][输入打断] 已设置 isTranslatingAndSending 为 false。`); }
    } else if (!isTranslatingAndSending) {
         // 输入时隐藏非持久性状态 (保持不变)
         if (statusBarElement && statusBarElement.classList.contains('visible')) {
             const statusSpan = statusBarElement.querySelector('span.status');
             const errorSpan = statusBarElement.querySelector('span.error');
             const successSpan = statusBarElement.querySelector('span.success');
             const infoSpan = statusBarElement.querySelector('span.info');
             // Hide only generic 'status' messages on input, keep error/success/info
             if (statusSpan && !errorSpan && !successSpan && !infoSpan) {
                  hideStatusDisplay();
             }
         }
    }
}

function handleSendButtonClick(event) {
    if (justTranslated) {
        justTranslated = false;
        hideStatusDisplay();
        return; // allow default click send
    }
    let sendButton = event.target.closest(SEND_BUTTON_SELECTOR);
    if (!sendButton) {
        const btn = event.target.closest('button');
        if (btn && btn.textContent.trim().toUpperCase() === 'SEND') {
            sendButton = btn;
        }
    }
    if (!sendButton) return;

    // 查找输入元素:优先包含图片的预览容器中的 caption,fallback 到聊天输入框
    let inputElement = null;
    let el = sendButton;
    while (el && el !== document.body) {
        const img = el.querySelector('img');
        const caption = el.querySelector('div[contenteditable="true"]');
        if (img && caption) { inputElement = caption; break; }
        el = el.parentElement;
    }
    if (!inputElement) {
        inputElement = document.querySelector(INPUT_SELECTOR);
    }
    if (!inputElement) return; // 无输入框, 跳过处理
    const text = inputElement.textContent?.trim() || "";
    const detectedLang = detectLanguage(text);

    // 英文缩写模式下直接替换文本,保留默认发送行为
    if (currentTranslationMode === MODE_ABBREVIATED && detectedLang !== 'Chinese' && detectedLang !== 'Burmese' && text) {
        let finalText = applyLetterAbbreviations(fixNumberAbbreviations(text));
        inputElement.textContent = finalText;
        setCursorToEnd(inputElement);
        inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
        updateStatusDisplay(SUCCESS_ABBREVIATION_APPLIED_MY, 'success', 2000);
        showInlineStatus(inputElement, SUCCESS_ABBREVIATION_APPLIED_MY);
        return; // 保留默认 click 发送
    }
    // 中文或缅甸语时拦截并翻译后发送
    if (text && (detectedLang === 'Chinese' || detectedLang === 'Burmese')) {
        const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? MODE_TEXT_ABBREVIATED_MY : MODE_TEXT_STANDARD_MY;
        console.log(`[输入翻译 v${SCRIPT_VERSION}][发送点击] 检测到 ${detectedLang} 文本。将使用 [${currentModeText}] 模式处理...`);
        event.preventDefault(); event.stopPropagation();
        if (sendButton.disabled) { updateStatusDisplay(ERROR_SEND_BUTTON_DISABLED_MY, 'error', 5000, true, true); return; }
        translateAndSend(text, inputElement, sendButton);
    } else {
        // 其他情况允许默认发送
        if (!isTranslatingAndSending) hideStatusDisplay();
    }
}

// --- 初始化与附加监听器 (保持不变) ---
function initialize() {
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 初始化脚本...`);
    document.body.addEventListener('click', handleSendButtonClick, true);
    const observer = new MutationObserver(mutations => {
        let controlsNeedCheck = false;
        let sendButtonMaybeAppeared = false;
        mutations.forEach(mutation => {
            if (mutation.addedNodes) {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType !== 1) return; // 只处理元素节点
                    // 检查容器
                    const containerNode = node.matches(INPUT_AREA_CONTAINER_SELECTOR) ? node : node.querySelector(INPUT_AREA_CONTAINER_SELECTOR);
                    if(containerNode) controlsNeedCheck = true;
                    // 检查输入框
                    const inputElementNode = node.matches(INPUT_SELECTOR) ? node : node.querySelector(INPUT_SELECTOR);
                    if (inputElementNode && !inputElementNode.dataset.customInputTranslateListener) {
                        attachInputListeners(inputElementNode);
                        controlsNeedCheck = true; // 输入框出现也需要检查控件
                    }
                    // 检查发送按钮
                    const sendButtonNode = node.matches(SEND_BUTTON_SELECTOR) ? node : node.querySelector(SEND_BUTTON_SELECTOR);
                    if(sendButtonNode) sendButtonMaybeAppeared = true;
                });
            }
            // 如果容器自身属性变化,也可能需要检查控件
            if (mutation.target && mutation.target.matches && mutation.target.matches(INPUT_AREA_CONTAINER_SELECTOR)) {
                controlsNeedCheck = true;
            }
        });

        if (controlsNeedCheck) {
            // 使用 setTimeout 稍微延迟执行,确保 DOM 结构稳定
            setTimeout(ensureControlsExist, 50);
        }
        if (sendButtonMaybeAppeared || !sendButtonClickListenerAttached) {
             const sendButton = document.querySelector(SEND_BUTTON_SELECTOR);
             if (sendButton && !sendButton.dataset.customSendClickListener) {
                 attachSendButtonListener(sendButton);
             }
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // 初始检查,以防页面加载时元素已存在
    setTimeout(() => {
        const initialContainer = document.querySelector(INPUT_AREA_CONTAINER_SELECTOR);
        if (initialContainer) { ensureControlsExist(); }
        const initialInputElement = document.querySelector(INPUT_SELECTOR);
        if (initialInputElement && !initialInputElement.dataset.customInputTranslateListener) {
            attachInputListeners(initialInputElement);
        }
        const initialSendButton = document.querySelector(SEND_BUTTON_SELECTOR);
        if(initialSendButton && !initialSendButton.dataset.customSendClickListener) {
            attachSendButtonListener(initialSendButton);
        }
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 初始检查完成,观察者已激活。`);
    }, 1800); // 延迟启动,等待 Telegram Web 加载
}

function attachInputListeners(inputElement) {
     if (inputElement.dataset.customInputTranslateListener) return;
     console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在附加 Keydown 监听器到输入框:`, inputElement);
     inputElement.addEventListener('keydown', handleInputKeyDown, true); // 使用捕获阶段确保优先处理
     inputElement.dataset.customInputTranslateListener = 'true';
     ensureControlsExist(); // 确保控件也存在
}

function attachSendButtonListener(sendButton) {
    if (sendButton.dataset.customSendClickListener) return;
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在附加 Click 监听器到发送按钮:`, sendButton);
    sendButton.addEventListener('click', handleSendButtonClick, true); // 使用捕获阶段确保优先处理
    sendButton.dataset.customSendClickListener = 'true';
    sendButtonClickListenerAttached = true; // 标记已附加监听器

    // 添加一个观察器来检测按钮是否从 DOM 中移除(例如切换聊天时)
    const buttonObserver = new MutationObserver(() => {
        if (!sendButton.isConnected) {
            console.log(`[输入翻译 v${SCRIPT_VERSION}] 发送按钮已从 DOM 移除。重置监听器标志。`);
            buttonObserver.disconnect();
            // 清理标志位和属性,以便下次能重新附加
            if (sendButton.dataset.customSendClickListener) {
                 delete sendButton.dataset.customSendClickListener;
            }
            sendButtonClickListenerAttached = false;
        }
    });
    // 观察按钮的父节点,检测子节点变化
    if (sendButton.parentNode) {
        buttonObserver.observe(sendButton.parentNode, { childList: true, subtree: false });
    } else {
         console.warn(`[输入翻译 v${SCRIPT_VERSION}] 未找到发送按钮的父节点用于观察器。`);
    }

}

// --- 启动初始化 (保持不变) ---
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initialize);
} else {
    initialize();
}

function showInlineStatus(el, msg, duration=2000) {
    const parent = el.parentElement;
    if (!parent) return;
    parent.style.position = parent.style.position || 'relative';
    const tip = document.createElement('div');
    tip.textContent = msg;
    tip.style.cssText = 'position:absolute;top:-24px;right:0;padding:4px 8px;background:rgba(0,0,0,0.7);color:#fff;border-radius:4px;font-size:12px;z-index:500;';
    parent.appendChild(tip);
    setTimeout(() => { if (tip && tip.parentElement) tip.parentElement.removeChild(tip); }, duration);
}

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址