Aistudio Redirect Bypass

Automatically replace Google redirect URLs on AI Studio with their actual destination links.

// ==UserScript==
// @name         Aistudio Redirect Bypass
// @namespace    https://greasyfork.org/
// @version      1.0
// @description  Automatically replace Google redirect URLs on AI Studio with their actual destination links.
// @author       Bui Quoc Dung
// @match        https://aistudio.google.com/*
// @grant        GM_xmlhttpRequest
// @connect      vertexaisearch.cloud.google.com
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  function resolveRedirect(googleUrl, callback) {
    let intermediateUrl;
    try {
      const urlObj = new URL(googleUrl);
      intermediateUrl = urlObj.searchParams.get('q');
    } catch (e) {
      callback(null);
      return;
    }

    if (!intermediateUrl) {
      callback(null);
      return;
    }

    GM_xmlhttpRequest({
      method: 'HEAD',
      url: intermediateUrl,
      onload: function (response) {
        if (response.finalUrl && response.finalUrl !== intermediateUrl) {
          callback(response.finalUrl.trim());
        } else {
          callback(null);
        }
      },
      onerror: function () {
        callback(null);
      }
    });
  }

  function fixAnchor(a) {
    const href = a.getAttribute('href');
    if (!href || !href.startsWith('https://www.google.com/url') || a.dataset.linkFixed) {
      return;
    }
    a.dataset.linkFixed = 'processing';
    resolveRedirect(href, realLink => {
      if (realLink) {
        a.setAttribute('href', realLink);
        a.dataset.linkFixed = 'true';
      } else {
        a.dataset.linkFixed = 'failed';
      }
    });
  }

  function scanAndFixAnchors() {
    document.querySelectorAll('a.ng-star-inserted[href^="https://www.google.com/url"]:not([data-link-fixed])').forEach(fixAnchor);
  }

  scanAndFixAnchors();

  const observer = new MutationObserver(mutations => {
    for (const mutation of mutations) {
      if (mutation.addedNodes.length > 0) {
        mutation.addedNodes.forEach(node => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            if (node.matches('a.ng-star-inserted[href^="https://www.google.com/url"]:not([data-link-fixed])')) {
              fixAnchor(node);
            }
            node.querySelectorAll('a.ng-star-inserted[href^="https://www.google.com/url"]:not([data-link-fixed])').forEach(fixAnchor);
          }
        });
      }
    }
  });

  observer.observe(document.body, { childList: true, subtree: true });
})();