imgur to rimgo image redirector

redirects imgur <img> tags to a randomly selected rimgo instance

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         imgur to rimgo image redirector
// @namespace    http://tampermonkey.net/
// @version      2025.11.28
// @description  redirects imgur <img> tags to a randomly selected rimgo instance
// @author       infinitysnapz
// @match        *://*/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=imgur.com
// @license     MIT; http://opensource.org/licenses/MIT
// @grant        GM_xmlhttpRequest
// ==/UserScript==

// based on:
//Imgur to Rimgo redirect v0.1.4 by 0b9
//https://gist.github.com/wont-work/e1f00fcc6c44b05a312573379b649afa#file-free-overjoyed-anywhere-you-go-user-js by kopper

(function() {
    'use strict';

    const apiUrl = 'https://rimgo.codeberg.page/api.json';
    const instancediscovery = 'https://rimgo.codeberg.page';

    var eligible = {};

    var broken = [

        "imgur.010032.xyz", // dead domain
        "projectsegfau.lt", // all private instances being shut down
        "rmgur.com", // dead domain
        "rimgo.frylo.net", // dead domain
        "rimgo.fascinated.cc", // 404 not found
        "rimgo.totaldarkness.net", // dead domain/times out
        "rimgo.quantenzitrone.eu", //error 502, keeps breaking
        "rimgo.reallyaweso.me", // keeps breaking

        "rimgo.darkness.services", // has anubis check
        "imgur.artemislena.eu", // has anubis check
        "rimgo.bloat.cat", // has anubis check and appears to be down
        "imgur.nerdvpn.de", // has anubis check
        "rg.kuuro.net", // has anubis check
        "rimgo.aketawi.space", // has anubis check
        // as amazing as anubis is in the fight against bots and AI, it means we cannot embed images from these sites properly.

        "drgns.space", //under maintenance, will check back later
        "rimgo.proxik.cloud", //cloudflare error, check back later
        "rimgo.thebunny.zone", //error 502
        //temporary dead domains

        //"r.opnxng.com",                             //second chance! testing, might still have anubis check
        //"imgur.sudovanilla.org",                    //second chance! formerly times out
        //"nohost.network",                           //second chance! formerly times out
        //"rimgo.lunar.icu",                          //second chance! formerly error 502
        //"rimgo.privacyredirect.com",                //second chance! formerly error 502
        //second chancers, domains that were down, but are back now!

    ];// soo many broken instances wtf

    const generateHash = (string) => { // hash, to allow us to cache images easier and reduce load on
        let hash = 0;
        for (const char of string) {
            hash = (hash << 5) - hash + char.charCodeAt(0);
            hash |= 0; // Constrain to 32bit integer
        }
        return hash;
    };

    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            for (const node of mutation.addedNodes) {
                walk(node);
            }
        }
    });

    /**
 * @param {Node} root
 */
    function walk(root) {
        if (!root.ownerDocument) throw "assertion falied: no owner document";

        const walker = root.ownerDocument.createNodeIterator(
            root,
            NodeFilter.SHOW_ELEMENT,
            (node) => {
                if (node.nodeType == Node.ELEMENT_NODE && node.shadowRoot) {return NodeFilter.FILTER_ACCEPT};

                if (node.nodeName == "STYLE" || node.nodeName == "SCRIPT") {return NodeFilter.FILTER_REJECT};

                if (node.nodeName == "IMG"){return NodeFilter.FILTER_ACCEPT};


                return NodeFilter.FILTER_SKIP;
            });

        /** @type {Node|null} */let node;
        node = walker.nextNode();
        while ((node = walker.nextNode())) {
            if (node.shadowRoot) {
                for (const child of node.shadowRoot.children) {
                    if (child.nodeName == "STYLE" || child.nodeName == "SCRIPT") continue;
                    walk(child);
                }

                observer.observe(node.shadowRoot, observerConfig);
                continue;
            };

            if (!node.nodeName == "IMG") continue;
            redirectImg(node);

        }
    }

    const observerConfig = {
        childList: true,
        subtree: true,
    };

    const redirectImg = (elem) => {
          const imgsrc = elem.src
          if (/https?:\/\/(\w+\.)?imgur.com\/(\w*)+(\.[a-zA-Z]{3,4})/.test(imgsrc)){
              const path = imgsrc.substring(imgsrc.indexOf("/", 8));
              const instanceUrl = eligible[Math.abs(generateHash(path) % eligible.length)].url
              const newUrl = `${instanceUrl}/${path.startsWith("/") ? path.slice(1) : path}`;
              elem.src = newUrl;
          };
    };

    GM_xmlhttpRequest({
        method: "GET",
        url: apiUrl,
        onload: function (response) {
            try {
                const data = JSON.parse(response.responseText);
                eligible = data.clearnet.filter(inst => inst.note.includes("✅ Data not collected"));
                eligible = eligible.filter(inst => !(new RegExp( '\\b' + broken.join('\\b|\\b') + '\\b') ).test(inst.url) );
                console.log(eligible)
                walk(document.body)
                observer.observe(document.body, observerConfig);
            } catch (e) {
                console.error("JSON parsing failed, no image redirecting will occur.", e);
            }
        },
        onerror: function (err) {
            console.error("Request failed, no image redirecting will occur.", err);
        }
    });

})();