// ==UserScript==
// @name AI Everywhere
// @namespace OperaBrowserGestures
// @description Highly customizable mini A.I. floating menu that can define words, answer questions, translate, and much more in a single click and with your custom prompts. Includes useful click to search on Google and copy selected text buttons, along with Rocker+Mouse Gestures and Units+Currency Converters, all features can be easily modified or disabled.
// @version 61
// @author hacker09
// @include *
// @exclude https://accounts.google.com/v3/signin/*
// @icon https://i.imgur.com/8iw8GOm.png
// @grant GM_registerMenuCommand
// @grant GM.xmlHttpRequest
// @grant GM_deleteValue
// @grant GM_openInTab
// @grant window.close
// @run-at document-end
// @grant GM_setValue
// @grant GM_getValue
// @connect google.com
// @connect generativelanguage.googleapis.com
// @require https://cdnjs.cloudflare.com/ajax/libs/marked/13.0.2/marked.min.js
// ==/UserScript==
const BypassTT = window.trustedTypes?.createPolicy('BypassTT', { createHTML: HTML => HTML }); //Bypass trustedTypes
if (GM_getValue("APIKey") === undefined || GM_getValue("APIKey") === null || GM_getValue("APIKey") === '') { //If the API Key isn't already set
window.onload = function() { //Onload
if (location.href === 'https://aistudio.google.com/app/apikey' && document.querySelector(".apikey-link") !== null) { //If the user is on the API Key site and already created an API Key
setTimeout(function() { //Start the setTimeout function
document.querySelectorAll(".apikey-link")[1].click(); //Click on the API Key
setTimeout(function() { //Start the setTimeout function
GM_setValue("APIKey", document.querySelector(".apikey-text").innerText); //Store the API Key
(GM_getValue("APIKey") !== undefined && GM_getValue("APIKey") !== null && GM_getValue("APIKey") !== '') ? alert('API Key automatically added!') : alert('Failed to automatically add API Key!'); //Show a message
}, 500); //Finish the setTimeout function
}, 500); //Finish the setTimeout function
} //Finish the if condition
}; //Finish the onload event listener
} //Finish the if condition
// Mouse Gestures _________________________________________________________________________________________________________________________________________________________
GM_registerMenuCommand("Enable/Disable Mouse Gestures", MouseGestures); //Adds an option to the tampermonkey menu
if (GM_getValue("MouseGestures") !== true && GM_getValue("MouseGestures") !== false) { //If MouseGestures isn't already set
GM_setValue("MouseGestures", true); //Enable the feature
} //Finish the if condition
function MouseGestures() //Enable/disable MouseGestures
{ //Start the function MouseGestures
if (GM_getValue("MouseGestures") === true) { //If it's enabled, disable it
GM_setValue("MouseGestures", false); //Disable the feature
} //Finish the if condition
else { //If it's disabled, enable it
GM_setValue("MouseGestures", true); //Enable the feature
location.reload(); //Reload the page
} //Finish the else condition
} //Finish the function MouseGestures
if (GM_getValue("MouseGestures") === true) //If the MouseGestures is enabled
{ //Start the if condition
const SENSITIVITY = 3; //Adjust the script mouse sensitivity here between 1 ~ 5
const TOLERANCE = 3; //Adjust the script mouse tolerance here between 1 ~ 5
const funcs = { //Store the MouseGestures functions
'L': function() { //Run when the mouse movement Left is performed
window.history.back(); //Go Back
}, //Finish the mouse movement Left
'R': function() { //Run when the mouse movement Right is performed
window.history.forward(); //Go Forward
}, //Finish the mouse movement Right
'D': function() { //Run when the mouse movement Down is performed
if (IsShiftNotPressed === true) { //If the shift key isn't being pressed
GM_openInTab(link, { //Open the link on a new tab
active: true, //Focus on the new tab
insert: true, //Insert the new tab after the actual tab
setParent: true //When closed return to the previous tab
}); //Open the link that was hovered
} //Finish the if condition
}, //Finish the mouse movement Down
'UD': function() { //Run when the mouse movement Up+Down is performed
location.reload(); //Reload the Tab
}, //Finish the mouse movement Up+Down
'DR': function(e) { //Run when the mouse movement Down+Right is performed
top.close(); //Close the tab
e.preventDefault(); //Disable the context menu
e.stopPropagation(); //Disable the context menu
}, //Finish the mouse movement Down+Right
'DU': function() { //Run when the mouse movement Down+Up is performed
GM_openInTab(link, { //Open the link that was hovered
active: false, //Don't focus on the new tab
insert: true, //Insert the new tab after the actual tab
setParent: true //Return to the tab the user was in
}); //Open the link that was hovered on a new background tab
} //Finish the mouse movement Down+Up
}; //Finish the variable to store the functions
//Math codes to track the mouse movement gestures
const s = 1 << ((7 - SENSITIVITY) << 1);
const t1 = Math.tan(0.15708 * TOLERANCE),t2 = 1 / t1;
let x, y, path;
const tracer = function(e) { //Start the const tracer
let cx = e.clientX, cy = e.clientY, deltaX = cx - x, deltaY = cy - y, distance = deltaX * deltaX + deltaY * deltaY;
if (distance > s) {
let slope = Math.abs(deltaY / deltaX), direction = '';
if (slope > t1) {
direction = deltaY > 0 ? 'D' : 'U';
} else if (slope <= t2) {
direction = deltaX > 0 ? 'R' : 'L';
}
if (path.charAt(path.length - 1) !== direction) {
path += direction;
}
x = cx;
y = cy;
}
}; //Finish the const tracer
window.addEventListener('mousedown', function(e) { //When the mouse is clicked
if (e.which === 3) { //Start the if condition
x = e.clientX;
y = e.clientY;
path = "";
window.addEventListener('mousemove', tracer, false); //Detect the mouse position
} //Finish the if condition
}, false); //Finish the event listener
var IsShiftNotPressed = true; //Hold the shift key status
window.addEventListener("contextmenu", function(e) { //When the shift key is/isn't pressed
if (e.shiftKey) { //If the shift key was pressed
IsShiftNotPressed = false; //Hold the shift key status
open(link, '_blank', 'height=' + screen.height + ',width=' + screen.width); //Open the link on a new window
} //Finish the if condition
if (LeftClicked === true) { //If the Left Click was released when the Rocker Mouse Gestures were enabled
e.preventDefault(); //Disable the context menu
e.stopPropagation(); //Disable the context menu
} //Finish the if condition
setTimeout(function() { //Start the setTimeout function
IsShiftNotPressed = true; //Hold the shift key status
}, 500); //Finish the setTimeout function
}, false); //Finish the event listener
window.addEventListener('contextmenu', function(e) { //When the right click BTN is released
window.removeEventListener('mousemove', tracer, false); //Track the mouse movements
if (path !== "") { //Start the if condition
e.preventDefault(); //Disable the context menu
if (funcs.hasOwnProperty(path)) { //Start the if condition
funcs[path]();
} //Finish the if condition
} //Finish the if condition
}, false); //Finish the event listener
var link; //Make the variable global
Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseover = function() { //Add an event listener to all link elements
link = this.href; //Store the hovered link to a variable
}); //Finish the forEach
Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseout = function() { //Add an event listener to all link elements
const PreviousLink = link; //Save the hovered link to another variable
setTimeout(function() { //Start the setTimeout function
if (PreviousLink === link) //If the hovered link is still the same as the previously hovered Link
{ //Start the if condition
link = 'about:newtab'; //Make the script open a new browser tab when the mouse leaves any link that was hovered
} //Finish the if condition
}, 200); //Finish the setTimeout function
}); //Finish the forEach
} //Finish the if condition
//Rocker Mouse Gesture Settings _________________________________________________________________________________________________________________________________________________________
GM_registerMenuCommand("Enable/Disable Rocker Mouse Gestures", RockerMouseGestures); //Adds an option to the tampermonkey menu
if (GM_getValue("RockerMouseGestures") !== true && GM_getValue("RockerMouseGestures") !== false) { //If RockerMouseGestures isn't already set
GM_setValue("RockerMouseGestures", false); //Disable the feature
} //Finish the if condition
function RockerMouseGestures() //Enable/disable RockerMouseGestures
{ //Start the function RockerMouseGestures
if (GM_getValue("RockerMouseGestures") === true) { //If it's enabled, disable it
GM_setValue("RockerMouseGestures", false); //Disable the feature
} //Finish the if condition
else { //If it's disabled, enable it
GM_setValue("RockerMouseGestures", true); //Enable the feature
location.reload(); //Reload the page
} //Finish the else condition
} //Finish the function RockerMouseGestures
if (GM_getValue("RockerMouseGestures") === true || GM_getValue("SearchHiLight") === true) //If the RockerMouseGestures or the SearchHiLight is enabled
{ //Start the if condition
var LeftClicked, RightClicked; //Create global variables
window.addEventListener("mousedown", function(e) { //Detect the right and left mouse clicks presses on the page
switch (e.button) { //Start the switch condition
case 0: //If Left Click was Pressed
LeftClicked = true; //Set the variable LeftClicked as true
break;
case 2: //If Right Click was Pressed
RightClicked = true; //Set the variable RightClicked as true
break;
} //Finish the switch condition
}, false); //Finish the event listener mouse down
window.addEventListener("mouseup", function(e) { //Detect the right and left mouse clicks releases on the page
switch (e.button) { //Start the switch condition
case 0: //If Left Click was released
LeftClicked = false; //Set the variable LeftClicked as false
break;
case 2: //If Right Click was released
RightClicked = false; //Set the variable RightClicked as false
break;
} //Finish the switch condition
if (LeftClicked && RightClicked === false) { //If Left was Clicked and then Right Click was released
history.back(); //Go Back
} //Finish the if condition
if (RightClicked && LeftClicked === false) { //If Right was Clicked and then Left Click was released
history.forward(); //Go Forward
} //Finish the if condition
}, false); //Finish the event listener mouse up
} //Finish the if condition
//SearchHighLight + CurrenciesConverter + UnitsConverter _______________________________________________________________________________________________________________________________________
GM_registerMenuCommand("Enable/Disable SearchHiLight", SearchHiLight); //Adds an option to the tampermonkey menu
if (GM_getValue("SearchHiLight") !== true && GM_getValue("SearchHiLight") !== false) { //If SearchHiLight isn't already set
GM_setValue("SearchHiLight", true); //Enable the feature
} //Finish the if condition
if (GM_getValue("CurrenciesConverter") !== true && GM_getValue("CurrenciesConverter") !== false) { //If CurrenciesConverter isn't already set
GM_setValue("CurrenciesConverter", true); //Enable the feature
} //Finish the if condition
if (GM_getValue("UnitsConverter") !== true && GM_getValue("UnitsConverter") !== false) { //If UnitsConverter isn't already set
GM_setValue("UnitsConverter", true); //Enable the feature
} //Finish the if condition
function SearchHiLight() //Enable/disable the SearchHiLight and the Currency/Unit converters
{ //Start the function SearchHiLight
if (GM_getValue("SearchHiLight") === true) { //If it's enabled, disable it
GM_setValue("SearchHiLight", false); //Disable the feature
GM_setValue("CurrenciesConverter", false); //Disable the feature
GM_deleteValue('YourLocalCurrency'); //Remove the YourLocalCurrency variable off the tampermonkey storage
GM_setValue("UnitsConverter", false); //Disable the feature
} //Finish the if condition
else { //If it's disabled, enable it
GM_setValue("SearchHiLight", true); //Enable the feature
if (confirm('If you want to enable the Currency Converter press OK.')) //Confirm to enable/disable feature
{ //Start the if condition
GM_setValue("CurrenciesConverter", true); //Enable the feature
} //Finish the if condition
else //If the user presses cancel
{ //Start the else condition
GM_setValue("CurrenciesConverter", false); //Disable the feature
} //Finish the else condition
if (confirm('If you want to enable the Units Converter press OK.')) //Confirm to enable/disable feature
{ //Start the if condition
GM_setValue("UnitsConverter", true); //Enable the feature
} //Finish the if condition
else //If the user presses cancel
{ //Start the else condition
GM_setValue("UnitsConverter", false); //Disable the feature
} //Finish the else condition
location.reload(); //Reload the page
} //Finish the else condition
} //Finish the function SearchHiLight
if (GM_getValue("SearchHiLight") === true) //If the SearchHiLight is enabled
{ //Start the if condition
var SelectedTextIsLink; //Create a global variable
const Links = new RegExp(/\.org|\.ly|\.net|\.co|\.tv|\.me|\.biz|\.club|\.site|\.br|\.gov|\.io|\.jp|\.edu|\.au|\.in|\.it|\.ca|\.mx|\.fr|\.tw|\.il|\.uk|\.zoom\.us|\youtu.be/i); //Create a global variable to check if the selected text is a link
var FinalCurrency, SelectedText, SelectedTextSearch = ''; //Create global variables
window.addEventListener('load', function() { //Start the function
document.body.addEventListener('mouseup', function() { //When the user releases the mouse click after selecting something
SelectedText = getSelection().toString(); //Store the selected text
SelectedTextSearch = getSelection().toString().replaceAll('&', '%26'); //Store the selected text to be opened on Google
//CurrenciesConverter _______________________________________________________________________________________________________________________________________
if (GM_getValue("CurrenciesConverter") === true) { //If Currencies Converter is enabled
shadowRoot.querySelector("#ShowCurrencyORUnits").innerText = ''; //Remove the previous Currency text
shadowRoot.querySelectorAll('.AI-BG-box button')[1].style.marginTop = '34%'; //Bring the Translate AI box to it's original position
const Currencies = new RegExp(/^[ \t\xA0]*(?=.*?(\d+(?:.\d+)?))(?=(?:\1[ \t\xA0]*)?(Dólares|dolares|dólares|dollars|AUD|BGN|BRL|BCH|BTC|BYN|CAD|CHF|CNY|CZK|DKK|EUR|EGP|ETH|GBP|GEL|HKD|HRK|HUF|IDR|ILS|INR|JPY|LTC|KRW|MXN|MYR|NOK|NZD|PHP|PLN|RON|RM|RUB|SEK|SGD|THB|TRY|USD|UAH|ZAR|KZT|YTL|\$|R\$|HK\$|US\$|\$US|¥|€|Rp|kn|Kč|kr|zł|£|฿|₩))(?:\1[ \t\xA0]*\2|\2[ \t\xA0]*\1)[ \t\xA0]*$/i); //Regex to check if the selected text is a currency
if (SelectedText.match(Currencies) !== null) //If the selected text is a currency
{ //Start the if condition
if (GM_getValue("YourLocalCurrency") === undefined) { //If the Local Currency hasn't been set
var UserInput = prompt('Write your local currency.\nThe script will always use your local currency to make exchange-rate conversions.\n\n*Currency input examples:\nBRL\nCAD\nUSD\netc...\n\n*Press OK'); //Get the user input
GM_setValue("YourLocalCurrency", UserInput); //Store the user local currency
} //Finish the if condition
(async () => { //Async function to get the final converted currency value
var CurrencySymbol = SelectedText.match(Currencies)[2]; //Store the currency symbol supposing "it's correct"
const CurrencySymbols = new RegExp(/\$|R\$|HK\$|US\$|\$US|¥|€|Rp|kn|Kč|kr|zł|£|฿|₩/i); //Create a variable to check for the selected currency symbols
if (SelectedText.match(Currencies)[2].match(CurrencySymbols) !== null) //If the selected currency contains a symbol
{ //Start the if condition
switch (SelectedText.match(CurrencySymbols)[0].toLowerCase()) { //If the selected currency contains a symbol
case '$': //Get the selected currency symbol
case 'us$': //Get the selected currency symbol
case '$us': //Get the selected currency symbol
CurrencySymbol = 'USD'; //"Convert" the symbol to the Currency Letters
break;
case 'r$': //Get the selected currency symbol
CurrencySymbol = 'BRL'; //"Convert" the symbol to the Currency Letters
break;
case 'hk$': //Get the selected currency symbol
CurrencySymbol = 'HKD'; //"Convert" the symbol to the Currency Letters
break;
case "¥": //Get the selected currency symbol
CurrencySymbol = 'JPY'; //"Convert" the symbol to the Currency Letters
break;
case '€': //Get the selected currency symbol
CurrencySymbol = 'EUR'; //"Convert" the symbol to the Currency Letters
break;
case 'rp': //Get the selected currency symbol
CurrencySymbol = 'IDR'; //"Convert" the symbol to the Currency Letters
break;
case 'kn': //Get the selected currency symbol
CurrencySymbol = 'HRK'; //"Convert" the symbol to the Currency Letters
break;
case 'kč': //Get the selected currency symbol
CurrencySymbol = 'CZK'; //"Convert" the symbol to the Currency Letters
break;
case 'kr': //Get the selected currency symbol
CurrencySymbol = 'DKK'; //"Convert" the symbol to the Currency Letters
break;
case 'zł': //Get the selected currency symbol
CurrencySymbol = 'PLN'; //"Convert" the symbol to the Currency Letters
break;
case '£': //Get the selected currency symbol
CurrencySymbol = 'GBP'; //"Convert" the symbol to the Currency Letters
break;
case '฿': //Get the selected currency symbol
CurrencySymbol = 'THB'; //"Convert" the symbol to the Currency Letters
break;
case '₩': //Get the selected currency symbol
CurrencySymbol = 'KRW'; //"Convert" the symbol to the Currency Letters
break;
} //Finish the switch condition
} //Finish the if condition
GM.xmlHttpRequest({ //Make a request to grab the final converted currency value
method: "GET",
url: `https://www.google.com/search?q=${SelectedText.match(Currencies)[1]} ${CurrencySymbol} in ${GM_getValue("YourLocalCurrency")}`,
onload: (response) => {
const newDocument = new DOMParser().parseFromString(response.responseText, 'text/html'); //Parses the fetch response
const FinalCurrency = parseFloat(newDocument.querySelector(".SwHCTb").innerText.split(' ')[0].replaceAll(',', '')); //Store the FinalCurrency and erase all commas
shadowRoot.querySelectorAll('.AI-BG-box button')[1].style.marginTop = '23%'; //Bring the Translate AI box to the top
if (SelectedText.match(Currencies)[2].match(CurrencySymbols) !== null) { //If the selected currency contains a symbol
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(CurrencySymbol + ' 🠂 ' + Intl.NumberFormat(navigator.language, {
style: 'currency',
currency: GM_getValue("YourLocalCurrency")
}).format(FinalCurrency) + '<span style=" color: #7B7D7F;"> │</span>'); //Show the FinalCurrency
} else { //If the selected currency contains no symbol
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(Intl.NumberFormat(navigator.language, {
style: 'currency',
currency: GM_getValue("YourLocalCurrency")
}).format(FinalCurrency) + '<span style=" color: #7B7D7F;"> │</span>'); //Show the FinalCurrency
}
var htmlcode = shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML; //Save the currency html
shadowRoot.querySelector("#ShowCurrencyORUnits").onmousemove = function() { //When the mouse hovers the currency
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)('Copy<span style=" color: #7B7D7F;"> │</span>'); //Change the element text to copy
}; //Finish the onmousemove event listener
shadowRoot.querySelector("#ShowCurrencyORUnits").onmouseout = function() { //When the mouse leaves the currency
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(htmlcode); //Return the previous converted currency html
}; //Finish the onmouseout event listener
shadowRoot.querySelector("#ShowCurrencyORUnits").onclick = function() { //When the user clicks on the currency
shadowRoot.querySelectorAll('.AI-BG-box button')[1].style.marginTop = '23%'; //Bring the Translate AI box to the top
navigator.clipboard.writeText(Intl.NumberFormat(navigator.language, {
style: 'currency',
currency: GM_getValue("YourLocalCurrency")
}).format(FinalCurrency)); //Copy the Final Currency
}; //Finish the onclick event listener
}
});
})(); //Finish the async function
} //Finish the if condition
} //Finish the if condition
//UnitsConverter _________________________________________________________________________________________________________________________________________________________________________
if (GM_getValue("UnitsConverter") === true) { //If the Units Converter option is enabled
shadowRoot.querySelectorAll('.AI-BG-box button')[1].style.marginTop = '34%'; //Bring the Translate AI box to its original position
shadowRoot.querySelector("#ShowCurrencyORUnits").innerText = ''; //Remove the previous Units text
const Units = new RegExp(/^[ \t\xA0]*(-?\d+(?:[., ]\d+)?)[ \t\xA0]*("|inch|inches|in|cms?|centimeters?|meters?|ft|kg|lbs?|pounds?|kilograms?|ounces?|g|ozs?|fl oz|fl oz (us)|fluid ounces?|kphs?|km\/h|kilometers per hours?|mphs?|meters per hours?|°?º?[CF]|km\/hs?|ml|milliliters?|l|liters?|litres?|gal|gallons?|yards?|yd|Millimeter|millimetre|kilometers?|mi|mm|miles?|km|ft|fl|feets?|mts?|grams?|kilowatts?|kws?|brake horsepower|mechanical horsepower|hps?|bhps?|miles per gallons?|mpgs?|liters per 100 kilometers?|l\/100km|liquid quarts?|lqs?|foot-?pounds?|ft-?lbs?|lb fts?|newton-?meters?|nm|\^\d+)[ \t\xA0]*(?:\(\w+\)[ \t\xA0]*)?$/i); //Create a variable to check if the selected text has units
if (SelectedText.match(Units) !== null) //If the selected text is an unit
{ //Start the if condition
const SelectedUnitValue = SelectedText.match(Units)[1].replaceAll(',', '.'); //Get the selected unit value and store the value to a variable
switch (SelectedText.match(Units)[2].toLowerCase()) { //Set all letters to Lower Case and convert the selected unit
case 'inch': //Get the unit type
case 'inches': //Get the unit type
case 'in': //Get the unit type
case '"': //Get the unit type
var NewUnit = 'cm'; //"Convert" the current unit
var ConvertedUnit = parseFloat(SelectedUnitValue * 2.54).toFixed(2); //Store the converted unit result
break;
case 'centimeter': //Get the unit type
case 'centimeters': //Get the unit type
case 'cm': //Get the unit type
case 'cms': //Get the unit type
NewUnit = 'in'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 2.54).toFixed(2); //Store the converted unit result
break;
case 'mt': //Get the unit type
case 'mts': //Get the unit type
case 'meters': //Get the unit type
case 'meter': //Get the unit type
NewUnit = 'ft'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 3.281).toFixed(2); //Store the converted unit result
break;
case 'kg': //Get the unit type
case 'kilograms': //Get the unit type
case 'kilogram': //Get the unit type
NewUnit = 'lb'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 2.205).toFixed(2); //Store the converted unit result
break;
case 'pound': //Get the unit type
case 'pounds': //Get the unit type
case 'lb': //Get the unit type
case 'lbs': //Get the unit type
NewUnit = 'kg'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 2.205).toFixed(2); //Store the converted unit result
break;
case 'ounce': //Get the unit type
case 'ounces': //Get the unit type
case 'oz': //Get the unit type
case 'ozs': //Get the unit type
NewUnit = 'g'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 28.35).toFixed(2); //Store the converted unit result
break;
case 'g': //Get the unit type
case 'gram': //Get the unit type
case 'grams': //Get the unit type
NewUnit = 'oz'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 28.35).toFixed(2); //Store the converted unit result
break;
case 'kilometer': //Get the unit type
case 'kilometers': //Get the unit type
NewUnit = 'mi'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 1.609).toFixed(2); //Store the converted unit result
break;
case 'kph': //Get the unit type
case 'kphs': //Get the unit type
case 'km/h': //Get the unit type
case 'km/hs': //Get the unit type
case 'kilometers per hour': //Get the unit type
case 'kilometers per hours': //Get the unit type
NewUnit = 'mph'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 1000).toFixed(2); //Store the converted unit result
break;
case 'mph': //Get the unit type
case 'mphs': //Get the unit type
case 'meters per hour': //Get the unit type
case 'meters per hours': //Get the unit type
NewUnit = 'km/h'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 1.000).toFixed(2); //Store the converted unit result
break;
case 'mi': //Get the unit type
case 'mile': //Get the unit type
case 'miles': //Get the unit type
NewUnit = 'km'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 1.609).toFixed(2); //Store the converted unit result
break;
case '°c': //Get the unit type
NewUnit = '°F'; //"Convert" the current unit
ConvertedUnit = parseFloat((SelectedUnitValue * 9 / 5) + 32).toFixed(2); //Store the converted unit result
break;
case '°f': //Get the unit type
NewUnit = '°C'; //"Convert" the current unit
ConvertedUnit = parseFloat((SelectedUnitValue - 32) * 5 / 9).toFixed(2); //Store the converted unit result
break;
case 'ºc': //Get the unit type
NewUnit = 'ºF'; //"Convert" the current unit
ConvertedUnit = parseFloat((SelectedUnitValue * 9 / 5) + 32).toFixed(2); //Store the converted unit result
break;
case 'ºf': //Get the unit type
NewUnit = 'ºC'; //"Convert" the current unit
ConvertedUnit = parseFloat((SelectedUnitValue - 32) * 5 / 9).toFixed(2); //Store the converted unit result
break;
case 'ml': //Get the unit type
case 'milliliter': //Get the unit type
case 'milliliters': //Get the unit type
NewUnit = 'fl oz (US)'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 29.574).toFixed(2); //Store the converted unit result
break;
case 'fl oz (US)': //Get the unit type
case 'fl oz': //Get the unit type
case 'fl': //Get the unit type
case 'fluid ounce': //Get the unit type
case 'fluid ounces': //Get the unit type
NewUnit = 'ml'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 29.574).toFixed(2); //Store the converted unit result
break;
case 'l': //Get the unit type
case 'litre': //Get the unit type
case 'liter': //Get the unit type
case 'litres': //Get the unit type
case 'liters': //Get the unit type
NewUnit = 'gal (US)'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 3.785).toFixed(2); //Store the converted unit result
break;
case 'gal': //Get the unit type
case 'gallon': //Get the unit type
case 'gallons': //Get the unit type
NewUnit = 'lt'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 3.785).toFixed(2); //Store the converted unit result
break;
case 'yard': //Get the unit type
case 'yards': //Get the unit type
case 'yd': //Get the unit type
NewUnit = 'm'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 1.094).toFixed(2); //Store the converted unit result
break;
case 'mm': //Get the unit type
case 'millimetre': //Get the unit type
case 'Millimeters': //Get the unit type
NewUnit = 'in'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 25.4).toFixed(2); //Store the converted unit result
break;
case 'ft': //Get the unit type
case 'feet': //Get the unit type
case 'feets': //Get the unit type
NewUnit = 'mt'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 0.3048).toFixed(2); //Store the converted unit result
break;
case 'kw': //Get the unit type
case 'kws': //Get the unit type
case 'kilowatt': //Get the unit type
case 'kilowatts': //Get the unit type
NewUnit = 'mhp'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 1.341).toFixed(2); //Store the converted unit result
break;
case 'mhp': //Get the unit type
case 'mhps': //Get the unit type
case 'hp': //Get the unit type
case 'hps': //Get the unit type
case 'brake horsepower': //Get the unit type
case 'mechanical horsepower': //Get the unit type
NewUnit = 'kw'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 1.341).toFixed(2); //Store the converted unit result
break;
case 'mpg': //Get the unit type
case 'mpgs': //Get the unit type
case 'miles per gallon': //Get the unit type
case 'miles per gallons': //Get the unit type
NewUnit = 'l/100km'; //"Convert" the current unit
ConvertedUnit = parseFloat(235.215 / SelectedUnitValue).toFixed(2); //Store the converted unit result
break;
case 'l/100km': //Get the unit type
case 'liters per 100 kilometer': //Get the unit type
case 'liters per 100 kilometers': //Get the unit type
NewUnit = 'US mpg'; //"Convert" the current unit
ConvertedUnit = parseFloat(235.215 / SelectedUnitValue).toFixed(2); //Store the converted unit result
break;
case 'lq': //Get the unit type
case 'lqs': //Get the unit type
case 'liquid quart': //Get the unit type
case 'liquid quarts': //Get the unit type
NewUnit = 'l'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 1.057).toFixed(2); //Store the converted unit result
break;
case 'liter': //Get the unit type
case 'liters': //Get the unit type
NewUnit = 'lqs'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 1.057).toFixed(2); //Store the converted unit result
break;
case 'foot-pound': //Get the unit type
case 'foot-pounds': //Get the unit type
case 'foot pound': //Get the unit type
case 'foot pounds': //Get the unit type
case 'ft-lbs': //Get the unit type
case 'ft-lb': //Get the unit type
case 'ft lbs': //Get the unit type
case 'ft lb': //Get the unit type
case 'lb ft': //Get the unit type
case 'lb fts': //Get the unit type
NewUnit = 'Nm'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue * 1.3558179483).toFixed(2); //Store the converted unit result
break;
case 'newton-meter': //Get the unit type
case 'newton-meters': //Get the unit type
case 'newton meter': //Get the unit type
case 'newton meters': //Get the unit type
case 'nm': //Get the unit type
NewUnit = 'ft lb'; //"Convert" the current unit
ConvertedUnit = parseFloat(SelectedUnitValue / 1.3558179483).toFixed(2); //Store the converted unit result
break;
case (SelectedText.match(Units)[2].replaceAll(',', '.').match(/\^/)).input: //Get the unit type
NewUnit = 'power'; //"Convert" the current unit
ConvertedUnit = Math.pow(parseFloat(SelectedUnitValue), parseFloat(SelectedText.split('^')[1])); //Store the converted unit result
break;
} //Finish the switch condition
setTimeout(function() { //Start the setTimeout function
shadowRoot.querySelectorAll('.AI-BG-box button')[1].style.marginTop = '23%'; //Bring the Translate AI box to the top
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(ConvertedUnit + ' ' + NewUnit + '<span style=" color: #7B7D7F;"> │</span> '); //Show the converted unit results
var htmlcode = shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML; //Save the converted unit value
shadowRoot.querySelector("#ShowCurrencyORUnits").onmousemove = function() { //When the mouse hovers the unit
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)('Copy<span style=" color: #7B7D7F;"> │</span>'); //Change the element text to copy
}; //Finish the onmousemove event listener
shadowRoot.querySelector("#ShowCurrencyORUnits").onmouseout = function() { //When the mouse leaves the unit
shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(htmlcode); //Return the previous html
}; //Finish the onmouseout event listener
shadowRoot.querySelector("#ShowCurrencyORUnits").onclick = function() { //When the unit is clicked
shadowRoot.querySelectorAll('.AI-BG-box button')[1].style.marginTop = '23%'; //Bring the Translate AI box to the top
navigator.clipboard.writeText(ConvertedUnit); //Copy the Final converted unit value
}; //Finish the onclick event listener
}, 0); //Finish the setTimeout
} //Finish the if condition
} //Finish the if condition
//Menu ___________________________________________________________________________________________________________________________________________________________________________
if (shadowRoot.querySelector("#SearchBTN").innerText === 'Open') //If the Search BTN text is 'Open'
{ //Start the if condition
shadowRoot.querySelector("#highlight_menu > ul").style.paddingInlineStart = '19px'; //Increase the menu size
shadowRoot.querySelector("#SearchBTN").innerText = 'Search'; //The next time that the menu is shown display the BTN text as Search again
shadowRoot.querySelector("#OpenAfter").remove(); //Remove custom Open white hover overlay
SelectedTextIsLink = false; //Make common words searchable again
} //Finish the if condition
if (SelectedText.match(Links) !== null) //If the selected text is a link
{ //Start the if condition
SelectedTextIsLink = true; //Declare that it's a link
shadowRoot.querySelector("#highlight_menu > ul").style.paddingInlineStart = '27px'; //Increase the menu size
shadowRoot.querySelector("#SearchBTN").innerText = 'Open'; //Change the BTN text to Open
shadowRoot.innerHTML += ` <style id="OpenAfter"> #SearchBTN::after { width: 225% !important; height: 221% !important; transform: translate(-48%, -71%) !important; } </style> `; //Add custom Open white hover overlay
} //Finish the if condition
const menu = shadowRoot.querySelector("#highlight_menu"); //Store menu element
if (document.getSelection().toString().trim() !== '') { //If text has been selected
const p = document.getSelection().getRangeAt(0).getBoundingClientRect(); //Store the positions
menu.style.display = ''; //Show the menu
menu.offsetHeight; //Trigger reflow by forcing a style calculation
menu.style.left = p.left + (p.width / 2) - (menu.offsetWidth / 2) + 'px'; //Position menu horizontally
menu.style.top = p.top - menu.offsetHeight - 10 + 'px'; //Position menu vertically
menu.classList.add('highlight_menu_animate'); //Add animation class
return; //Exit if text is selected
}
menu.style.display = 'none'; //Hide the menu
}); //Finish the mouse up event listener
}); //Finish the function
//AI Menu ___________________________________________________________________________________________________________________________________________________________________________
var audio, Generating, isRecognizing = false; //Declare global variables
const HtmlMenu = document.createElement('div'); //Create a container div
HtmlMenu.setAttribute('style', `width: 0px; height: 0px; display: block;`); //Hide the container div by default
const shadowRoot = HtmlMenu.attachShadow({ mode: 'closed' }); //Create a closed shadow
const BGColor = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'rgb(37, 36, 53)' : '#e7edf1'; //Change AI theme according to the browser theme
const IMGsColor = BGColor === '#e7edf1' ? 'filter: invert(1)' : ''; //If on white mode invert black colors to white
const TextColor = BGColor === '#e7edf1' ? 'black' : 'white'; //According to the browser theme change the AI menu text color
const UniqueLangs = navigator.languages.filter((l, i, arr) => !arr.slice(0, i).some(e => e.split('-')[0].toLowerCase() === l.split('-')[0].toLowerCase()) ); //Filter unique languages
const Lang = UniqueLangs.length > 1 ? `${UniqueLangs[0]} and into ${UniqueLangs[1]}` : UniqueLangs[0]; //Use 1 or 2 languages
const GeminiSVG = '<svg viewBox="0 0 32 32" fill="none"> <path d="M14 28C14 26.0633 13.6267 24.2433 12.88 22.54C12.1567 20.8367 11.165 19.355 9.905 18.095C8.645 16.835 7.16333 15.8433 5.46 15.12C3.75667 14.3733 1.93667 14 0 14C1.93667 14 3.75667 13.6383 5.46 12.915C7.16333 12.1683 8.645 11.165 9.905 9.905C11.165 8.645 12.1567 7.16333 12.88 5.46C13.6267 3.75667 14 1.93667 14 0C14 1.93667 14.3617 3.75667 15.085 5.46C15.8317 7.16333 16.835 8.645 18.095 9.905C19.355 11.165 20.8367 12.1683 22.54 12.915C24.2433 13.6383 26.0633 14 28 14C26.0633 14 24.2433 14.3733 22.54 15.12C20.8367 15.8433 19.355 16.835 18.095 18.095C16.835 19.355 15.8317 20.8367 15.085 22.54C14.3617 24.2433 14 26.0633 14 28Z" fill="url(#paint)"></path></svg>'; //Store the GeminiSVG
shadowRoot.innerHTML = (html => BypassTT?.createHTML(html) || html)(`<svg width=" 0" height=" 0"> <defs> <radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.77876 11.3795) rotate(18.6832) scale(29.8025 238.737)" id="paint"> <stop offset="0.0671246" stop-color="#9168C0"></stop> <stop offset="0.342551" stop-color="#5684D1"></stop> <stop offset="0.672076" stop-color="#1BA1E3"></stop> </radialGradient> </defs> </svg><style> .show-button { animation: growAndFade 0.2s ease-out forwards; } @keyframes growAndFade { 0% { transform: scale(0.3) translate(0%, 0%); opacity: 0; } 20% { transform: scale(0.4) translate(1%, 1%); opacity: 0.2; } 40% { transform: scale(0.5) translate(2%, 2%); opacity: 0.4; } 60% { transform: scale(0.7) translate(3%, 3%); opacity: 0.6; } 80% { transform: scale(0.9) translate(4%, 4%); opacity: 0.8; } 100% { transform: scale(1) translate(5%, 5%); opacity: 1; } } .MenuGemini > svg { width: 45px; height: 25px; margin-left: -12px; margin-right: -15px; } #ShowCurrencyORUnits { position: relative; } #ShowCurrencyORUnits::after { content: ""; background-color: rgba(255, 255, 255, 0.4); width: 133%; height: 217%; position: absolute; top: -9px; left: -19px; pointer-events: none; border-bottom-left-radius: 10px; display: none;} #ShowCurrencyORUnits:hover::after { display: block; } :host { all: initial; } #SearchBTN { position: relative; } #SearchBTN::after { background-color: rgb(255 255 255 / 40%); width: 168%; height: 220%; transform: translate(-43%, -73%); pointer-events: none; border-color: unset; border-style: unset; border-bottom-left-radius: 10px; display: none; } #SearchBTN:hover::after { display: block; /* Show on hover */ } #CopyBTN { position: relative; } #CopyBTN::after { background-color: rgb(255 255 255 / 40%); width: 131%; height: 220%; transform: translate(-13%, -73%); pointer-events: none; border-color: unset; border-style: unset; border-bottom-right-radius: 10px; display: none; } #CopyBTN:hover::after { display: block; /* Show on hover */ } ::-webkit-scrollbar { width: 7px;} ::-webkit-scrollbar-thumb { background: #484d65; border-radius: 3px; } .popuptext::after { content: ""; top: 100%; left: 50%; margin-left: -10px; border-top-width: 10px; border-right-width: 10px; border-left-width: 10px; position: absolute; border-style: solid; border-color: #575959 transparent transparent transparent; } .AI-BG-box button:hover { background-color: #401ACC; } .AI-BG-box { border-width: 7px 2px 2px 2px; border-style: solid; border-color: rgb(87, 89, 89); width: -webkit-fill-available; height: 85px; background-color: #242837; position: absolute; border-top-right-radius: 15px; border-top-left-radius: 15px; bottom: 85%; } .AI-BG-box button { color: white; margin-top: 5%; padding: 4px; background-color: #5021FF; border: none; cursor: pointer; border-radius: 7px; position: inherit; margin-left: 6%; width: fit-content; } .AI-BG-box button img { top: 2px; width: 13px; right: 3%; position: relative;} .AI-BG-box button + button { margin-top: 34%; } </style> <div id="highlight_menu" style="display:none; color: white; position: fixed; background-color: rgb(87, 89, 89); font-size: 13.4px; font-family: monospace; z-index: 9999; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px;"> <div class="AI-BG-box"> <button id="AIBTN"><div class="MenuGemini" style="display: flex; align-items: center;">${GeminiSVG}Explore more</div></button> <button id="AIBTN" class="translate"><div class="MenuGemini" style="display: flex; align-items: center;">${GeminiSVG}Translate</div></button> </div> <ul style="padding-inline-end: 19px !important; padding-inline-start: 19px !important; margin-block-end: 10px;"> <li class="popuptext" style="cursor: pointer; display: inline;"></li><li id="ShowCurrencyORUnits" style="cursor: pointer; display: inline;">${FinalCurrency}</li> <li class="popuptext" id="SearchBTN" style="cursor: pointer; display: inline;">Search</li> <li class="popuptext" id="CopyBTN" style="cursor: pointer; display: inline;"> <span style=" color: #7B7D7F;">|</span> Copy</li> </ul> </div> <style> :host { --color-OrangeORLilac: #B969CC; } @keyframes borderColorChange { 0%, 100% { border-image-source: linear-gradient( to right, rgba(118, 126, 132, 0.6) 0%, rgba(118, 126, 132, 0.6) 10%, orange 45%, orange 55%, rgba(118, 126, 132, 0.6) 90%, rgba(118, 126, 132, 0.6) 100% ); } 50% { border-image-source: linear-gradient( to right, var(--color-OrangeORLilac) 0%, var(--color-OrangeORLilac) 25%, #FF8051 40%, #FF8051 60%, var(--color-OrangeORLilac) 75%, var(--color-OrangeORLilac) 100% ); } } @keyframes borderGradientChange { 0%, 100% { border-image-source: linear-gradient( to right, rgba(118, 126, 132, 0.6) 0%, rgba(118, 126, 132, 0.6) 10%, #FF8051 45%, #FF8051 55%, rgba(118, 126, 132, 0.6) 90%, rgba(118, 126, 132, 0.6) 100% ); } 50% { border-image-source: linear-gradient( to right, var(--color-OrangeORLilac) 0%, var(--color-OrangeORLilac) 25%, #FF8051 40%, #FF8051 60%, var(--color-OrangeORLilac) 75%, var(--color-OrangeORLilac) 100% ); } } .animated-border { border-width: 10px; border-style: solid; border-image-slice: 1; animation: borderColorChange 4s infinite, borderGradientChange 4s infinite; } </style> <div class="animated-border" id="AIBox" style="display: none; width: 38.4%; height: 4%; overflow: hidden; overflow-wrap: anywhere; background: border-box border-box ${BGColor}; padding-top: 10px; padding-bottom: 10px; position: fixed; top: 10%; left: 50.3%; transform: translateX(-50%); z-index: 999999;"><div id="tabcontext" style="font: initial; position: fixed;margin-left: 69%;margin-top: -10px;color: #94999e;align-items: center;gap: 0.375rem;display: flex;width: 22%;user-select: none;z-index: 999999;"><p>Page Context</p><p style=" font-size: 75%; color: #94999e; display: flex; align-items: center; height: 1.5rem; border-radius: 0.375rem; border-width: 1px; border-style: solid; padding-left: 0.375rem; padding-right: 0.375rem; ">Tab</p></div> <style> @keyframes stateAnimation { 0%, 100% { opacity: 0; } 33% { opacity: 1; } } .state1, .state2, .state3 { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .state2, .state3 { display: none; /* Hide initially */ } .animate1 { animation: stateAnimation 3s infinite; } .animate2 { animation: stateAnimation 3s infinite 1s; } .animate3 { animation: stateAnimation 3s infinite 2s; } </style> <button id="dictate" onmouseover="this.style.background='#401ACC'" onmouseout="this.style.background='#5021FF'" style=" display: none; z-index: 99999; background: rgb(80, 33, 255); border: 1px solid rgb(65, 69, 90); border-radius: 10px; cursor: pointer; left: 91.5%; position: relative; width: 32px; height: 32px;top: -2px;"> <svg viewBox="0 0 700 700" style="position: absolute;top: 12%;left: 15%;width: 100%;height: 100%;"> <defs> <path id="commonPath1" d="M439.5,236c0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,70-64,126.9-142.7,126.9s-142.7-56.9-142.7-126.9c0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,86.2,71.5,157.4,163.1,166.7v57.5h-23.6c-11.3,0-20.4,9.1-20.4,20.4s9.1,20.4,20.4,20.4h88c11.3,0,20.4-9.1,20.4-20.4s-9.1-20.4-20.4-20.4h-23.6v-57.5C368,393.4,439.5,322.2,439.5,236Z" fill="#fff"></path> <path id="commonPath2" d="M256,323.5c51,0,92.3-41.3,92.3-92.3v-127.9C348.3,52.3,307,11,256,11s-92.3,41.3-92.3,92.3v127.9c0,51,41.3,92.3,92.3,92.3ZM203.7,103.3C203.7,74.5,227.2,51,256,51s52.3,23.5,52.3,52.3v127.9c0,28.8-23.5,52.3-52.3,52.3s-52.3-23.5-52.3-52.3v-127.9Z" fill="#fff"></path> <ellipse id="commonEllipse" rx="53" ry="59" transform="translate(255.581 226.12)" fill="#0f0"></ellipse> </defs> <g class="state1"> <use href="#commonPath1"></use> <use href="#commonPath2"></use> </g> <g class="state2"> <use href="#commonPath1"></use> <use href="#commonPath2"></use> <use href="#commonEllipse"></use> <rect width="106" height="68.751" transform="translate(202.581 167.12)" fill="#0f0"></rect> </g> <g class="state3"> <use href="#commonPath1"></use> <use href="#commonPath2"></use> <use href="#commonEllipse"></use> <ellipse rx="53" ry="59.21" transform="translate(255.581 226.457)" fill="#0f0"></ellipse> <rect width="106" height="136.9" transform="translate(202.581 89.492)" fill="#0f0"></rect> <ellipse rx="35" ry="40.072" transform="matrix(1.513 0 0 1 255.557 89.492)" fill="#0f0"></ellipse> </g> </svg> </button> <button id="TopPause" onmouseover="this.style.background='#401ACC'" onmouseout="this.style.background='#5021FF'" style=" display: inline-flex; z-index: 99999; background: #5021FF; border: 1px solid #41455A; border-radius: 10px; cursor: pointer;left: 91.5%; top: -7.5px; position: relative; width: 32px; height: 32px; flex-direction: row; justify-content: center; align-items: center; "> <svg width="12" height="12" viewBox="0 0 12 12" fill="none"> <rect x="0.499756" y="0.5" width="11" height="11" rx="1.5" fill="white" stroke="white"/> </svg></button><div class="BoxGemini" id="gemini" style=" margin-top: -50px; position: absolute; margin-left: 1%;">${GeminiSVG}</div><div id="context" style="display: none; left: 1%; top: 30%;z-index: 999;position: absolute;border-radius: 0.375rem;background-color: rgb(255, 122, 0); color: white; padding: 0.375rem 0.5rem;font-size: 10px;font-weight: 700;line-height: 10px;">PAGE CONTEXT</div><input class="Prompt" id="prompt" placeholder="Enter your prompt to Gemini" style="color: ${TextColor}; width: 64%; height: 160%; position: relative; top: -12px; background-color: inherit; border: none; outline: none;"></div> <div id="AIBox" style="display: none; height: auto;width: 37.4%;overflow-y: auto;max-height: 63%; min-height: 20%;background: ${BGColor};box-shadow: #767e8499 0px 0px 0px 10px; border-radius: 15px;padding: 10px;position: fixed;top: 22.5%;left: 50.3%;transform: translateX(-50%);z-index: 999999;"> <div id="AIAnswer" style="display: flex; margin-left: 2%; align-items: flex-start;"></div> </div> <div id="loadingScreen" style="display: none; background-color: rgb(49 53 73 / 80%); z-index: 200;position: fixed;width: 100%;height: 100%; top: 0;"></div>`); //Set the menu html
shadowRoot.querySelector("#AIBTN:first-of-type").classList.add('show-button'); //Animate the Explore BTN
shadowRoot.querySelector("#AIBTN.translate").classList.add('show-button'); //Animate the Translate BTN
function RemoveContext() { //Start the function
shadowRoot.querySelector("#gemini").style.display = ''; //Show the Gemini BTN
shadowRoot.querySelector("#prompt").placeholder = 'Enter your prompt to Gemini'; //Return default placeholder
shadowRoot.querySelector("#prompt").style.left = ''; //Return the input bar to its original left position
shadowRoot.querySelector("#prompt").style.width = '64%'; //Return the input bar to its original width position
shadowRoot.querySelector("#context").style.display = 'none'; //Hide the context view
shadowRoot.querySelector("#tabcontext").style.display = 'flex'; //Show the "page context tab"
shadowRoot.querySelector('.animated-border').style.setProperty('--color-OrangeORLilac', '#B969CC'); //Return default lilac border effect color
} //Finish the function
function Generate(Prompt, button) { //Call the AI endpoint
const context = shadowRoot.querySelector("#context").style.display === '' ? `(You're not allowed to say anything like "Based on the provided text")\n"${Prompt} mainly base yourself on the text below\n${document.body.innerText}` : Prompt; //Add the page context if context is enabled
const AIFunction = button.match('translate') ? `(You're not allowed to say anything like "The text is already in ${UniqueLangs[0]}"\nNo translation is needed).\Translate into ${Lang} the following text/word inside quotes "${Prompt}".\nAlso give me a definition and usage examples.` : button.match('Prompt') ? context : `(PS*I'm unable to provide you with more context, so don't ask for it! Also, don't mention that I haven't provided context or anything similar to it!) Help me further explore a term or topic from the text/word: "${Prompt}"`; //AI prompts
const msg = button.match('translate') ? `Translate this text: "${Prompt.length > 215 ? Prompt.trim().slice(0, 215) + '…' : Prompt.trim()}"` : button.match('Prompt') ? Prompt.length > 240 ? Prompt.trim().slice(0, 240) + '…' : Prompt.trim() : `Help me further explore a term or topic from the text: "${Prompt.length > 180 ? Prompt.trim().slice(0, 180) + '…' : Prompt.trim()}"`; //User text
function startGeneratingText() { //Start the startGeneratingText function
Generating = setInterval(function() { //Start the interval to change the text
if (shadowRoot.querySelector("#finalanswer").innerText === 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ▋') { //Start the if condition
shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ'; //Remove ▋
} else { //Toggle between showing and hiding ▋
shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ▋'; //Add ▋
} //Finish the else condition
}, 200); //Finish the setInterval
} //Finish the startGeneratingText function
const request = GM.xmlHttpRequest({ //Call the AI API
method: "POST",
url: `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${GM_getValue("APIKey")}`,
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({
contents: [{
parts: [{
text: `${AIFunction}` //Use our AI prompt
}]
}],
safetySettings: [ //Allow all content
{
category: "HARM_CATEGORY_HARASSMENT",
threshold: "BLOCK_NONE"
},
{
category: "HARM_CATEGORY_HATE_SPEECH",
threshold: "BLOCK_NONE"
},
{
category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
threshold: "BLOCK_NONE"
},
{
category: "HARM_CATEGORY_DANGEROUS_CONTENT",
threshold: "BLOCK_NONE"
}
],
}),
onerror: function(err) { //Onerror
clearInterval(Generating); //Stop showing ▋
shadowRoot.querySelector("#finalanswer").innerHTML = `<br>Please copy and paste the error below:<br><a href="https://greasyfork.org/scripts/419825/feedback" style=" color: #81ff72; text-decoration: unset; ">Click here to report this bug</a><br><br> Prompt: ${Prompt}<br> Button: ${button}<br> Error: ${err}}<br><br><br>`; //Show the error message
},
onload: function(response) { //Onload
clearInterval(Generating); //Stop showing ▋
const AIResponse = JSON.parse(response.responseText).candidates?.[0]?.content?.parts?.[0]?.text;
if (AIResponse !== undefined) { //If AIResponse is not undefined
shadowRoot.querySelector("#finalanswer").innerHTML = (html => BypassTT?.createHTML(html) || html)(marked.parse(AIResponse) + '<br>'); //Show the parsed AI response
} else { //If AIResponse is undefined
shadowRoot.querySelector("#finalanswer").innerHTML = `<br>Please copy and paste the error below:<br><a href="https://greasyfork.org/scripts/419825/feedback" style=" color: #81ff72; text-decoration: unset; ">Click here to report this bug</a><br><br> Prompt: ${Prompt}<br> Button: ${button}<br> Error: ${response.responseText}<br><br><br>`; //Show the error message
} //Finish the else condition
audio = new SpeechSynthesisUtterance(AIResponse.replace(/[^a-zA-Z0-9\s%.,!?]/g, '')); //Play the AI response text, removing non-alphanumeric characters for better pronunciation
shadowRoot.querySelector("#copyAnswer").onclick = function() { //When the copy AI answer BTN is clicked
shadowRoot.querySelector("#copyAnswer").style.display = 'none'; //Hide the copy AI answer BTN
shadowRoot.querySelector("#AnswerCopied").style.display = 'inline-flex'; //Show the copied checkmark
navigator.clipboard.writeText(AIResponse.replace(/(\*\*|##)/g, '')); //Copy the AI response without duplicated symbols
setTimeout(() => { //Start the setTimeout function
shadowRoot.querySelector("#copyAnswer").style.display = 'inline-flex'; //Show the copy BTN
shadowRoot.querySelector("#AnswerCopied").style.display = 'none'; //Hide the copied checkmark
}, 1000); //Finish the setTimeout function
};
shadowRoot.querySelector("#dictate").style.display = ''; //Show the dictate BTN
shadowRoot.querySelector("#TopPause").style.display = 'none'; //Hide the TopPause BTN
shadowRoot.querySelector("#AIMenu").style.display = 'flex'; //Show the AIMenu BTN
shadowRoot.querySelector("#prompt").focus(); //Focus on the input bar
},
onabort: function(response) { //Onabort
clearInterval(Generating); //Stop showing ▋
shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤResponse has been interrupted.'; //Show a message
shadowRoot.querySelector("#dictate").style.display = ''; //Show the dictate BTN
shadowRoot.querySelector("#copyAnswer").style.display = 'none'; //Hide the copy AI answer BTN
shadowRoot.querySelector("#TopPause").style.display = 'none'; //Hide the TopPause BTN
shadowRoot.querySelector("#AIMenu").style.display = 'flex'; //Show the AIMenu BTN
shadowRoot.querySelector("#speak").style.display = 'none'; //Hide the speak BTN
},
onloadstart: function(response) { //Onloadstart
shadowRoot.querySelector("#AIAnswer").innerHTML = (html => BypassTT?.createHTML(html) || html)(`<style> pre { white-space: pre-wrap; padding: 10px; border: 1px solid #ccc; } .container { font: initial; font-size: 1em; display: flex; flex-direction: column; } .msg { display: flex; align-items: flex-start; margin-bottom: 10px; } .msg svg { margin-left: -10px; } .LineEl { border-top: 1px solid #000; margin-bottom: 10px; } .BoxGemini > svg {width: 32px; height: 32px;}</style><div style=" margin-left: -10px; "> <svg width="32" height="32" viewBox="0 0 32 32"><rect width="32" height="32" rx="8" fill="#5021FF"></rect><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7375 12.5186C12.7375 10.7594 14.1636 9.33333 15.9228 9.33333C17.6819 9.33333 19.108 10.7594 19.108 12.5186C19.108 14.2778 17.6819 15.7039 15.9228 15.7039C14.1636 15.7039 12.7375 14.2778 12.7375 12.5186ZM15.9228 8C13.4272 8 11.4042 10.023 11.4042 12.5186C11.4042 15.0142 13.4272 17.0372 15.9228 17.0372C18.4183 17.0372 20.4414 15.0142 20.4414 12.5186C20.4414 10.023 18.4183 8 15.9228 8ZM11.5819 17.6255C11.8982 17.437 12.0018 17.0278 11.8133 16.7115C11.6248 16.3952 11.2156 16.2916 10.8993 16.4801C10.6831 16.6089 10.4663 16.8148 10.2746 17.0349C10.0746 17.2644 9.87008 17.546 9.68554 17.8601C9.32327 18.4767 9 19.2839 9 20.1144C9 20.8532 9.12214 21.4899 9.41978 22.0347C9.72071 22.5855 10.1679 22.9818 10.7122 23.2937C11.2082 23.5779 11.7335 23.8486 12.5469 24.0394C13.3432 24.2262 14.3899 24.3308 15.9368 24.3308C19.0007 24.3308 20.5881 23.9091 21.6046 22.9619C22.5374 22.0927 22.9531 21.1528 22.9506 20.1128C22.9489 19.4161 22.6359 18.6481 22.2905 18.0381C21.9435 17.4254 21.4844 16.8333 21.0628 16.5185C20.7678 16.2983 20.3501 16.3589 20.1298 16.6539C19.9095 16.949 19.9701 17.3667 20.2652 17.587C20.4764 17.7446 20.826 18.1578 21.1302 18.695C21.4359 19.2349 21.6164 19.7615 21.6173 20.116C21.6188 20.7365 21.3947 21.3351 20.6956 21.9864C20.0802 22.5599 18.9602 22.9975 15.9368 22.9975C14.4401 22.9975 13.5073 22.8952 12.8514 22.7414C12.2127 22.5915 11.8133 22.3879 11.375 22.1368C10.9852 21.9134 10.7439 21.6773 10.5899 21.3954C10.4326 21.1075 10.3333 20.7113 10.3333 20.1144C10.3333 19.609 10.5393 19.039 10.8351 18.5355C10.9796 18.2896 11.1364 18.0755 11.2798 17.9108C11.4315 17.7368 11.5404 17.6502 11.5819 17.6255Z" fill="white"></path></svg> </div><div style="margin-left: 1%;"> <div style="color: ${TextColor}; font-size: 105%; top: 7px; position: relative;"> <div class="container"><div id="msg" style=" margin-bottom: 3%; ">${msg}</div><div id="LineEl" style="background-color: rgb(65, 69, 90); width: 105%; height: 1px; margin-left: -6%; margin-bottom: 2%;"></div><div class="BoxGemini" style=" margin-left: -6.5%; width: 0%; height: 0%; ">${GeminiSVG}</div> <div id="finalanswer" style="margin-top: -11%; "> </div> <div id="AIMenu" style="display: none; gap: 1.5%;margin-top: -5%;justify-content: flex-end;padding-bottom: 2%;"><button id="bottompause" onmouseover="this.style.background='rgba(255, 255, 255, 0.4)'" onmouseout="this.style.background='#212430'" style=" ${IMGsColor}; display: none; background: #212430; border: 1px solid #41455A; border-radius: 10px; cursor: pointer; width: 32px; height: 32px; flex-direction: row; justify-content: center; align-items: center; "><svg width="16" height="16" viewBox="0 -2 8 13" fill="none"> <path fill-rule="evenodd" clip-rule="evenodd" d="M1.49879 0.5C0.671042 0.5 1.52588e-05 1.17103 1.52588e-05 1.99878V8.00122C1.52588e-05 8.82897 0.671042 9.5 1.49879 9.5C2.32655 9.5 2.99757 8.82897 2.99757 8.00122V1.99878C2.99757 1.17103 2.32655 0.5 1.49879 0.5ZM1.00002 1.99878C1.00002 1.72331 1.22333 1.5 1.49879 1.5C1.77426 1.5 1.99757 1.72331 1.99757 1.99878V8.00122C1.99757 8.27669 1.77426 8.5 1.49879 8.5C1.22333 8.5 1.00002 8.27669 1.00002 8.00122V1.99878ZM6.50575 0.5C5.678 0.5 5.00697 1.17103 5.00697 1.99878V8.00122C5.00697 8.82897 5.678 9.5 6.50575 9.5C7.33351 9.5 8.00453 8.82897 8.00453 8.00122V1.99878C8.00453 1.17103 7.33351 0.5 6.50575 0.5ZM6.00697 1.99878C6.00697 1.72331 6.23028 1.5 6.50575 1.5C6.78122 1.5 7.00453 1.72331 7.00453 1.99878V8.00122C7.00453 8.27669 6.78122 8.5 6.50575 8.5C6.23028 8.5 6.00697 8.27669 6.00697 8.00122V1.99878Z" fill="white"></path> </svg></button><button id="speak" onmouseover="this.style.background='rgba(255, 255, 255, 0.4)'" onmouseout="this.style.background='#212430'" style=" ${IMGsColor}; background: #212430; border: 1px solid #41455A; border-radius: 10px; display: inline-flex; cursor: pointer; width: 32px; height: 32px; flex-direction: row; justify-content: center; align-items: center; "><svg width="16" height="16" viewBox="0 0 16 16" fill="#fff"> <path fill-rule="inherit" clip-rule="evenodd" d="M6.99585 3.24577C6.81771 3.36247 6.58157 3.56921 6.2112 3.89612L4.20926 5.66321L4.18027 5.68895C4.07192 5.78537 3.93427 5.90788 3.75948 5.97398C3.58469 6.04009 3.40043 6.03934 3.25538 6.03875L3.21662 6.03864H2.50001C2.25017 6.03864 2.11309 6.03971 2.018 6.05249L2.01435 6.05299L2.01385 6.05663C2.00107 6.15173 2.00001 6.28881 2.00001 6.53864V9.53864C2.00001 9.78848 2.00107 9.92556 2.01385 10.0207L2.01435 10.0243L2.01799 10.0248C2.11309 10.0376 2.25017 10.0386 2.50001 10.0386H3.2338L3.27297 10.0385C3.41953 10.0379 3.60574 10.0372 3.78206 10.1046C3.95838 10.172 4.09659 10.2968 4.20536 10.395L4.23448 10.4212L6.20852 12.189C6.57949 12.5212 6.81642 12.7317 6.99537 12.8508L7.00796 12.8591L7.01018 12.8442C7.04081 12.6314 7.04208 12.3145 7.04208 11.8166V4.27098C7.04208 3.77697 7.04081 3.46312 7.01041 3.25234L7.00823 3.23776L6.99585 3.24577ZM7.1278 3.17543C7.12773 3.17558 7.1259 3.17617 7.12253 3.17674C7.12619 3.17556 7.12788 3.17528 7.1278 3.17543ZM6.97834 3.11168C6.97653 3.10878 6.97576 3.10702 6.97583 3.10686C6.97589 3.10671 6.9768 3.10815 6.97834 3.11168ZM6.97515 12.9916C6.97508 12.9915 6.97586 12.9897 6.97769 12.9867C6.97613 12.9903 6.97522 12.9918 6.97515 12.9916ZM7.12322 12.9217C7.12662 12.9223 7.12847 12.9229 7.12854 12.9231C7.12862 12.9232 7.12692 12.9229 7.12322 12.9217ZM6.44789 2.40927C6.69128 2.24984 7.05663 2.07222 7.45332 2.25119C7.85002 2.43016 7.95863 2.82161 8.00017 3.10959C8.04215 3.40069 8.04212 3.78842 8.04209 4.23246L8.04208 4.27098V11.8166L8.04209 11.8551C8.04212 12.3031 8.04215 12.6937 7.99998 12.9867C7.95838 13.2757 7.84954 13.67 7.45005 13.8485C7.05057 14.027 6.68423 13.845 6.44119 13.6832C6.19482 13.5192 5.90383 13.2586 5.57013 12.9597L5.57012 12.9597L5.5414 12.934L3.56736 11.1662C3.49189 11.0986 3.45417 11.0652 3.42542 11.0429L3.4238 11.0417L3.42176 11.0415C3.38548 11.0389 3.3351 11.0386 3.2338 11.0386H2.50001L2.47281 11.0386C2.26077 11.0387 2.05471 11.0387 1.88475 11.0159C1.69315 10.9901 1.47451 10.9274 1.2929 10.7458C1.11129 10.5641 1.04853 10.3455 1.02277 10.1539C0.999921 9.98395 0.999962 9.77788 1 9.56585L1.00001 9.53864V6.53864L1 6.51144C0.999962 6.29941 0.999921 6.09334 1.02277 5.92338C1.04853 5.73178 1.11129 5.51315 1.2929 5.33154C1.47451 5.14993 1.69315 5.08717 1.88475 5.06141C2.0547 5.03856 2.26076 5.0386 2.4728 5.03864H2.4728L2.50001 5.03864H3.21662C3.31686 5.03864 3.36669 5.03836 3.40258 5.03584L3.40461 5.03569L3.40622 5.03446C3.4348 5.0126 3.47234 4.97984 3.5475 4.9135L5.54944 3.14641L5.57832 3.12091L5.57834 3.1209L5.57835 3.12089C5.91122 2.82703 6.20187 2.57043 6.44789 2.40927ZM10.1345 5.33693C10.2257 5.07628 10.5109 4.93892 10.7716 5.03012C11.5468 5.30139 12.1156 5.71974 12.4845 6.27343C12.851 6.82368 12.9896 7.46152 12.9888 8.12059C12.9881 8.77784 12.8479 9.36588 12.4685 9.8652C12.095 10.3568 11.5331 10.7045 10.8038 10.9736C10.5448 11.0692 10.2573 10.9367 10.1617 10.6777C10.0661 10.4186 10.1986 10.1311 10.4577 10.0355C11.0913 9.80166 11.4579 9.54244 11.6723 9.2602C11.8809 8.98566 11.9883 8.63292 11.9888 8.11953C11.9894 7.59876 11.8804 7.1703 11.6522 6.82786C11.4264 6.48888 11.0533 6.18815 10.4413 5.97401C10.1807 5.88281 10.0433 5.59758 10.1345 5.33693ZM10.5874 3.04341C10.3154 2.99552 10.0561 3.17716 10.0082 3.44912C9.96033 3.72108 10.142 3.98036 10.4139 4.02825C11.5592 4.22994 12.4289 4.71111 13.0117 5.38193C13.5932 6.05126 13.9207 6.94547 13.9201 8.03323C13.9195 9.12625 13.5988 9.99297 13.0242 10.6448C12.4457 11.3008 11.573 11.7808 10.3984 12.026C10.1281 12.0825 9.95475 12.3474 10.0112 12.6177C10.0676 12.888 10.3325 13.0614 10.6028 13.0049C11.9332 12.7271 13.0195 12.1622 13.7743 11.3061C14.5328 10.4457 14.9194 9.33294 14.9201 8.03375C14.9208 6.7372 14.5263 5.60054 13.7666 4.72609C13.0082 3.85314 11.9174 3.27763 10.5874 3.04341Z"></path> </svg></button> <button id="AnswerCopied" onmouseover="this.style.background='rgba(255, 255, 255, 0.4)'" onmouseout="this.style.background='#212430'" style=" ${IMGsColor}; background: #212430; border: 1px solid #41455A; border-radius: 10px; display: none; cursor: pointer; width: 32px; height: 32px; flex-direction: row; justify-content: center; align-items: center; "><svg width="16" height="16" viewBox="0 0 10 8" fill="none"> <path d="M1.02063 3.68066L3.67635 6.65194L8.97935 1.34802" stroke="white" stroke-linecap="round"/> </svg></button><button id="copyAnswer" onmouseover="this.style.background='rgba(255, 255, 255, 0.4)'" onmouseout="this.style.background='#212430'" style=" ${IMGsColor}; background: #212430; border: 1px solid #41455A; border-radius: 10px; display: inline-flex; cursor: pointer; width: 32px; height: 32px; flex-direction: row; justify-content: center; align-items: center; "><svg width="16" height="16" viewBox="0 0 16 16" fill="none"> <path fill-rule="evenodd" clip-rule="evenodd" d="M4.22727 4.5H3.5C2.39543 4.5 1.5 5.39543 1.5 6.5V12.5C1.5 13.6046 2.39543 14.5 3.5 14.5H9.5C10.6046 14.5 11.5 13.6046 11.5 12.5V11.7727H10.5V12.5C10.5 13.0523 10.0523 13.5 9.5 13.5H3.5C2.94772 13.5 2.5 13.0523 2.5 12.5V6.5C2.5 5.94772 2.94772 5.5 3.5 5.5H4.22727V4.5Z" fill="white"></path> <rect x="5" y="2" width="9" height="9" rx="1.5" stroke="white"></rect> </svg></button> <button id="NewAnswer" onmouseover="this.style.background='rgba(255, 255, 255, 0.4)'" onmouseout="this.style.background='#212430'" style=" ${IMGsColor}; background: #212430; border: 1px solid #41455A; border-radius: 10px; display: inline-flex; cursor: pointer; width: 32px; height: 32px; flex-direction: row; justify-content: center; align-items: center; "><svg width="16" height="16" viewBox="0 0 16 16" fill="none"> <path d="M3.64362 8.00003C3.64362 5.70974 5.50027 3.85309 7.79056 3.85309C9.06546 3.85309 10.2057 4.42786 10.9671 5.33402C11.0399 5.42069 11.0743 5.56527 10.9942 5.64533L10.5291 6.11045C10.2141 6.42543 10.4372 6.964 10.8826 6.964H12.75C13.0261 6.964 13.25 6.74015 13.25 6.464V4.59664C13.25 4.15119 12.7114 3.92811 12.3964 4.24309L11.8532 4.78632C11.7983 4.84128 11.7013 4.81866 11.6513 4.75915C10.7273 3.65956 9.34048 2.95947 7.79056 2.95947C5.00674 2.95947 2.75 5.21621 2.75 8.00003C2.75 10.7839 5.00674 13.0406 7.79056 13.0406C9.95003 13.0406 11.7913 11.6828 12.5092 9.77593C12.5962 9.54499 12.4795 9.28729 12.2485 9.20034C12.0176 9.11338 11.7599 9.2301 11.6729 9.46104C11.0818 11.0312 9.5659 12.147 7.79056 12.147C5.50027 12.147 3.64362 10.2903 3.64362 8.00003Z" fill="white"></path> </svg></button></div></div>`); //Create the AI menu HTML
var transcript = ""; //Add words
startGeneratingText(); //Call the function startGeneratingText
shadowRoot.querySelector("#loadingScreen").style.display = ''; //Show the black background
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition; //Define SpeechRecognition
var recognition = new SpeechRecognition(); //Create a new instance of the SpeechRecognition object
recognition.interimResults = true; //Show partial results
recognition.continuous = true; //Keep listening until stopped
shadowRoot.querySelector("#highlight_menu").style.display = 'none'; //Hide the mini menu on the page
shadowRoot.querySelectorAll("#AIBox").forEach(el => el.style.display = ''); //Show the AI input and box
getSelection().removeAllRanges(); //UnSelect the selected text so that if the user clicks on the past selected text the menu won't show up again
shadowRoot.querySelector("#loadingScreen").onclick = function() { //When the black background is clicked
shadowRoot.querySelectorAll("#AIBox").forEach(el => el.style.display = 'none'); //Hide the AI input and box
this.style.display = 'none'; //Hide the black background
recognition.stop(); //Stop recognizing audio
speechSynthesis.cancel(); //Stop speaking
request.abort(); //Abort any ongoing request
if (shadowRoot.querySelector("#gemini").style.display === 'none') { //If the Gemini BTN is hidden
RemoveContext(); //Return original prompt input styles
} //Finish the if condition
} //Finish the onclick event listener
shadowRoot.querySelector("#TopPause").onclick = function() { //When the TopPause BTN is clicked
shadowRoot.querySelector("#dictate").style.display = '' //Show the dictate BTN
shadowRoot.querySelector("#TopPause").style.display = 'none' //Hide the TopPause BTN
request.abort(); //Abort the request
} //Finish the onclick event listener
recognition.onend = function() { //After the recognition ends
shadowRoot.querySelectorAll('.state1, .state2, .state3').forEach((state, index) => { //ForEach SVG animation state
index.toString().match(/1|2/) ? state.style.display = 'none' : ''; //Show only the 1 state
state.classList.remove('animate'+index); //Apply animation class
}); //Finish the ForEach loop
isRecognizing = false; //Update the flag
transcript !== '' ? Generate(transcript, shadowRoot.querySelector("#prompt").className) : shadowRoot.querySelector("#finalanswer").innerHTML = `<br>It looks like there was no audio detected. Please try again or check your mic settings.<br><br>`; //Show the error message; //Call the AI API if audio has been detected
}; //Finish the recognition end event listener
recognition.onresult = function(event) { //Handle the result event
transcript = ""; //Clear the transcript at the start of the event
for (var i = 0; i < event.results.length; i++) { //For all transcript results
transcript += event.results[i][0].transcript + " "; //Concatenate all intermediate transcripts
} //Finish the for loop
shadowRoot.querySelector("#msg").innerText = transcript.length > 240 ? transcript.slice(0, 240) + '…' : transcript; //Display the recognized words
}; //Finish the recognition result event listener
shadowRoot.querySelector("#dictate").onclick = function() { //When dictate is clicked
if (isRecognizing) { //If already recognizing
recognition.stop(); //Stop recognizing
} else { //If not recognizing
isRecognizing = true; //Update the flag
recognition.start(); //Start recognizing
shadowRoot.querySelectorAll('.state1, .state2, .state3').forEach((state, index) => { //ForEach SVG animation state
state.style.display = 'unset'; //Show all states
state.classList.add('animate'+index); //Apply animation class
}); //Finish the ForEach loop
} //Finish the else condition
}; //Finish the onclick event listener
var desiredVoice = null; //Create a new null variable
speechSynthesis.onvoiceschanged = () => desiredVoice = speechSynthesis.getVoices().find(v => v.name === "Microsoft Zira - English (United States)"); //Get and store the desired voice
speechSynthesis.onvoiceschanged(); //Handle cases where the event doesn't fire
function speakText(text) { //Create a function to speak the text
audio.voice = desiredVoice; //Use the desiredVoice
speechSynthesis.speak(audio); //Speak the text
} //Finish the function
shadowRoot.querySelectorAll("#speak, #bottompause").forEach(function(el) { //ForEach BTN
el.onclick = function() { //When speak or the bottom pause BTNs are clicked
if (speechSynthesis.speaking) { //If speech synthesis is speaking
speechSynthesis.cancel(); //Stop speaking
shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN
shadowRoot.querySelector("#bottompause").style.display = 'none'; //Hide the pause BTN
} //Finish the if condition
else //If speech synthesis isn't speaking
{ //Start the else condition
shadowRoot.querySelector("#speak").style.display = 'none' //Hide the play BTN
shadowRoot.querySelector("#bottompause").style.display = 'inline-flex'; //Show the pause BTN
speakText(audio); //Speak the AI reponse text
audio.onend = (event) => { //When the audio ends
shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN
shadowRoot.querySelector("#bottompause").style.display = 'none'; //Hide the pause BTN
}; //Finish the audio end event listener
} //Finish the else condition
}; //Finish the onclick event listener
}); //Finish the ForEach loop
shadowRoot.querySelector("#NewAnswer").onclick = function() { //When the user clicks on the new answer
shadowRoot.querySelector("#dictate").style.display = 'none'; //Hide the dictate BTN
shadowRoot.querySelector("#TopPause").style.display = 'inline-flex'; //Show the top pause BTN
Generate(Prompt, button); //Call the AI API
}; //Finish the onclick event listener
} //Finish the onloadstart event listener
});//Finish the GM.xmlHttpRequest function
} //Finish the Generate function
shadowRoot.querySelector("#prompt").addEventListener("keydown", (event) => { //When the user presses a key on the input bar
if (event.key === "Enter") { //If enter is pressed
Generate(shadowRoot.querySelector("#prompt").value, shadowRoot.querySelector("#prompt").className); //Call the AI API
shadowRoot.querySelector("#prompt").value = ''; //Erase the prompt text
} //Finish the if condition
if (event.key === "Tab") { //If tab is pressed
if (shadowRoot.querySelector("#gemini").style.display === 'none') { //If the Gemini BTN is hidden
RemoveContext(); //Return original prompt input styles
} //Finish the if condition
else //If tab the Gemini BTN isn't hidden
{ //Start the else condition
shadowRoot.querySelector("#gemini").style.display = 'none'; //Hide the Gemini BTN
shadowRoot.querySelector("#prompt").placeholder = `Gemini is using ${location.host.replace('www.','')} for context...`; //Change placeholder
shadowRoot.querySelector("#prompt").style.left = '12%'; //Push the input bar to the left
shadowRoot.querySelector("#prompt").style.width = '75%'; //Increase the input bar width
shadowRoot.querySelector("#context").style.display = ''; //Show the context view
shadowRoot.querySelector("#tabcontext").style.display = 'none'; //Hide the "page context tab"
shadowRoot.querySelector('.animated-border').style.setProperty('--color-OrangeORLilac', '#FF8051'); //Change the border effect color to orange
} //Finish the else condition
} //Finish the if condition
setTimeout(() => { //Wait for the code above to execute
shadowRoot.querySelector("#prompt").focus(); //Refocus on the input bar
}, 0); //Finish the setTimeout
}); //Finish the keydown event listener
if (document.body.textContent !== '' || document.body.innerText !== '') //If the body has any text
{ //Start the if condition
document.body.appendChild(HtmlMenu); //Add the script menu div container
} //Finish the if condition
shadowRoot.querySelector("#SearchBTN").onmousedown = function() { //When the Search BTN is clicked
var LinkfyOrSearch = 'https://www.google.com/search?q='; //Create a variable to open google
if (SelectedTextIsLink === true) //If the selected text is a link
{ //Start the if condition
LinkfyOrSearch = 'https://'; //Make the non-HTTP and non-HTTPS links able to be opened
} //Finish the if condition
if (SelectedText.match(/http:|https:/) !== null) //If the selected text is a link that already has HTTP or HTTPS
{ //Start the if condition
LinkfyOrSearch = ''; //Remove the https:// that was previously added to this variable
} //Finish the if condition
GM_openInTab(LinkfyOrSearch + SelectedTextSearch, { //Open google and search for the selected text
active: true, //Make the new tab active (selected)
setParent: true, //Consider the new tab as a child of the current tab
loadInBackground: true //Don't load the tab in the background
}); //Finish the GM_openInTab function
getSelection().removeAllRanges(); //UnSelect the selected text after the search BTN is clicked so that if the user clicks on the past selected text the menu won't show up again.
shadowRoot.querySelector("#highlight_menu").style.display = 'none'; //Hide the menu
}; //Finish the onmousedown event listener
shadowRoot.querySelector("#CopyBTN").onmousedown = function() { //When the copy BTN is clicked
navigator.clipboard.writeText(SelectedText); //Copy the selected text
}; //Finish the onmousedown event listener
shadowRoot.querySelectorAll("#AIBTN").forEach(function(button) { //For the Explore and Translate BTNs
button.onmousedown = function(event,i) { //When the BTNs are Clicked
if (GM_getValue("APIKey") === undefined || GM_getValue("APIKey") === null || GM_getValue("APIKey") === '') { //If the API Key isn't already set
GM_setValue("APIKey", prompt('Enter your API key\n*Press OK')); //Store the API Key
} //Finish the if condition
if (GM_getValue("APIKey") !== null && GM_getValue("APIKey") !== '') { //if the API Key is already set
Generate(SelectedText, this.className); //Call the AI API
} //Finish the if condition
}; //Finish the onmousedown event listener
}); //Finish the foreach loop
//Allow the script in iframes__________________________________________________________________________________________________________________________________________________________________
setTimeout(function() { //Start the setTimeout function
const AllIframes = document.querySelectorAll("iframe"); //Get all iframes on the page
for (var i = AllIframes.length; i--;) { //Start the for condition
if (AllIframes[i].allow.match('clipboard-write;') === null && AllIframes[i].src.match(Links) !== null && AllIframes[i].src.match(/recaptcha|rt.*.*.edu|challenges.cloudflare|youtube|dailymotion|vimeo|streamtape|mcloud|vidstream|mp4upload|googlevideo|kaltura|crunchyroll|animesup|google.com\/recaptcha\/|blank.html|\.mp4/) === null) //If the iframe doesn't have the clipboard-write attribute yet, it has a link and it isn't a video
{ //Start the if condition
AllIframes[i].allow = AllIframes[i].allow + 'clipboard-write;'; //Add the permission to copy the iframe text
AllIframes[i].src = AllIframes[i].src; //Reload the iframe to apply the new permissions
} //Finish the if condition
} //Finish the for condition
}, 4000); //Finish the setTimeout function
window.addEventListener('scroll', async function() { //When the page is scrolled
shadowRoot.querySelector("#highlight_menu").style.display = 'none'; //Hide the menu
if (LeftClicked === false && SelectedText !== '') { //If the Left Click isn't being held, and if something is currently selected
getSelection().removeAllRanges(); //UnSelect the selected text when scrolling the page down so that if the user clicks on the past selected text the menu won't show up again
} //Finish the if condition
}); //Finish the on-scroll event listener
} //Finish the if condition