/* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] * Copyright (C) 2024 - 2026 Mic (m@micz.it) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Some original methods derived from https://github.com/KudoAI/chatgpt.js/blob/7eb8463cd61143fa9e1d5a8ec3c14d3c1b286e54/chatgpt.js // Using a full string to inject it in the ChatGPT page to avoid any security error export const mzta_script = ` let force_go = false; let do_force_completion = false; let current_message = null; let current_action = null; let current_tabId = null; let current_mailMessageId = null; let selectionChangeTimeout = null; let isDragging = false; let delay_wait_completion = 7000; // milliseconds let _customTextArray = []; let _currentCustomTextIndex = 0; let lastSelectedHtml = ""; async function chatgpt_sendMsg(msg, method ='') { // return -1 send button not found, -2 textarea not found let textArea = document.getElementById('prompt-textarea') //check if the textarea has been found if(!textArea) { console.error("[ThunderAI] Textarea not found!"); return -2; } // from sept 2024 // Remove existing content while (textArea.firstChild) { textArea.removeChild(textArea.firstChild); } // Parse msg as HTML and append its nodes const parser = new DOMParser(); const doc = parser.parseFromString(msg, 'text/html'); Array.from(doc.body.childNodes).forEach(node => { textArea.appendChild(node.cloneNode(true)); }); textArea.dispatchEvent(new Event('input', { bubbles: true })); //wait for the button to change from the audio button to the send button (from nov-2024) await new Promise(resolve => setTimeout(resolve, 1000)); let sendButton = document.querySelector('[data-testid="send-button"]') // pre-GPT-4o || document.querySelector('path[d*="M15.1918 8.90615C15.6381"]')?.parentNode.parentNode // from sept-2024; || document.querySelector('path[d*="M15.192 8.906a1.143"]')?.parentNode.parentNode; // post-GPT-4o; //check if the sendbutton has been found if (!sendButton) { console.error("[ThunderAI] Send button not found!"); return -1; } const delaySend = setInterval(() => { //console.log(">>>>>>>>>> sendButton disabled: " + sendButton?.hasAttribute('disabled')); if (!sendButton?.hasAttribute('disabled')) { // send msg method.toLowerCase() == 'click' ? sendButton.click() : textArea.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 13, bubbles: true })); clearInterval(delaySend); }else{ //console.error(">>>>>>>>>> The sendButton seems to be disabled! Trying again..."); sendButton = document.querySelector('path[d*="M15.192 8.906a1.143"]')?.parentNode.parentNode // post-GPT-4o; || document.querySelector('[data-testid="send-button"]'); } }, 25); return 0; //everything is ok } async function chatgpt_isIdle() { return new Promise(resolve => { const intervalId = setInterval(() => { if (chatgpt_getRegenerateButton() || do_force_completion) { clearInterval(intervalId); resolve(true); } }, 100);});} function chatgpt_getRegenerateButton() { for (const mainSVG of document.querySelectorAll('main svg.icon')) { if (mainSVG.querySelector('path[d^="M3.502 16.6663V13"]') || mainSVG.querySelector('path[d^="M3.06957"]') || mainSVG.querySelector('path[d^="M10.9153 1.83987L11.2942 1.88772L11.4749"]') || document.querySelector("button[data-testid=good-response-turn-action-button]")){ // regen icon or thumb-up icon found //console.log(">>>>>>>>>> found regen icon!"); return mainSVG.parentNode.parentNode; } } for (const mainSVG of document.querySelectorAll('main svg.icon')) { if (mainSVG.querySelector('path[d^="M9.75122 4.09203C9.75122"]') || mainSVG.querySelector('path[d^="M11 4.9099C11 4.47485"]')){ // read aloud icon found //console.log(">>>>>>>>>> found read aloud icon!"); return mainSVG.parentNode.parentNode; } } } function chatpgt_scrollToBottom () { try { //document.querySelector('button[class*="cursor"][class*="bottom"]').click(); document.querySelector('path[d^="M9.33468 3.33333C9.33468"]')?.parentNode?.parentNode?.click(); } catch (err) { console.error('[ThunderAI] ', err); } } function addCustomDiv(prompt_action,tabId,mailMessageId) { // Create