Replace Google AI Studio Redirect Links with Actual Links (Link Auto-cleaner)

Replaces Google redirect URLs on Google AI Studio with their actual destination links. It will replace the redirect URLs once they appear.

// ==UserScript==
// @name         Replace Google AI Studio Redirect Links with Actual Links (Link Auto-cleaner)
// @namespace    Violentmonkey userscripts by ReporterX
// @author       ReporterX
// @version      1.0
// @description  Replaces Google redirect URLs on Google AI Studio with their actual destination links. It will replace the redirect URLs once they appear. 
// @match        https://aistudio.google.com/*
// @grant        GM_xmlhttpRequest
// @connect      vertexaisearch.cloud.google.com
// @run-at       document-idle
// @icon         https://www.google.com/s2/favicons?domain=aistudio.google.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Use a Set to keep track of links that are being processed or have been processed.
    const processedLinks = new WeakSet();

    function resolveFinalUrl(link) {
        // Mark the link as processed to avoid repeated requests.
        processedLinks.add(link);

        GM_xmlhttpRequest({
            method: "HEAD",
            url: link.href,
            onload: function(response) {
                if (response.finalUrl && response.finalUrl !== link.href) {
                    link.href = response.finalUrl;
                    // Optional: Add a visual indicator that the link has been resolved.
                    link.style.textDecoration = "underline";
                    link.style.color = '#1a0dab'; // A more traditional "visited" link color
                }
            },
            onerror: function(error) {
                console.error("Userscript Error: Could not fetch final URL for", link.href, error);
                 // Optional: Style the link to indicate an error occurred.
                link.style.color = 'red';
            }
        });
    }


    function cleanAllRedirects() {
        const links = document.querySelectorAll('a[href*="google.com/url?"], a[href*="vertexaisearch.cloud.google.com"]');

        links.forEach(link => {
            if (processedLinks.has(link)) {
                return;
            }

            let currentHref = link.href;

            // First, handle the initial google.com/url redirect if it exists.
            if (currentHref.includes('google.com/url?')) {
                 try {
                    const url = new URL(currentHref);
                    const destination = url.searchParams.get('q');
                    if (destination) {
                        currentHref = decodeURIComponent(destination);
                        link.href = currentHref; // Set the intermediate href
                    }
                } catch (e) {
                    console.error("Userscript Error: Failed to parse Google redirect URL.", e);
                    processedLinks.add(link); // Mark as processed to avoid retrying a bad link
                    return;
                }
            }


            // Now, if the link is a vertex AI redirect, resolve it to its final destination.
            if (currentHref.includes('vertexaisearch.cloud.google.com')) {
                 // Change link style to indicate it's being processed
                link.style.color = '#5f6368'; // A muted color
                link.style.textDecoration = 'underline dotted';
                resolveFinalUrl(link);
            } else {
                 // If it was just a standard google.com/url, we're done with it.
                 processedLinks.add(link);
            }
        });
    }

    // Run the function on initial page load.
    cleanAllRedirects();

    // Use a MutationObserver to handle dynamically loaded content efficiently.
    const observer = new MutationObserver(cleanAllRedirects);
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
})();