// ==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 64 // @author hacker09 // @include * // @exclude https://accounts.google.com/v3/signin/* // @icon https://i.imgur.com/8iw8GOm.png // @grant GM_registerMenuCommand // @grant GM_getResourceText // @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 // @resource AICSS https://hacker09.glitch.me/AICSS.css // @require https://cdnjs.cloudflare.com/ajax/libs/marked/14.0.0/marked.min.js // @downloadURL none // ==/UserScript== /* jshint esversion: 11 */ const BypassTT = window.trustedTypes?.createPolicy('BypassTT', { createHTML: HTML => HTML }); //Bypass trustedTypes if (GM_getValue("APIKey") === undefined || GM_getValue("APIKey") === null || GM_getValue("APIKey") === '') { //Set up the API Key window.onload = function() { if (location.href === 'https://aistudio.google.com/app/apikey' && document.querySelector(".apikey-link") !== null) { setTimeout(function() { document.querySelectorAll(".apikey-link")[1].click(); //Click on the API Key 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!'); (GM_getValue("APIKey") !== undefined && GM_getValue("APIKey") !== null && GM_getValue("APIKey") !== '') ? alert('API Key automatically added!') : alert('Failed to automatically add API Key!'); }, 500); }, 500); } }; } // Mouse Gestures _________________________________________________________________________________________________________________________________________________________ GM_registerMenuCommand("Enable/Disable Mouse Gestures", MouseGestures); if (GM_getValue("MouseGestures") !== true && GM_getValue("MouseGestures") !== false) { GM_setValue("MouseGestures", true); } function MouseGestures() //Enable/disable MouseGestures { if (GM_getValue("MouseGestures") === true) { GM_setValue("MouseGestures", false); } else { GM_setValue("MouseGestures", true); location.reload(); } } if (GM_getValue("MouseGestures") === true) //If the MouseGestures is enabled { const SENSITIVITY = 3; const TOLERANCE = 3; const funcs = { //Store the MouseGestures functions 'L': function() { //Detect the Left movement window.history.back(); }, 'R': function() { //Detect the Right movement window.history.forward(); }, 'D': function() { //Detect the Down movement if (IsShiftNotPressed === true) { //If the shift key isn't being pressed GM_openInTab(link, { active: true, insert: true, setParent: true }); } }, 'UD': function() { //Detect the Up+Down movement location.reload(); }, 'DR': function(e) { //Detect the Down+Right movement top.close(); e.preventDefault(); e.stopPropagation(); }, 'DU': function() { //Detect the Down+Up movement GM_openInTab(link, { active: false, insert: true, setParent: true }); } }; //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; } }; window.addEventListener('mousedown', function(e) { if (e.which === 3) { x = e.clientX; y = e.clientY; path = ""; window.addEventListener('mousemove', tracer, false); //Detect the mouse position } }, false); var IsShiftNotPressed = true; //Hold the shift key status window.addEventListener("contextmenu", function(e) { //When the shift key is/isn't pressed if (e.shiftKey) { IsShiftNotPressed = false; open(link, '_blank', 'height=' + screen.height + ',width=' + screen.width); } if (LeftClicked === true) { //If the Left Click was released when the Rocker Mouse Gestures were enabled e.preventDefault(); e.stopPropagation(); } setTimeout(function() { IsShiftNotPressed = true; }, 500); }, false); window.addEventListener('contextmenu', function(e) { //When the right click BTN is released window.removeEventListener('mousemove', tracer, false); //Track the mouse movements if (path !== "") { e.preventDefault(); if (funcs.hasOwnProperty(path)) { funcs[path](); } } }, false); var link; Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseover = function() { link = this.href; //Store the hovered link to a variable }); Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseout = function() { const PreviousLink = link; //Save the hovered link to a variable setTimeout(function() { if (PreviousLink === link) //If the hovered link is still the same as the previously hovered Link { link = 'about:newtab'; //Make the script open a new browser tab when the mouse leaves any link that was hovered } }, 200); }); } //Rocker Mouse Gesture Settings _________________________________________________________________________________________________________________________________________________________ GM_registerMenuCommand("Enable/Disable Rocker Mouse Gestures", RockerMouseGestures); if (GM_getValue("RockerMouseGestures") !== true && GM_getValue("RockerMouseGestures") !== false) { //Set up the RockerMouseGestures GM_setValue("RockerMouseGestures", false); } function RockerMouseGestures() //Enable/disable RockerMouseGestures { if (GM_getValue("RockerMouseGestures") === true) { GM_setValue("RockerMouseGestures", false); } else { GM_setValue("RockerMouseGestures", true); location.reload(); } } if (GM_getValue("RockerMouseGestures") === true || GM_getValue("SearchHiLight") === true) //If the RockerMouseGestures or the SearchHiLight is enabled { var LeftClicked, RightClicked; window.addEventListener("mousedown", function(e) { //Track which side of the mouse was the first one to be pressed switch (e.button) { case 0: LeftClicked = true; break; case 2: RightClicked = true; break; } }, false); window.addEventListener("mouseup", function(e) { //Track which side of the mouse was the last one to be released switch (e.button) { case 0: LeftClicked = false; break; case 2: RightClicked = false; break; } if (LeftClicked && RightClicked === false) { //If Left was Clicked and then Right Click was released history.back(); //Go Back } if (RightClicked && LeftClicked === false) { //If Right was Clicked and then Left Click was released history.forward(); //Go Forward } }, false); } //SearchHighLight + CurrenciesConverter + UnitsConverter _______________________________________________________________________________________________________________________________________ GM_registerMenuCommand("Enable/Disable SearchHiLight", SearchHiLight); if (GM_getValue("SearchHiLight") !== true && GM_getValue("SearchHiLight") !== false) { //Set up the SearchHiLight GM_setValue("SearchHiLight", true); } if (GM_getValue("CurrenciesConverter") !== true && GM_getValue("CurrenciesConverter") !== false) { GM_setValue("CurrenciesConverter", true); } if (GM_getValue("UnitsConverter") !== true && GM_getValue("UnitsConverter") !== false) { GM_setValue("UnitsConverter", true); } function SearchHiLight() //Enable/disable the SearchHiLight and the Currency/Unit converters { if (GM_getValue("SearchHiLight") === true) { GM_setValue("SearchHiLight", false); GM_setValue("CurrenciesConverter", false); GM_deleteValue('YourLocalCurrency'); GM_setValue("UnitsConverter", false); } else { GM_setValue("SearchHiLight", true); if (confirm('If you want to enable the Currency Converter press OK.')) { GM_setValue("CurrenciesConverter", true); } else { GM_setValue("CurrenciesConverter", false); } if (confirm('If you want to enable the Units Converter press OK.')) { GM_setValue("UnitsConverter", true); } else { GM_setValue("UnitsConverter", false); } location.reload(); } } if (GM_getValue("SearchHiLight") === true) //If the SearchHiLight is enabled { var SelectedTextIsLink, FinalCurrency, SelectedText, SelectedTextSearch = ''; 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); window.addEventListener('load', function() { //Start the script after the page loads 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 const CurrencySymbols = new RegExp(/\$|R\$|HK\$|US\$|\$US|¥|€|Rp|kn|Kč|kr|zł|£|฿|₩/i); 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); function ShowConvertion(UnitORCurrency, Type, Result) { shadowRoot.querySelector("#SearchBTN").innerHTML = (html => BypassTT?.createHTML(html) || html)('' + shadowRoot.querySelector("#SearchBTN").innerHTML); if (UnitORCurrency === 'Currencies' && SelectedText.match(Currencies)[2].match(CurrencySymbols) !== null) { //If the selected currency contains a symbol shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(Type + ' 🠂 ' + Intl.NumberFormat(navigator.language, { style: 'currency', currency: GM_getValue("YourLocalCurrency") }).format(Result)); //Show the FinalCurrency } if (UnitORCurrency === 'Currencies' && SelectedText.match(Currencies)[2].match(CurrencySymbols) === null) { //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(Result)); //Show the FinalCurrency } UnitORCurrency === 'Units' ? shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(Result + ' ' + Type) : ''; //Show the converted unit results var htmlcode = shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML; //Save the converted unit/currency value var offsetWidth = shadowRoot.querySelector("#ShowCurrencyORUnits").offsetWidth; //Store the current menu size shadowRoot.querySelector("#ShowCurrencyORUnits").onmouseover = function() { //When the mouse hovers the unit/currency shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(`Copy`); shadowRoot.querySelector("#ShowCurrencyORUnits").style.display = 'inline-flex'; shadowRoot.querySelector("#ShowCurrencyORUnits").style.justifyContent = 'space-around'; shadowRoot.querySelector("#ShowCurrencyORUnits").style.width = `${offsetWidth}px`; //Maintain the aspect ratio }; shadowRoot.querySelector("#ShowCurrencyORUnits").onmouseout = function() { //When the mouse leaves the unit/currency shadowRoot.querySelector("#ShowCurrencyORUnits").style.width = ''; //Return the original aspect ratio shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(htmlcode); //Return the previous html }; shadowRoot.querySelector("#ShowCurrencyORUnits").onclick = function() { //When the unit/currency is clicked UnitORCurrency === 'Units' ? navigator.clipboard.writeText(Result) : navigator.clipboard.writeText(Intl.NumberFormat(navigator.language, { style: 'currency', currency: GM_getValue("YourLocalCurrency") }).format(Result)); }; } //CurrenciesConverter _______________________________________________________________________________________________________________________________________ if (GM_getValue("CurrenciesConverter") === true) { //If Currencies Converter is enabled shadowRoot.querySelector("#ShowCurrencyORUnits").innerText = ''; //Remove the previous Currency text if (SelectedText.match(Currencies) !== null) //If the selected text is a currency { if (GM_getValue("YourLocalCurrency") === undefined) { 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'); GM_setValue("YourLocalCurrency", UserInput); } (async () => { //Get the final converted currency value var CurrencySymbol = SelectedText.match(Currencies)[2]; //Store the currency symbol if (SelectedText.match(Currencies)[2].match(CurrencySymbols) !== null) //If the selected currency contains a symbol { switch (SelectedText.match(CurrencySymbols)[0].toLowerCase()) { //If the selected currency contains a symbol case '$': case 'us$': case '$us': CurrencySymbol = 'USD'; break; case 'r$': CurrencySymbol = 'BRL'; break; case 'hk$': CurrencySymbol = 'HKD'; break; case "¥": CurrencySymbol = 'JPY'; break; case '€': CurrencySymbol = 'EUR'; break; case 'rp': CurrencySymbol = 'IDR'; break; case 'kn': CurrencySymbol = 'HRK'; break; case 'kč': CurrencySymbol = 'CZK'; break; case 'kr': CurrencySymbol = 'DKK'; break; case 'zł': CurrencySymbol = 'PLN'; break; case '£': CurrencySymbol = 'GBP'; break; case '฿': CurrencySymbol = 'THB'; break; case '₩': CurrencySymbol = 'KRW'; break; } } GM.xmlHttpRequest({ //Get 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'); //Parse the fetch response const FinalCurrency = parseFloat(newDocument.querySelector(".SwHCTb").innerText.split(' ')[0].replaceAll(',', '')); //Store the FinalCurrency and erase all commas ShowConvertion('Currencies', CurrencySymbol, FinalCurrency); } }); })(); } } //UnitsConverter _________________________________________________________________________________________________________________________________________________________________________ if (GM_getValue("UnitsConverter") === true) { //If the Units Converter option is enabled 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); if (SelectedText.match(Units) !== null) //If the selected text is an unit { const SelectedUnitValue = SelectedText.match(Units)[1].replaceAll(',', '.'); //Get the selected unit value switch (SelectedText.match(Units)[2].toLowerCase()) { //Convert the selected unit case 'inch': case 'inches': case 'in': case '"': case '”': var NewUnit = 'cm'; var ConvertedUnit = parseFloat(SelectedUnitValue * 2.54).toFixed(2); break; case 'centimeter': case 'centimeters': case 'cm': case 'cms': NewUnit = 'in'; ConvertedUnit = parseFloat(SelectedUnitValue / 2.54).toFixed(2); break; case 'mt': case 'mts': case 'meters': case 'meter': NewUnit = 'ft'; ConvertedUnit = parseFloat(SelectedUnitValue * 3.281).toFixed(2); break; case 'kg': case 'kilograms': case 'kilogram': NewUnit = 'lb'; ConvertedUnit = parseFloat(SelectedUnitValue * 2.205).toFixed(2); break; case 'pound': case 'pounds': case 'lb': case 'lbs': NewUnit = 'kg'; ConvertedUnit = parseFloat(SelectedUnitValue / 2.205).toFixed(2); break; case 'ounce': case 'ounces': case 'oz': case 'ozs': NewUnit = 'g'; ConvertedUnit = parseFloat(SelectedUnitValue * 28.35).toFixed(2); break; case 'g': case 'gram': case 'grams': NewUnit = 'oz'; ConvertedUnit = parseFloat(SelectedUnitValue / 28.35).toFixed(2); break; case 'kilometer': case 'kilometers': NewUnit = 'mi'; ConvertedUnit = parseFloat(SelectedUnitValue / 1.609).toFixed(2); break; case 'kph': case 'kphs': case 'km/h': case 'km/hs': case 'kilometers per hour': case 'kilometers per hours': NewUnit = 'mph'; ConvertedUnit = parseFloat(SelectedUnitValue * 0.621371).toFixed(2); break; case 'mph': case 'mphs': case 'meters per hour': case 'meters per hours': NewUnit = 'km/h'; ConvertedUnit = parseFloat(SelectedUnitValue / 1.000).toFixed(2); break; case 'mi': case 'mile': case 'miles': NewUnit = 'km'; ConvertedUnit = parseFloat(SelectedUnitValue * 1.609).toFixed(2); break; case '°c': NewUnit = '°F'; ConvertedUnit = parseFloat((SelectedUnitValue * 9 / 5) + 32).toFixed(2); break; case '°f': NewUnit = '°C'; ConvertedUnit = parseFloat((SelectedUnitValue - 32) * 5 / 9).toFixed(2); break; case 'ºc': NewUnit = 'ºF'; ConvertedUnit = parseFloat((SelectedUnitValue * 9 / 5) + 32).toFixed(2); break; case 'ºf': NewUnit = 'ºC'; ConvertedUnit = parseFloat((SelectedUnitValue - 32) * 5 / 9).toFixed(2); break; case 'ml': case 'milliliter': case 'milliliters': NewUnit = 'fl oz (US)'; ConvertedUnit = parseFloat(SelectedUnitValue / 29.574).toFixed(2); break; case 'fl oz (US)': case 'fl oz': case 'fl': case 'fluid ounce': case 'fluid ounces': NewUnit = 'ml'; ConvertedUnit = parseFloat(SelectedUnitValue * 29.574).toFixed(2); break; case 'l': case 'litre': case 'liter': case 'litres': case 'liters': NewUnit = 'gal (US)'; ConvertedUnit = parseFloat(SelectedUnitValue / 3.785).toFixed(2); break; case 'gal': case 'gallon': case 'gallons': NewUnit = 'lt'; ConvertedUnit = parseFloat(SelectedUnitValue * 3.785).toFixed(2); break; case 'yard': case 'yards': case 'yd': NewUnit = 'm'; ConvertedUnit = parseFloat(SelectedUnitValue / 1.094).toFixed(2); break; case 'mm': case 'millimetre': case 'Millimeters': NewUnit = 'in'; ConvertedUnit = parseFloat(SelectedUnitValue / 25.4).toFixed(2); break; case 'ft': case 'feet': case 'feets': NewUnit = 'mt'; ConvertedUnit = parseFloat(SelectedUnitValue * 0.3048).toFixed(2); break; case 'kw': case 'kws': case 'kilowatt': case 'kilowatts': NewUnit = 'mhp'; ConvertedUnit = parseFloat(SelectedUnitValue * 1.341).toFixed(2); break; case 'mhp': case 'mhps': case 'hp': case 'hps': case 'brake horsepower': case 'mechanical horsepower': NewUnit = 'kw'; ConvertedUnit = parseFloat(SelectedUnitValue / 1.341).toFixed(2); break; case 'mpg': case 'mpgs': case 'miles per gallon': case 'miles per gallons': NewUnit = 'l/100km'; ConvertedUnit = parseFloat(235.215 / SelectedUnitValue).toFixed(2); break; case 'l/100km': case 'liters per 100 kilometer': case 'liters per 100 kilometers': NewUnit = 'US mpg'; ConvertedUnit = parseFloat(235.215 / SelectedUnitValue).toFixed(2); break; case 'lq': case 'lqs': case 'liquid quart': case 'liquid quarts': NewUnit = 'l'; ConvertedUnit = parseFloat(SelectedUnitValue / 1.057).toFixed(2); break; case 'liter': case 'liters': NewUnit = 'lqs'; ConvertedUnit = parseFloat(SelectedUnitValue * 1.057).toFixed(2); break; case 'foot-pound': case 'foot-pounds': case 'foot pound': case 'foot pounds': case 'ft-lbs': case 'ft-lb': case 'ft lbs': case 'ft lb': case 'lb ft': case 'lb fts': NewUnit = 'Nm'; ConvertedUnit = parseFloat(SelectedUnitValue * 1.3558179483).toFixed(2); break; case 'newton-meter': case 'newton-meters': case 'newton meter': case 'newton meters': case 'nm': NewUnit = 'ft lb'; ConvertedUnit = parseFloat(SelectedUnitValue / 1.3558179483).toFixed(2); break; case (SelectedText.match(Units)[2].replaceAll(',', '.').match(/\^/)).input: NewUnit = 'power'; ConvertedUnit = Math.pow(parseFloat(SelectedUnitValue), parseFloat(SelectedText.split('^')[1])); break; } ShowConvertion('Units', NewUnit, ConvertedUnit); } } //Menu ___________________________________________________________________________________________________________________________________________________________________________ if (shadowRoot.querySelector("#SearchBTN").innerText === 'Open') //If the Search BTN text is 'Open' { shadowRoot.querySelector("#highlight_menu > ul").style.paddingInlineStart = '19px'; //Increase the menu size shadowRoot.querySelector("#SearchBTN").innerText = 'Search'; //Display the BTN text as Search again shadowRoot.querySelector("#OpenAfter").remove(); //Remove the custom Open white hover overlay SelectedTextIsLink = false; //Make common words searchable again } if (SelectedText.match(Links) !== null) //If the selected text is a link { SelectedTextIsLink = true; 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 a custom Open white hover overlay } shadowRoot.querySelector("#SearchBTN").onmousedown = function() { var LinkfyOrSearch = 'https://www.google.com/search?q='; if (SelectedTextIsLink === true) { LinkfyOrSearch = 'https://'; //Make the non-HTTP and non-HTTPS links able to be opened } if (SelectedText.match(/http:|https:/) !== null) //If the selected text is a link that already has HTTP or HTTPS { LinkfyOrSearch = ''; //Remove the https:// that was previously added to this variable } GM_openInTab(LinkfyOrSearch + SelectedTextSearch, { //Open google and search for the selected text active: true, setParent: true, loadInBackground: true }); 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").classList.remove('show'); //Hide the menu }; const menu = shadowRoot.querySelector("#highlight_menu"); if (document.getSelection().toString().trim() !== '') { //If text has been selected const p = document.getSelection().getRangeAt(0).getBoundingClientRect(); //Store the selected position menu.classList.add('show'); //Show the menu menu.offsetHeight; //Trigger reflow by forcing a style calculation menu.style.left = p.left + (p.width / 2) - (menu.offsetWidth / 2) + 'px'; menu.style.top = p.top - menu.offsetHeight - 10 + 'px'; menu.classList.add('highlight_menu_animate'); return; //Keep the menu open } menu.classList.remove('show'); //Hide the menu shadowRoot.querySelectorAll("#SearchBTN span")?.forEach(el => el.remove()); //Return previous HTML }); }); //AI Menu ___________________________________________________________________________________________________________________________________________________________________________ var audio, Generating, isRecognizing = false; 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' }); 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 svg colors to white const TextColor = BGColor === '#e7edf1' ? 'black' : 'white'; //Depending on 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 = ' '; shadowRoot.innerHTML = (html => BypassTT?.createHTML(html) || html)(`

Page Context

Tab

${GeminiSVG}
PAGE CONTEXT
`); //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 Generate(Prompt, button) { //Call the AI endpoint const context = !!shadowRoot.querySelector("#context.show") ? `(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() { Generating = setInterval(function() { //Start the interval to change the text if (shadowRoot.querySelector("#finalanswer").innerText === 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ▋') { shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ'; } else { //Toggle between showing and hiding ▋ shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ▋'; } }, 200); } 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) { clearInterval(Generating); //Stop showing ▋ shadowRoot.querySelector("#finalanswer").innerHTML = `
Please copy and paste the error below:
Click here to report this bug

Prompt: ${Prompt}
Button: ${button}
Error: ${err}}


`; //Show an error message }, onload: function(response) { clearInterval(Generating); //Stop showing ▋ const AIResponse = JSON.parse(response.responseText).candidates?.[0]?.content?.parts?.[0]?.text; if (AIResponse !== undefined) { shadowRoot.querySelector("#finalanswer").innerHTML = (html => BypassTT?.createHTML(html) || html)(marked.parse(AIResponse) + '
'); //Show the parsed AI response } else { shadowRoot.querySelector("#finalanswer").innerHTML = `
Please copy and paste the error below:
Click here to report this bug

Prompt: ${Prompt}
Button: ${button}
Error: ${response.responseText}


`; //Show an error message } 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() { shadowRoot.querySelector("#copyAnswer").style.display = 'none'; shadowRoot.querySelector("#AnswerCopied").style.display = 'inline-flex'; navigator.clipboard.writeText(AIResponse.replace(/(\*\*|##)/g, '')); //Copy the AI response without duplicated symbols setTimeout(() => { //Return play BTN svg shadowRoot.querySelector("#copyAnswer").style.display = 'inline-flex'; shadowRoot.querySelector("#AnswerCopied").style.display = 'none'; }, 1000); }; shadowRoot.querySelector("#dictate").classList.add('show'); //Show the dictate BTN shadowRoot.querySelector("#TopPause").classList.remove('show'); //Hide the TopPause BTN shadowRoot.querySelector("#AIMenu").classList.add('show'); //Show the AIMenu BTN shadowRoot.querySelector("#prompt").focus(); }, onabort: function(response) { clearInterval(Generating); //Stop showing ▋ shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤResponse has been interrupted.'; shadowRoot.querySelector("#dictate").classList.add('show'); //Show the dictate BTN shadowRoot.querySelector("#copyAnswer").style.display = 'none'; //Hide the copy AI answer BTN shadowRoot.querySelector("#TopPause").classList.remove('show'); //Hide the TopPause BTN shadowRoot.querySelector("#AIMenu").classList.add('show'); //Show the AIMenu BTN shadowRoot.querySelector("#speak").style.display = 'none'; //Hide the speak BTN }, onloadstart: function(response) { shadowRoot.querySelector("#dictate").classList.remove('show'); //Hide the dictate BTN shadowRoot.querySelector("#TopPause").classList.add('show'); //Show the TopPause BTN shadowRoot.querySelector("#AIAnswer").innerHTML = (html => BypassTT?.createHTML(html) || html)(`
${msg}
${GeminiSVG}
`); //Create the AI menu HTML var transcript = ""; //Add words startGeneratingText(); shadowRoot.querySelector("#CloseOverlay").classList.add('show'); //Show a black overlay var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition; var recognition = new SpeechRecognition(); recognition.interimResults = true; //Show partial results recognition.continuous = true; //Keep listening until stopped shadowRoot.querySelector("#highlight_menu").classList.remove('show'); //Hide the mini menu on the page shadowRoot.querySelectorAll("#AIBox, .animated-border, #AIBox.AnswerBox").forEach(el => el.classList.add('show')); //Show the AI input and box getSelection().removeAllRanges(); //UnSelect the selected text so that if the user clicks on a previously selected text the menu won't show up again shadowRoot.querySelector("#CloseOverlay").onclick = function() { shadowRoot.querySelectorAll("#AIBox, .animated-border, #AIBox.AnswerBox").forEach(el => el.classList.remove('show')); //Hide the AI input and box this.classList.remove('show'); 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 shadowRoot.querySelector("#AddContext").remove(); //Return original prompt input styles shadowRoot.querySelector("#context").classList.remove('show'); //Hide the context view shadowRoot.querySelector("#prompt").placeholder = 'Enter your prompt to Gemini'; //Return default placeholder } }; shadowRoot.querySelector("#TopPause").onclick = function() { shadowRoot.querySelector("#dictate").classList.add('show'); //Show the dictate BTN shadowRoot.querySelector("#TopPause").classList.remove('show'); //Hide the TopPause BTN request.abort(); //Abort the request }; recognition.onend = function() { 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); //Stop the voice recording animation }); isRecognizing = false; transcript !== '' ? Generate(transcript, shadowRoot.querySelector("#prompt").className) : shadowRoot.querySelector("#finalanswer").innerHTML = `
No audio detected. Please try again or check your mic settings.ㅤㅤㅤㅤㅤㅤㅤㅤㅤ

`; //Call the AI API if audio has been detected or show an error message }; //Finish the recognition end event listener recognition.onresult = function(event) { //Handle voice recognition results 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 } shadowRoot.querySelector("#msg").innerText = transcript.length > 240 ? transcript.slice(0, 240) + '…' : transcript; //Display recognized words }; shadowRoot.querySelector("#dictate").onclick = function() { if (isRecognizing) { recognition.stop(); } else { isRecognizing = true; recognition.start(); shadowRoot.querySelectorAll('.state1, .state2, .state3').forEach((state, index) => { //ForEach SVG animation state state.style.display = 'unset'; //Show all states state.classList.add('animate'+index); //Start the voice recording animation }); } }; var desiredVoice = null; 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) { audio.voice = desiredVoice; //Use the desiredVoice speechSynthesis.speak(audio); //Speak the text } shadowRoot.querySelectorAll("#speak, #bottompause").forEach(function(el) { el.onclick = function() { //When speak or the bottom pause BTNs are clicked if (speechSynthesis.speaking) { speechSynthesis.cancel(); shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN shadowRoot.querySelector("#bottompause").classList.remove('show'); //Hide the pause BTN } else { shadowRoot.querySelector("#speak").style.display = 'none'; //Hide the play BTN shadowRoot.querySelector("#bottompause").classList.add('show'); //Show the pause BTN speakText(audio); //Speak the AI reponse text audio.onend = (event) => { shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN shadowRoot.querySelector("#bottompause").classList.remove('show'); //Hide the pause BTN }; } }; }); shadowRoot.querySelector("#NewAnswer").onclick = function() { shadowRoot.querySelector("#dictate").classList.remove('show'); //Hide the dictate BTN shadowRoot.querySelector("#TopPause").classList.add('show'); //Show the top pause BTN Generate(Prompt, button); //Call the AI API }; } //Finish the onloadstart event listener });//Finish the GM.xmlHttpRequest function } //Finish the Generate function shadowRoot.querySelector("#prompt").addEventListener("keydown", (event) => { if (event.key === "Enter") { Generate(shadowRoot.querySelector("#prompt").value, shadowRoot.querySelector("#prompt").className); //Call the AI API shadowRoot.querySelector("#prompt").value = ''; //Erase the prompt text } if (event.key === "Tab") { if (shadowRoot.querySelector("#prompt").placeholder.match('using')) { //If the input bar contains the word "using" shadowRoot.querySelector("#AddContext").remove(); //Return original prompt input styles shadowRoot.querySelector("#context").classList.remove('show'); //Hide the context view shadowRoot.querySelector("#prompt").placeholder = 'Enter your prompt to Gemini'; //Return default placeholder } else { shadowRoot.querySelector("#context").classList.add('show'); //Show the context view shadowRoot.querySelector("#prompt").placeholder = `Gemini is using ${location.host.replace('www.','')} for context...`; //Change placeholder shadowRoot.querySelector("#highlight_menu").insertAdjacentHTML('beforebegin', ` `); //Show the context bar } } setTimeout(() => { //Wait for the code above to execute shadowRoot.querySelector("#prompt").focus(); //Refocus on the input bar }, 0); }); if (document.body.textContent !== '' || document.body.innerText !== '') //If the body has any text { document.body.appendChild(HtmlMenu); //Add the script menu div container } shadowRoot.querySelectorAll("#AIBTN").forEach(function(button) { button.onmousedown = function(event,i) { //When the Explore or the Translate BTNs are clicked if (GM_getValue("APIKey") === undefined || GM_getValue("APIKey") === null || GM_getValue("APIKey") === '') { //Set up the API Key if it isn't already set GM_setValue("APIKey", prompt('Enter your API key\n*Press OK')); } if (GM_getValue("APIKey") !== null && GM_getValue("APIKey") !== '') { Generate(SelectedText, this.className); //Call the AI API } }; }); //Allow the script in iframes__________________________________________________________________________________________________________________________________________________________________ setTimeout(function() { const AllIframes = document.querySelectorAll("iframe"); for (var i = AllIframes.length; i--;) { if (AllIframes[i].allow.match('clipboard-write;') === null && AllIframes[i].src.match(Links) !== null && AllIframes[i].src.match(/recaptcha|(rt|hrms.*.*.edu)|challenges.cloudflare|youtube|dailymotion|vimeo|streamtape|mcloud|vidstream|dood.wf|mp4upload|googlevideo|kaltura|crunchyroll|animesup|embtaku.pro|aniwave.se\/ajax|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 { 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 } } }, 4000); window.addEventListener('scroll', async function() { shadowRoot.querySelector("#highlight_menu").classList.remove('show'); //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 } }); }