Instantly share code, notes, and snippets.
Created
October 31, 2025 12:23
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save SaeedX302/580a161a485f723f2d99c1de8ce3d35f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name AI Navigation Bar (BETA) | |
| // @namespace http://tampermonkey.net/ | |
| // @version 3.0 | |
| // @description Automatically clicks the "Try GPT-5" button and adds navigation buttons to AI chat services | |
| // @author You | |
| // @match https://m365.cloud.microsoft/* | |
| // @match https://claude.ai/* | |
| // @match https://chatgpt.com/* | |
| // @match https://chat.deepseek.com/* | |
| // @match https://gemini.google.com/* | |
| // @match https://www.perplexity.ai/* | |
| // @grant GM_xmlhttpRequest | |
| // @connect favicon.yandex.net | |
| // @homepage https://greasyfork.org/en/scripts/550204-ai-navigation-bar | |
| // @downloadURL https://update.greasyfork.org/scripts/550204/AI%20Navigation%20Bar.user.js | |
| // @updateURL https://update.greasyfork.org/scripts/550204/AI%20Navigation%20Bar.meta.js | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // Navigation buttons configuration | |
| const navButtons = [ | |
| { name: 'M365', url: 'https://m365.cloud.microsoft' }, | |
| { name: 'Gemini', url: 'https://gemini.google.com' }, | |
| { name: 'Anthropic', url: 'https://claude.ai' }, | |
| { name: 'ChatGPT', url: 'https://chatgpt.com' }, | |
| { name: 'DeepSeek', url: 'https://chat.deepseek.com' }, | |
| { name: 'Perplexity', url: 'https://www.perplexity.ai' } | |
| ]; | |
| // Cache for favicon data URLs | |
| const faviconCache = {}; | |
| // Extract domain from URL | |
| function getDomain(url) { | |
| try { | |
| const hostname = new URL(url).hostname; | |
| return hostname; | |
| } catch (e) { | |
| console.error('Invalid URL:', url); | |
| return ''; | |
| } | |
| } | |
| // Check if URL matches current domain | |
| function isSameDomain(url) { | |
| try { | |
| const targetDomain = new URL(url).hostname; | |
| const currentDomain = window.location.hostname; | |
| return targetDomain === currentDomain; | |
| } catch (e) { | |
| return false; | |
| } | |
| } | |
| // Fetch favicon using GM_xmlhttpRequest and convert to data URL | |
| function getFaviconDataUrl(domain) { | |
| return new Promise((resolve) => { | |
| if (faviconCache[domain]) { | |
| resolve(faviconCache[domain]); | |
| return; | |
| } | |
| const faviconUrl = `https://favicon.yandex.net/favicon/v2/${domain}?size=32`; | |
| GM_xmlhttpRequest({ | |
| method: 'GET', | |
| url: faviconUrl, | |
| responseType: 'blob', | |
| onload: function(response) { | |
| const reader = new FileReader(); | |
| reader.onloadend = function() { | |
| faviconCache[domain] = reader.result; | |
| console.log(`✓ Favicon loaded for ${domain}`); | |
| resolve(reader.result); | |
| }; | |
| reader.readAsDataURL(response.response); | |
| }, | |
| onerror: function(error) { | |
| console.error(`✗ Favicon failed for ${domain}:`, error); | |
| resolve(null); | |
| } | |
| }); | |
| }); | |
| } | |
| // Create navigation bar | |
| async function createNavigationBar() { | |
| // Check if nav bar already exists | |
| if (document.getElementById('ai-nav-bar')) return; | |
| const navBar = document.createElement('div'); | |
| navBar.id = 'ai-nav-bar'; | |
| navBar.style.cssText = ` | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| background: transparent; | |
| padding: 6px; | |
| display: flex; | |
| gap: 6px; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 999999; | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| pointer-events: none; | |
| `; | |
| for (const btn of navButtons) { | |
| const isCurrentSite = isSameDomain(btn.url); | |
| // Skip adding the button for the current site | |
| if (isCurrentSite) { | |
| continue; | |
| } | |
| const button = document.createElement('button'); | |
| button.style.cssText = ` | |
| background: rgba(45, 45, 45, 0.9); | |
| color: #e0e0e0; | |
| border: 1px solid #404040; | |
| padding: 5px 12px; | |
| border-radius: 20px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| font-size: 12px; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.3); | |
| backdrop-filter: blur(10px); | |
| pointer-events: auto; | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| `; | |
| // Extract domain and fetch favicon as data URL | |
| const domain = getDomain(btn.url); | |
| if (domain) { | |
| const faviconDataUrl = await getFaviconDataUrl(domain); | |
| if (faviconDataUrl) { | |
| const favicon = document.createElement('img'); | |
| favicon.src = faviconDataUrl; | |
| favicon.alt = btn.name; | |
| favicon.style.cssText = ` | |
| width: 16px; | |
| height: 16px; | |
| object-fit: contain; | |
| flex-shrink: 0; | |
| `; | |
| button.appendChild(favicon); | |
| } | |
| } | |
| // Add text | |
| const text = document.createElement('span'); | |
| text.textContent = btn.name; | |
| button.appendChild(text); | |
| // Hover effects | |
| button.onmouseenter = () => { | |
| button.style.background = 'rgba(61, 61, 61, 0.95)'; | |
| button.style.borderColor = '#505050'; | |
| button.style.transform = 'translateY(-1px)'; | |
| button.style.boxShadow = '0 3px 6px rgba(0,0,0,0.4)'; | |
| }; | |
| button.onmouseleave = () => { | |
| button.style.background = 'rgba(45, 45, 45, 0.9)'; | |
| button.style.borderColor = '#404040'; | |
| button.style.transform = 'translateY(0)'; | |
| button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.3)'; | |
| }; | |
| button.onclick = () => { | |
| // Different domain: open in new tab | |
| window.open(btn.url, '_blank'); | |
| }; | |
| navBar.appendChild(button); | |
| } | |
| // Add to page | |
| document.body.insertBefore(navBar, document.body.firstChild); | |
| console.log('Navigation bar created successfully!'); | |
| } | |
| // Original auto-click functionality | |
| let attempts = 0; | |
| const maxAttempts = 20; | |
| const delay = 500; | |
| const editorDelay = 1000; | |
| let buttonClicked = false; | |
| let editorClicked = false; | |
| function findAndClickButton() { | |
| if (buttonClicked) return; | |
| attempts++; | |
| console.log(`Attempt ${attempts}: Looking for GPT-5 button...`); | |
| const buttons = document.querySelectorAll('button[aria-pressed="false"]'); | |
| let found = false; | |
| buttons.forEach(button => { | |
| if (button.textContent.includes("Try GPT-5") && !buttonClicked) { | |
| console.log("Found GPT-5 button, clicking..."); | |
| button.click(); | |
| found = true; | |
| buttonClicked = true; | |
| setTimeout(() => { | |
| findAndClickEditor(); | |
| }, editorDelay); | |
| } | |
| }); | |
| if (found) { | |
| console.log("GPT-5 button clicked successfully!"); | |
| observer.disconnect(); | |
| return; | |
| } | |
| if (attempts < maxAttempts && !buttonClicked) { | |
| setTimeout(findAndClickButton, delay); | |
| } else if (!buttonClicked) { | |
| console.log("Max attempts reached, GPT-5 button not found"); | |
| } | |
| } | |
| function findAndClickEditor() { | |
| if (editorClicked) return; | |
| console.log("Looking for chat editor element..."); | |
| const editorElement = document.getElementById('m365-chat-editor-target-element'); | |
| if (editorElement) { | |
| console.log("Found chat editor element, clicking..."); | |
| editorElement.click(); | |
| editorClicked = true; | |
| console.log("Chat editor element clicked successfully!"); | |
| } else { | |
| console.log("Chat editor element not found yet"); | |
| } | |
| } | |
| // Initialize navigation bar with delay | |
| function initNavigationBar() { | |
| // Wait for page to fully load and settle | |
| setTimeout(() => { | |
| createNavigationBar(); | |
| // Re-check periodically in case it gets hidden or removed | |
| // Run checks every 2 seconds for the first 1 minute | |
| let checkCount = 0; | |
| const maxChecks = 30; // 30 checks × 2 seconds = 1 minute | |
| const intervalId = setInterval(() => { | |
| checkCount++; | |
| if (!document.getElementById('ai-nav-bar')) { | |
| console.log('Navigation bar was removed, recreating...'); | |
| createNavigationBar(); | |
| } | |
| // Stop checking after 2 minutes | |
| if (checkCount >= maxChecks) { | |
| clearInterval(intervalId); | |
| console.log('Navigation bar monitoring stopped after 1 minute'); | |
| } | |
| }, 2000); | |
| }, 300); // Wait 0.3 seconds after page load | |
| } | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', initNavigationBar); | |
| } else if (document.readyState === 'interactive') { | |
| initNavigationBar(); | |
| } else { | |
| // Page already fully loaded | |
| initNavigationBar(); | |
| } | |
| // Original auto-click initialization (M365 ONLY) | |
| const isM365 = window.location.hostname.includes('m365.cloud.microsoft'); | |
| if (isM365) { | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', () => { | |
| setTimeout(findAndClickButton, 1000); | |
| }); | |
| } else { | |
| setTimeout(findAndClickButton, 1000); | |
| } | |
| window.addEventListener('load', () => { | |
| setTimeout(findAndClickButton, 2000); | |
| }); | |
| const observer = new MutationObserver((mutations) => { | |
| if (buttonClicked) return; | |
| mutations.forEach((mutation) => { | |
| if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { | |
| mutation.addedNodes.forEach((node) => { | |
| if (node.nodeType === 1 && (node.tagName === 'BUTTON' || node.querySelector('button'))) { | |
| setTimeout(findAndClickButton, 500); | |
| } | |
| }); | |
| } | |
| }); | |
| }); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| setTimeout(() => { | |
| observer.disconnect(); | |
| console.log("MutationObserver disconnected"); | |
| }, 30000); | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment