// ==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 // @downloadURL none // ==/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) + ' │'); //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) + ' │'); //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 │'); //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 + ' │ '); //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 │'); //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 += ` `; //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 = ''; //Store the GeminiSVG shadowRoot.innerHTML = (html => BypassTT?.createHTML(html) || html)(`
`); //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 = `