Twitter to Nitter Redirector

Redirects Twitter/X.com to Nitter.net. Skips if ?nonitter is present and appends ?nonitter to links (see: Nitter/Nonitter Companion for Twitter to Nitter Redirector with Skip)

// ==UserScript==
// @name        Twitter to Nitter Redirector
// @namespace   https://greasyfork.org/nl/users/1197317-opus-x
// @version      1.02
// @description Redirects Twitter/X.com to Nitter.net. Skips if ?nonitter is present and appends ?nonitter to links (see: Nitter/Nonitter Companion for Twitter to Nitter Redirector with Skip)
// @author      Opus-X
// @license     MIT
// @match       https://x.com/*
// @match       https://twitter.com/*
// @exclude-match https://x.com/
// @exclude-match https://x.com/home
// @exclude-match https://x.com/explore
// @exclude-match https://x.com/notifications
// @exclude-match https://x.com/messages
// @exclude-match https://x.com/i/*
// @exclude-match https://x.com/bookmarks
// @exclude-match https://x.com/*/communities
// @exclude-match https://x.com/compose
// @exclude-match https://x.com/intent/tweet
// @exclude-match https://twitter.com/
// @exclude-match https://twitter.com/home
// @exclude-match https://twitter.com/explore
// @exclude-match https://twitter.com/notifications
// @exclude-match https://twitter.com/messages
// @exclude-match https://twitter.com/i/*
// @exclude-match https://twitter.com/bookmarks
// @exclude-match https://twitter.com/*/communities
// @exclude-match https://twitter.com/compose
// @exclude-match https://twitter.com/intent/tweet
// @grant       none
// @run-at      document-start
// ==/UserScript==

(function () {
    'use strict';

    const NITTER = 'nitter.net';

    const currentURL = window.location.href;
    const hasNonitter = currentURL.includes('?nonitter') || currentURL.includes('&nonitter');
    const isRootOrHome = /^https:\/\/(x|twitter)\.com(\/|\/home)?$/.test(currentURL);

    if (hasNonitter || isRootOrHome) {
        // Skip redirect and append ?nonitter to links
        document.addEventListener('DOMContentLoaded', function() {
            function appendNonitter() {
                const links = document.querySelectorAll('a[href*="x.com"], a[href*="twitter.com"], a[href*="t.co"], a[href^="/"]');
                links.forEach(link => {
                    let href = link.getAttribute('href');
                    if (href.startsWith('/')) {
                        href = 'https://x.com' + href;
                    }
                    if (!href.includes('?nonitter') && !href.includes('&nonitter')) {
                        if (href.includes('?')) {
                            link.href = href + '&nonitter';
                        } else {
                            link.href = href + '?nonitter';
                        }
                    }
                });
            }

            appendNonitter();

            const observer = new MutationObserver(appendNonitter);
            observer.observe(document.body, { childList: true, subtree: true });

            setTimeout(appendNonitter, 2000);
        });
        if (isRootOrHome && !hasNonitter) {
            window.location.assign(currentURL + (currentURL.includes('?') ? '&nonitter' : '?nonitter'));
        }
        return;
    }

    const redirectedURL = currentURL.replace(/^https:\/\/(x|twitter)\.com/, `https://${NITTER}`);

    if (redirectedURL !== currentURL) {
        window.location.assign(redirectedURL);
    }
})();