Lemmy Universal Link Rewriter

Ensures that all URLs to Lemmy instances always point to your main/home instance.

目前為 2023-06-25 提交的版本,檢視 最新版本

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Lemmy Universal Link Rewriter
// @namespace    http://azzurite.tv/
// @license      GPLv3
// @version      1.1.1
// @description  Ensures that all URLs to Lemmy instances always point to your main/home instance.
// @source       https://gitlab.com/azzurite/lemmy-rewrite-links
// @author       Azzurite
// @match        *://*/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=join-lemmy.org
// @grant        GM.setValue
// @grant        GM.getValue
// @require      https://unpkg.com/@popperjs/core@2
// @require      https://unpkg.com/tippy.js@6
// ==/UserScript==
"use strict";

const DEBUG = false;

const INSTANCES_LEMMY = lemmyInstances();
const INSTANCES_KBIN = kbinInstances();

const tippy = window.tippy;

const C = createConstants();

const OUR_CHANGES = { addedNodes: {} };

let HOME;
(async () => {
    HOME = await GM.getValue(`home`) || askForHomeIfOnInstance();
    updateHomePeriodically();
    startRewriting();
})();

//=========== FUNCTION DEFINITIONS ===========

function createConstants() {
    return {
        ICON_CLASS: withNS(`icon`),
        ICON_STYLES_ID: withNS(`icon-styles`),
        ICON_GRAPHIC_ID: withNS(`icon-graphic`),
        ORIGINAL_LINK_CLASS: withNS(`original-link`),
        SHOW_AT_HOME_BUTTON_ID: withNS(`show-at-home`),
        MAKE_HOME_BUTTON_ID: withNS(`make-home`),
        ICON_SVG_TEMPLATE_ID: withNS(`icon-template`)
    };
}

function triggerRewrite() {
    const triggerElem = document.createElement(`span`);
    triggerElem.style.display = `none`;
    document.body.append(triggerElem);
    setTimeout(() => {
        triggerElem.remove();
    }, 0);
}

function updateHomePeriodically() {
    debug(`Current HOME`, HOME);
    setInterval(async () => {
        const prev = HOME;

        HOME = await GM.getValue(`home`);

        if (prev !== HOME) {
            debug(`HOME changed from`, prev, `to`, HOME);
            triggerRewrite();
        }
    }, 1337)
}

function isOrHasOurAddedNode(node) {
    return Object.values(OUR_CHANGES.addedNodes).some(selector => node.matches?.(selector) || node.querySelector?.(selector));
}

function isIrrelevantChange(change) {
    if (change.type === `childList`) {
        if (Array.from(change.removedNodes).some(isOrHasOurAddedNode)) {
            trace(`Change`, change, `is relevant because a removed node is/has ours`);
            return false;
        }
        if (!Array.from(change.addedNodes).every(isOrHasOurAddedNode)) {
            trace(`Change`, change, `is relevant because not every added node is/has ours`);
            return false;
        }
    } else if (change.type === `attributes` && isRemoteUrl(new URL(change.target.href))) {
        trace(`Change`, change, `is relevant because href changed to a remote URL`);
        return false;
    }

    trace(`Change`, change, `is irrelevant`);
    return true;
}

async function startRewriting() {
    new MutationObserver((changes, observer) => {
        debug(`MutationObserver triggered`, changes);
        if (changes.every(isIrrelevantChange)) {
            debug(`All observed changes are irrelevant`);
            return;
        }
        doAllDomChanges(changes);
    }).observe(document.body, { 
        subtree: true, 
        childList: true,
        attributeFilter: [ `href` ]
    });

    await doAllDomChanges();
}

async function doAllDomChanges(changes) {
    debug(`doAllDomChanges start`);

    const addedMakeHomeButton = addMakeHomeButton();
    if (addedMakeHomeButton) debug(`Added Make Home Button`);

    const addedShowAtHomeButton = HOME ? addShowAtHomeButton() : false;
    if (addedShowAtHomeButton) debug(`Added Show At Home Button`);

    const rewrittenLinks = HOME ? await rewriteLinksToLocal(changes) : false;
    if (rewrittenLinks) debug(`Rewritten some links`);

    debug(`doAllDomChanges end`);
}

async function askForHomeIfOnInstance() {
    if (INSTANCES_LEMMY.has(location.origin) &&
        confirm(`Set this instance to be your home instance to which all URLs get rewritten to?`)) {

        GM.setValue(`home`, location.origin);
        return location.origin;
    } else {
        return null;
    }
}

function withNS(identifier) {
    return `lemmy-rewrite-urls-` + identifier;
}

function createSVG() { return document.createElementNS(`http://www.w3.org/2000/svg`, `svg`) }

function createIconTooltip(icon, link, originalHref) {
    const content = document.createElement(`span`);
    content.innerHTML = `Original link: <a class="${C.ORIGINAL_LINK_CLASS}" href="${originalHref}">${originalHref}</a>`;
    tippy(icon, {
        content,
        interactive: true,
        appendTo: () => link.parentNode,
        hideOnClick: false
    });
}

function ensureTemplateAvailable() {
    if (document.querySelector(`#` + C.ICON_SVG_TEMPLATE_ID)) return;

    const template = createSVG();
    template.id = C.ICON_SVG_TEMPLATE_ID
    template.innerHTML = `<defs><g id=${C.ICON_GRAPHIC_ID}><path fill=currentColor d="M52.8 34.6c.8.8 1.8 1.2 2.8 1.2s2-.4 2.8-1.2c1.5-1.5 1.5-4 0-5.6l-5.2-5.2h26v30.6c0 2.2 1.8 3.9 3.9 3.9 2.2 0 3.9-1.8 3.9-3.9V19.8c0-2.2-1.8-3.9-3.9-3.9h-30l5.2-5.2c1.5-1.5 1.5-4 0-5.6s-4-1.5-5.6 0l-11.8 12c-1.5 1.5-1.5 4 0 5.6l11.9 11.9zM31.1 28.7V11c0-3-2.5-5.5-5.5-5.5H8C5 5.5 2.5 8 2.5 11v17.7c0 3 2.5 5.5 5.5 5.5h17.7c3 0 5.4-2.5 5.4-5.5zM47.2 65.4c-1.5-1.5-4-1.5-5.6 0s-1.5 4 0 5.6l5.2 5.2h-26V45.6c0-2.2-1.8-3.9-3.9-3.9S13 43.5 13 45.6v34.5c0 2.2 1.8 3.9 3.9 3.9h30l-5.2 5.2c-1.5 1.5-1.5 4 0 5.6.8.8 1.8 1.2 2.8 1.2s2-.4 2.8-1.2l11.9-11.9c1.5-1.5 1.5-4 0-5.6l-12-11.9zM92 65.8H74.4c-3 0-5.5 2.5-5.5 5.5V89c0 3 2.5 5.5 5.5 5.5H92c3 0 5.5-2.5 5.5-5.5V71.3c0-3-2.5-5.5-5.5-5.5z"/></g>`;

    OUR_CHANGES.addedNodes[C.ICON_SVG_TEMPLATE_ID] = `#` + C.ICON_SVG_TEMPLATE_ID;
    document.head.append(template);
}

function ensureIconStylesAdded() {
    if (document.querySelector(`#` + C.ICON_STYLES_ID)) return;

    const style = document.createElement(`style`);
    style.id = C.ICON_STYLES_ID;
    style.innerText = `
    .${C.ICON_CLASS} {
        display: inline-block;
        vertical-align: sub;
        height: 1em; width: 1em;
        margin-left: 0.5em;
    }`;

    OUR_CHANGES.addedNodes[C.ICON_STYLES_ID] = `#` + C.ICON_STYLES_ID;
    document.head.append(style);
}

function createIcon(link, originalHref) {
    ensureTemplateAvailable();

    const icon = createSVG();
    icon.setAttribute(`class`, C.ICON_CLASS);
    ensureIconStylesAdded();
    icon.setAttribute(`viewBox`, `0 0 100 100`);
    icon.innerHTML = `<use href=#${C.ICON_GRAPHIC_ID} />`
    createIconTooltip(icon, link, originalHref);

    const wrapper = document.createElement(`span`);
    wrapper.addEventListener(`click`, (event) => {
        // for mobile so the tooltip can be opened
        event.preventDefault();
        event.stopPropagation();
    });

    OUR_CHANGES.addedNodes[C.ICON_CLASS] = `.` + C.ICON_CLASS;
    wrapper.append(icon);

    return wrapper;
}


function isRemoteLemmyUrl(url) {
    return url.origin !== HOME && INSTANCES_LEMMY.has(url.origin);
}

function isRemoteKbinUrl(url) {
    return url.origin !== HOME && INSTANCES_KBIN.has(url.origin);
}

function isRemoteUrl(url) {
    return isRemoteLemmyUrl(url) || isRemoteKbinUrl(url);
}

function isStandardAtLemmyFormat(url) {
    const paths = url.pathname.split(`/`);
    return paths[1] === `c` || paths[1] === `u`;
}

/**
 * @param url remote url to find local url for
 * @param rootPath optional, otherwise uses root path of {@link url}
 * @returns {string}
 */
function findLocalUrlForStandardAtFormat(url, rootPath) {
    const paths = url.pathname.split(`/`);
    
    const name = paths[2].includes(`@`) ? paths[2] : paths[2] + `@` + url.host;
    return `${HOME}/${rootPath || paths[1]}/${name}`;
}

function findLocalUrlForLemmyUrl(url) {
    if (isStandardAtLemmyFormat(url)) {
        return findLocalUrlForStandardAtFormat(url);
    } else {
        return null;
    }
}

function isStandardAtFormatKbin(url) {
    const paths = url.pathname.split(`/`);
    return paths.length === 3 && paths[1] === `m`;
}

function mappedKbinRootPath(url) {
    const paths = url.pathname.split(`/`);
    if (paths[1] === `m`) {
        return `c`
    } else {
        return null;
    }
}

function isKbinUserUrl(url) {
    const paths = url.pathname.split(`/`);
    return paths.length === 3 && paths[1] === `u`;
}

function findLocalUrlForKbinUserUrl(url) {
    const paths = url.pathname.split(`/`);

    const name = paths[2].includes(`@`) ? paths[2].substring(1) : paths[2] + `@` + url.host;
    return `${HOME}/u/${name}`;
}

function findLocalUrlForKbinUrl(url) {
    if (isStandardAtFormatKbin(url)) {
        return findLocalUrlForStandardAtFormat(url, mappedKbinRootPath(url));
    } else if (isKbinUserUrl(url)) {
        return findLocalUrlForKbinUserUrl(url);
    }
}

function findLocalUrl(url) {
    if (isRemoteLemmyUrl(url)) return findLocalUrlForLemmyUrl(url);
    if (isRemoteKbinUrl(url)) return findLocalUrlForKbinUrl(url);
    return null;
}

function debug() {
    if (DEBUG) console.debug(`Rewriter | `, ...arguments);
}
function trace() {
    if (DEBUG === `trace`) console.debug(`Rewriter Trace | `, ...arguments);
}

function isHashLink(link) {
    return link.hash && link.origin + link.pathname + link.search === location.origin + location.pathname + location.search;
}

function rewriteToLocal(link) {
    if (!link.parentNode) return false; // DOM got changed under us
    if (link.classList.contains(C.ORIGINAL_LINK_CLASS)) return false;
    if (link.querySelector(`.` + C.ICON_CLASS)) return false;
    if (isHashLink(link)) return false;

    const localUrl = findLocalUrl(link);
    if (!localUrl) return false;

    if (localUrl === location.href) return false; // Probably a federation source link

    const oldHref = link.href;
    const treeWalker = document.createTreeWalker(link, NodeFilter.SHOW_TEXT, (node) => {
        if (node.textContent.toLowerCase().trim() === oldHref.toLowerCase().trim()) {
            return NodeFilter.FILTER_ACCEPT;
        } else {
            return NodeFilter.FILTER_SKIP;
        }
    });
    let textNode;
    while ((textNode = treeWalker.nextNode()) !== null) {
        textNode.textContent = localUrl;
    }

    link.href = localUrl;
    link.addEventListener(`click`, (event) => {
        // Fix for SPAs
        if (event.button === 0 && !event.ctrlKey && link.target !== `_blank`) {
            location.href = localUrl;
        }
    })
    link.append(createIcon(link, oldHref));

    trace(`Rewrite link`, link, ` from`, oldHref, `to`, localUrl);
    return true;
}

function findLinksInChange(change) {
    if (change.type === `childList`) {
        const links =  Array.from(change.addedNodes)
            .flatMap((addedNode) => {
                if (addedNode.tagName?.toLowerCase() === `a`) {
                    return addedNode
                } else if (addedNode.querySelectorAll) {
                    return Array.from(addedNode.querySelectorAll(`a`));
                } else {
                    return [];
                }
            });
        if (links.length > 0) trace(`Change`, change, `contained the links`, links);
        return links;
    } else if (change.type === `attributes`) {
        return change.target.matches?.(`a`) ? change.target : [];
    } else {
        return [];
    }
}

function findLinksToRewrite(changes) {
    if (!changes) {
        return document.querySelectorAll(`a`);
    }
    
    return changes.flatMap(findLinksInChange);
}

async function rewriteLinksToLocal(changes) {
    const links = findLinksToRewrite(changes);
    const chunkSize = 50;
    return await (async function processChunk(currentChunk) {
        const startIdx = currentChunk * chunkSize;
        const endChunkIdx = (currentChunk + 1) * chunkSize;
        const endIdx = Math.min(links.length, endChunkIdx);

        debug(`Processing ${links.length} links, current chunk `, currentChunk,
            `processing links ${startIdx} to ${endIdx}`)
        let anyRewritten = false;
        for (let i = startIdx; i < endIdx; ++i) {
            const rewritten = rewriteToLocal(links[i]);
            anyRewritten = anyRewritten || rewritten;
        }
        debug(`Processed links ${startIdx} to ${endIdx}`);

        if (endChunkIdx >= links.length) {
            return anyRewritten;
        }

        const chunkResult = await (new Promise(resolve => setTimeout(async () => {
            resolve(await processChunk(currentChunk + 1));
        }, 0)));
        return anyRewritten || chunkResult;
    })(0);
}

function showAtHomeButtonText() {
    const host = new URL(HOME).hostname;
    return `Show on ${host}`;
}

function createShowAtHomeAnchor(localUrl) {
    const showAtHome = document.createElement(`a`);
    showAtHome.dataset.creationHref = location.href;
    showAtHome.id = C.SHOW_AT_HOME_BUTTON_ID;
    showAtHome.innerText = showAtHomeButtonText();
    showAtHome.href = localUrl;

    OUR_CHANGES.addedNodes[C.SHOW_AT_HOME_BUTTON_ID] = `#` + C.SHOW_AT_HOME_BUTTON_ID;

    return showAtHome;
}

function isV17() {
    return isoData?.site_res?.version.startsWith(`0.17`);
}

function addLemmyShowAtHomeButton(localUrl) {
    const logo = document.querySelector(`a.navbar-brand`);
    const navbarIcons = isV17() ? document.querySelector(`[title="Search"]`)?.closest(`.navbar-nav`) : document.querySelector(`#navbarIcons`);
    if (!logo || !navbarIcons) {
        debug(`Could not find position to insert ShowAtHomeButton at`);
        return false;
    }
    const mobile = createShowAtHomeAnchor(localUrl);
    mobile.classList.add(`d-md-none`);
    mobile.style[`margin-right`] = `8px`;
    mobile.style[`margin-left`] = `auto`;
    if (isV17()) {
        document.querySelector(`.navbar-nav.ml-auto`)?.classList.remove(`ml-auto`);
    }
    
    logo.insertAdjacentElement('afterend', mobile);
    
    const desktop = createShowAtHomeAnchor(localUrl);
    desktop.classList.add(`d-md-inline`);
    desktop.style[`margin-right`] = `8px`;
    navbarIcons.insertAdjacentElement('beforebegin', desktop);
    return true;
}

function addKbinShowAtHomeButton(localUrl) {
    const prependTo = document.querySelector(`#header menu:not(.head-nav__menu)`)
    if (!prependTo) {
        debug(`Could not find position to insert ShowAtHomeButton at`);
        return false;
    }

    const item = document.createElement(`li`);
    item.append(createShowAtHomeAnchor(localUrl));
    prependTo.prepend(item);
    return true;
}

function addShowAtHomeButton() {
    const oldButton = document.querySelector(`#` + C.SHOW_AT_HOME_BUTTON_ID);
    if (oldButton && oldButton.dataset.creationHref !== location.href) {
        debug(`Removing old show at home button`);
        oldButton.remove(); // for SPA (like Lemmy) we need to watch when the location changes and update
    } else if (oldButton) {
        debug(`Old show at home button still exists`);
        return false;
    }

    const localUrl = findLocalUrl(location);
    if (!localUrl) {
        debug(`No local URL for show at home button found`, isRemoteKbinUrl(location));
        return false;
    }

    if (isRemoteLemmyUrl(location)) {
        return addLemmyShowAtHomeButton(localUrl);
    } else if (isRemoteKbinUrl(location)) {
        return addKbinShowAtHomeButton(localUrl);
    } else {
        return false;
    }
}

function addMakeHomeButton() {
    if (document.querySelector(`#` + C.MAKE_HOME_BUTTON_ID)) return false;
    if (!isRemoteLemmyUrl(location) || location.pathname !== `/settings`) return false;

    const insertAfter = document.querySelector(`#user-password`)?.closest(`.card`);
    if (!insertAfter) return;

    const button = document.createElement(`button`);
    button.id = C.MAKE_HOME_BUTTON_ID;
    button.setAttribute(`class`, `btn btn-block btn-primary mr-4 w-100`)
    button.innerText = `Make this my home instance for URL rewriting`;
    button.addEventListener(`click`, () => {
        GM.setValue(`home`, location.origin);
        HOME = location.origin;
        button.remove();
    });

    OUR_CHANGES.addedNodes[C.MAKE_HOME_BUTTON_ID] = `#` + C.MAKE_HOME_BUTTON_ID;
    insertAfter.insertAdjacentElement('afterend', button);

    return true;
}

function lemmyInstances() {
    /* retrieved with:
    (async function() {
        const req = await fetch("https://lemmymap.feddit.de/instances.json", {
            "headers": {"Cache-Control": "no-cache"}
        });
        const resp = await req.json();
        console.log(resp.map(site => new URL(site.site_view.site.actor_id).origin).sort());
    })(); 
    */
    return new Set(["http://changeme_gnv6cavn4bbpwvrpmjs5", "http://changeme_qiivckbjhtzuinufzvr2", "http://changeme_qiivckbjhtzuinufzvr2", "http://kek.henlo.fi", "https://0v0.social", "https://0xdd.org.ru", "https://1337lemmy.com", "https://158436977.xyz", "https://acqrs.co.uk", "https://actuallyruben.nl", "https://aggregation.cafe", "https://agora.nop.chat", "https://aiparadise.moe", "https://algebro.xyz", "https://anarch.is", "https://androiddev.network", "https://anime-pub.moe", "https://animoe.xyz", "https://apollo.town", "https://areality.social", "https://ascy.mooo.com", "https://aulem.org", "https://aussie.zone", "https://badblocks.rocks", "https://baomi.tv", "https://baraza.africa", "https://bbs.9tail.net", "https://bbs.darkwitch.net", "https://beehaw.org", "https://beer.andma.la", "https://beevibes.net", "https://bethe.kingofdog.de", "https://bigfoot.ninja", "https://biglemmowski.win", "https://bluuit.org", "https://board.minimally.online", "https://bolha.social", "https://bookwormstory.social", "https://booty.world", "https://botnet.club", "https://bubblesthebunny.com", "https://bulletintree.com", "https://butts.international", "https://c.calciumlabs.com", "https://caint.org", "https://cavy.rocks", "https://centennialstate.social", "https://chat.maiion.com", "https://cigar.cx", "https://civilloquy.com", "https://clatter.eu", "https://cnvrs.net", "https://code4lib.net", "https://coeus.sbs", "https://communick.news", "https://community.adiquaints.moe", "https://community.nicfab.it", "https://compuverse.uk", "https://crystals.rest", "https://cubing.social", "https://culture0.cc", "https://darmok.xyz", "https://databend.run", "https://dataterm.digital", "https://dendarii.alaeron.com", "https://derp.foo", "https://derpzilla.net", "https://dgngrnder.com", "https://diggit.xyz", "https://digipres.cafe", "https://digitalgoblin.uk", "https://discuss.icewind.me", "https://discuss.jacen.moe", "https://discuss.ntfy.sh", "https://discuss.online", "https://discuss.tchncs.de", "https://distress.digital", "https://dmv.social", "https://donky.social", "https://dormi.zone", "https://dot.surf", "https://drachennetz.com", "https://drak.gg", "https://drlemmy.net", "https://dsilo061298.ddns.net", "https://dubvee.org", "https://dubvee.org", "https://einweckglas.com", "https://endlesstalk.org", "https://endofti.me", "https://eslemmy.es", "https://eventfrontier.com", "https://eviltoast.org", "https://exploding-heads.com", "https://f.jbradaric.me", "https://fadoverso.pt", "https://fanaticus.social", "https://fanexus.com", "https://fed.rosssi.co.uk", "https://feddi.no", "https://feddit.at", "https://feddit.ch", "https://feddit.cl", "https://feddit.de", "https://feddit.dk", "https://feddit.eu", "https://feddit.fun", "https://feddit.it", "https://feddit.jp", "https://feddit.nl", "https://feddit.nu", "https://feddit.nz", "https://feddit.pl", "https://feddit.ro", "https://feddit.site", "https://feddit.strike23.de", "https://feddit.tech", "https://feddit.win", "https://feddiverse.org", "https://federated.community", "https://federated.ninja", "https://fedibb.ml", "https://fedit.io", "https://feditown.com", "https://fediverse.love", "https://fediverse.ro", "https://feedly.j-cloud.uk", "https://femboys.bar", "https://fenbushi.site", "https://fig.systems", "https://fjdk.uk", "https://fl0w.cc", "https://forkk.me", "https://foros.fediverso.gal", "https://forum.basedcount.com", "https://forum.stellarcastle.net", "https://freewilltiger.page", "https://frig.social", "https://geddit.social", "https://geddit.social", "https://glasstower.nl", "https://goddess.name", "https://gonelemmy.xyz", "https://granitestate.social", "https://greg.city", "https://group.lt", "https://grumpy.schuppentier.club", "https://hakbox.social", "https://halubilo.social", "https://hammerdown.0fucks.nl", "https://hc.frorayz.tech", "https://heckoverflow.net", "https://hoodlem.me", "https://hoodratshit.org", "https://hqueue.dev", "https://hyperfair.link", "https://iceorchid.net", "https://info.prou.be", "https://infosec.pub", "https://insane.dev", "https://invariant-marxism.red", "https://jalim.xyz", "https://jamie.moe", "https://jemmy.jeena.net", "https://ka.tet42.org", "https://kale.social", "https://keeb.lol", "https://keylog.zip", "https://kleptonix.com", "https://kyu.de", "https://l.1in1.net", "https://l.biendeo.com", "https://l.bxy.sh", "https://l.jugregator.org", "https://l.mathers.fr", "https://l.mchome.net", "https://l.nulltext.org", "https://l.plabs.social", "https://l.roofo.cc", "https://l.twos.dev", "https://labdegato.com", "https://laguna.chat", "https://latte.isnot.coffee", "https://le-me.xyz", "https://le.fduck.net", "https://le.mnau.xyz", "https://leaf.dance", "https://leby.dev", "https://leddit.minnal.icu", "https://leddit.social", "https://lef.li", "https://lem.agoomem.xyz", "https://lem.amd.im", "https://lem.cochrun.xyz", "https://lem.elbullazul.com", "https://lem.free.as", "https://lem.lyk.pw", "https://lem.monster", "https://lem.ph3j.com", "https://lem.serkozh.me", "https://lem.simple-gear.com", "https://lem.southcape.social", "https://lemdit.com", "https://lemido.freakspot.net", "https://lemitar.meta1203.com", "https://lemiverse.xyz", "https://lemm.ee", "https://lemmerz.org", "https://lemmings.basic-domain.com", "https://lemmings.online", "https://lemmit.online", "https://lemmit.online", "https://lemmit.xyz", "https://lemmony.click", "https://lemmus.org", "https://lemmy", "https://lemmy", "https://lemmy", "https://lemmy", "https://lemmy-xqddz-u4892.vm.elestio.app", "https://lemmy.0x3d.uk", "https://lemmy.1204.org", "https://lemmy.2kd.de", "https://lemmy.4d2.org", "https://lemmy.6px.eu", "https://lemmy.86thumbs.net", "https://lemmy.aguiarvieira.pt", "https://lemmy.albertoluna.es", "https://lemmy.alexland.ca", "https://lemmy.amxl.com", "https://lemmy.amyjnobody.com", "https://lemmy.ananace.dev", "https://lemmy.andiru.de", "https://lemmy.anji.nl", "https://lemmy.anonion.social", "https://lemmy.antemeridiem.xyz", "https://lemmy.antisocial.ly", "https://lemmy.appeine.com", "https://lemmy.arclight.pro", "https://lemmy.astheriver.art", "https://lemmy.aucubin.de", "https://lemmy.austinite.online", "https://lemmy.austinvaness.com", "https://lemmy.austinwadeheller.com", "https://lemmy.avata.social", "https://lemmy.azamserver.com", "https://lemmy.barnacles.one", "https://lemmy.baswag.de", "https://lemmy.batlord.org", "https://lemmy.beebl.es", "https://lemmy.beru.co", "https://lemmy.best", "https://lemmy.blad.is", "https://lemmy.blahaj.zone", "https://lemmy.bleh.au", "https://lemmy.bloodmoon-network.de", "https://lemmy.blue", "https://lemmy.blugatch.tube", "https://lemmy.borlax.com", "https://lemmy.brad.ee", "https://lemmy.bradis.me", "https://lemmy.brief.guru", "https://lemmy.bringdaruck.us", "https://lemmy.browntown.dev", "https://lemmy.brynstuff.co.uk", "https://lemmy.bulwarkob.com", "https://lemmy.bunbi.net", "https://lemmy.burger.rodeo", "https://lemmy.burger.rodeo", "https://lemmy.burningboard.net", "https://lemmy.ca", "https://lemmy.cablepick.net", "https://lemmy.cafe", "https://lemmy.caffeinated.social", "https://lemmy.calebmharper.com", "https://lemmy.calvss.com", "https://lemmy.cat", "https://lemmy.chiisana.net", "https://lemmy.chromozone.dev", "https://lemmy.ciechom.eu", "https://lemmy.click", "https://lemmy.cloudhub.social", "https://lemmy.clueware.org", "https://lemmy.cmstactical.net", "https://lemmy.cnschn.com", "https://lemmy.cock.social", "https://lemmy.coeus.icu", "https://lemmy.comfysnug.space", "https://lemmy.commodore.social", "https://lemmy.cook.gg", "https://lemmy.coolmathgam.es", "https://lemmy.cornspace.space", "https://lemmy.corrigan.xyz", "https://lemmy.coupou.fr", "https://lemmy.croc.pw", "https://lemmy.cultimean.group", "https://lemmy.davidbuckley.ca", "https://lemmy.davidfreina.at", "https://lemmy.dbzer0.com", "https://lemmy.dcrich.net", "https://lemmy.deadca.de", "https://lemmy.death916.xyz", "https://lemmy.decronym.xyz", "https://lemmy.deev.io", "https://lemmy.dekay.se", "https://lemmy.demonoftheday.eu", "https://lemmy.devils.house", "https://lemmy.direktoratet.se", "https://lemmy.discothe.quest", "https://lemmy.dlgreen.com", "https://lemmy.dnet.social", "https://lemmy.donmcgin.com", "https://lemmy.doomeer.com", "https://lemmy.dork.lol", "https://lemmy.dormedas.com", "https://lemmy.douwes.co.uk", "https://lemmy.dudeami.win", "https://lemmy.dupper.net", "https://lemmy.dustybeer.com", "https://lemmy.dyslexicjedi.com", "https://lemmy.easfrq.live", "https://lemmy.eatsleepcode.ca", "https://lemmy.eco.br", "https://lemmy.edgarchirivella.com", "https://lemmy.efradaphi.de", "https://lemmy.eic.lu", "https://lemmy.einval.net", "https://lemmy.elest.io", "https://lemmy.elest.io", "https://lemmy.elmusfire.xyz", "https://lemmy.emopolarbear.com", "https://lemmy.enchanted.social", "https://lemmy.escapebigtech.info", "https://lemmy.eus", "https://lemmy.fakecake.org", "https://lemmy.fanboys.xyz", "https://lemmy.fauxreigner.net", "https://lemmy.fbxl.net", "https://lemmy.fdvrs.xyz", "https://lemmy.fedi.bub.org", "https://lemmy.fedihub.social", "https://lemmy.fediverse.jp", "https://lemmy.fediversum.de", "https://lemmy.film", "https://lemmy.finance", "https://lemmy.flauschbereich.de", "https://lemmy.flugratte.dev", "https://lemmy.fmhy.ml", "https://lemmy.foxden.party", "https://lemmy.foxden.social", "https://lemmy.freddeliv.me", "https://lemmy.fredhs.net", "https://lemmy.fribyte.no", "https://lemmy.friheter.com", "https://lemmy.fromshado.ws", "https://lemmy.frozeninferno.xyz", "https://lemmy.fucs.io", "https://lemmy.fun", "https://lemmy.funkyfish.cool", "https://lemmy.funkylab.xyz", "https://lemmy.fwgx.uk", "https://lemmy.fyi", "https://lemmy.g97.top", "https://lemmy.game-files.net", "https://lemmy.gareth.computer", "https://lemmy.ghostplanet.org", "https://lemmy.gjz010.com", "https://lemmy.glasgow.social", "https://lemmy.gmprojects.pro", "https://lemmy.graphics", "https://lemmy.graz.social", "https://lemmy.gross.hosting", "https://lemmy.grouchysysadmin.com", "https://lemmy.grygon.com", "https://lemmy.gsp8181.co.uk", "https://lemmy.gtfo.social", "https://lemmy.haigner.me", "https://lemmy.hamrick.xyz", "https://lemmy.helheim.net", "https://lemmy.helios42.de", "https://lemmy.hellwhore.com", "https://lemmy.help", "https://lemmy.helvetet.eu", "https://lemmy.holmosapien.com", "https://lemmy.hopskipjump.cloud", "https://lemmy.hosted.frl", "https://lemmy.hpost.no", "https://lemmy.hutch.chat", "https://lemmy.intai.tech", "https://lemmy.irrealis.net", "https://lemmy.isamp.com", "https://lemmy.iswhereits.at", "https://lemmy.itermori.de", "https://lemmy.iys.io", "https://lemmy.jacaranda.club", "https://lemmy.jacaranda.club", "https://lemmy.jamesj999.co.uk", "https://lemmy.jamestrey.com", "https://lemmy.jasondove.me", "https://lemmy.jasonsanta.xyz", "https://lemmy.javant.xyz", "https://lemmy.jigoku.us.to", "https://lemmy.jlh.name", "https://lemmy.jmtr.org", "https://lemmy.johnpanos.com", "https://lemmy.jpaulus.io", "https://lemmy.jpiolho.com", "https://lemmy.jstsmthrgk.eu", "https://lemmy.jtmn.dev", "https://lemmy.juggler.jp", "https://lemmy.k6qw.com", "https://lemmy.kagura.eu", "https://lemmy.karaolidis.com", "https://lemmy.katia.sh", "https://lemmy.kemomimi.fans", "https://lemmy.keychat.org", "https://lemmy.kghorvath.com", "https://lemmy.kizaing.ca", "https://lemmy.knocknet.net", "https://lemmy.ko4abp.com", "https://lemmy.kodeklang.social", "https://lemmy.korgen.xyz", "https://lemmy.koski.co", "https://lemmy.krobier.com", "https://lemmy.kutara.io", "https://lemmy.kya.moe", "https://lemmy.l00p.org", "https://lemmy.l0nax.org", "https://lemmy.legally-berlin.de", "https://lemmy.lemist.de", "https://lemmy.lif.ovh", "https://lemmy.link", "https://lemmy.linuxuserspace.show", "https://lemmy.littlejth.com", "https://lemmy.livesound.world", "https://lemmy.loomy.li", "https://lemmy.loungerat.io", "https://lemmy.loutsenhizer.com", "https://lemmy.lpcha.im", "https://lemmy.lucaslower.com", "https://lemmy.lukeog.com", "https://lemmy.lylapol.com", "https://lemmy.m1k.cloud", "https://lemmy.maatwo.com", "https://lemmy.macaddict89.me", "https://lemmy.mambastretch.com", "https://lemmy.maples.dev", "https://lemmy.mariusdavid.fr", "https://lemmy.marud.fr", "https://lemmy.mats.ooo", "https://lemmy.matthe815.dev", "https://lemmy.mazurka.xyz", "https://lemmy.mb-server.com", "https://lemmy.mbirth.uk", "https://lemmy.media", "https://lemmy.meissners.me", "https://lemmy.meli.dev", "https://lemmy.menos.gotdns.org", "https://lemmy.mentalarts.info", "https://lemmy.meowchat.xyz", "https://lemmy.meridiangrp.co.uk", "https://lemmy.mildgrim.com", "https://lemmy.mira.pm", "https://lemmy.ml", "https://lemmy.mlaga97.space", "https://lemmy.mlsn.fr", "https://lemmy.modshiftx.com", "https://lemmy.monster", "https://lemmy.moonling.nl", "https://lemmy.morrisherd.com", "https://lemmy.mpcjanssen.nl", "https://lemmy.mrm.one", "https://lemmy.munsell.io", "https://lemmy.mxh.nu", "https://lemmy.my.id", "https://lemmy.mypinghertz.com", "https://lemmy.mywire.xyz", "https://lemmy.n1ks.net", "https://lemmy.naga.sh", "https://lemmy.name", "https://lemmy.nanoklinika.tk", "https://lemmy.nathaneaston.com", "https://lemmy.nauk.io", "https://lemmy.neeley.cloud", "https://lemmy.nerdcave.us", "https://lemmy.nerdcore.social", "https://lemmy.nexus", "https://lemmy.nikore.net", "https://lemmy.nine-hells.net", "https://lemmy.ninja", "https://lemmy.nope.ly", "https://lemmy.nopro.be", "https://lemmy.norbz.org", "https://lemmy.notdead.net", "https://lemmy.nrd.li", "https://lemmy.nz", "https://lemmy.obrell.se", "https://lemmy.one", "https://lemmy.onitato.com", "https://lemmy.onlylans.io", "https://lemmy.otakufarms.com", "https://lemmy.parasrah.com", "https://lemmy.pastwind.top", "https://lemmy.pathoris.de", "https://lemmy.pcft.eu", "https://lemmy.pe1uca.dev", "https://lemmy.pec0ra.ch", "https://lemmy.perigrine.ca", "https://lemmy.philipcristiano.com", "https://lemmy.picote.ch", "https://lemmy.pineapplemachine.com", "https://lemmy.pineapplenest.com", "https://lemmy.pipe01.net", "https://lemmy.piperservers.net", "https://lemmy.pipipopo.pl", "https://lemmy.pit.ninja", "https://lemmy.place", "https://lemmy.plasmatrap.com", "https://lemmy.podycust.co.uk", "https://lemmy.podycust.co.uk", "https://lemmy.ppl.town", "https://lemmy.primboard.de", "https://lemmy.pro", "https://lemmy.productionservers.net", "https://lemmy.proxmox-lab.com", "https://lemmy.pryst.de", "https://lemmy.pt", "https://lemmy.pub", "https://lemmy.pubsub.fun", "https://lemmy.pussthecat.org", "https://lemmy.pwzle.com", "https://lemmy.pxm.nl", "https://lemmy.qpixel.me", "https://lemmy.quad442.com", "https://lemmy.radio", "https://lemmy.rat.academy", "https://lemmy.ravc.tech", "https://lemmy.recursed.net", "https://lemmy.remotelab.uk", "https://lemmy.rhymelikedi.me", "https://lemmy.riffel.family", "https://lemmy.rimkus.it", "https://lemmy.rollenspiel.monster", "https://lemmy.room409.xyz", "https://lemmy.roombob.cat", "https://lemmy.root6.de", "https://lemmy.rubenernst.dev", "https://lemmy.run", "https://lemmy.run", "https://lemmy.s9m.xyz", "https://lemmy.saik0.com", "https://lemmy.samad.one", "https://lemmy.sascamooch.com", "https://lemmy.sbs", "https://lemmy.scam-mail.me", "https://lemmy.scav1.com", "https://lemmy.schlunker.com", "https://lemmy.schmeisserweb.at", "https://lemmy.schuerz.at", "https://lemmy.scottlabs.io", "https://lemmy.sdf.org", "https://lemmy.sebbem.se", "https://lemmy.secnd.me", "https://lemmy.sedimentarymountains.com", "https://lemmy.seifert.id", "https://lemmy.selfhost.quest", "https://lemmy.selfip.org", "https://lemmy.server.fifthdread.com", "https://lemmy.services.coupou.fr", "https://lemmy.sh", "https://lemmy.shattervideoisland.com", "https://lemmy.sidh.bzh", "https://lemmy.sietch.online", "https://lemmy.skillissue.dk", "https://lemmy.smeargle.fans", "https://lemmy.snoot.tube", "https://lemmy.socdojo.com", "https://lemmy.soontm.de", "https://lemmy.spacestation14.com", "https://lemmy.sprawl.club", "https://lemmy.srv.eco", "https://lemmy.srv0.lol", "https://lemmy.staphup.nl", "https://lemmy.stark-enterprise.net", "https://lemmy.starlightkel.xyz", "https://lemmy.starmade.de", "https://lemmy.steken.xyz", "https://lemmy.stormlight.space", "https://lemmy.strandundmeer.net", "https://lemmy.stuart.fun", "https://lemmy.studio", "https://lemmy.suchmeme.nl", "https://lemmy.sumuun.net", "https://lemmy.sumuun.net", "https://lemmy.svc.vesey.tech", "https://lemmy.sweevo.net", "https://lemmy.syrasu.com", "https://lemmy.sysctl.io", "https://lemmy.tancomps.net", "https://lemmy.tanktrace.de", "https://lemmy.tario.org", "https://lemmy.tarsis.org", "https://lemmy.taubin.cc", "https://lemmy.teaisatfour.com", "https://lemmy.technosorcery.net", "https://lemmy.techstache.com", "https://lemmy.tedomum.net", "https://lemmy.telaax.com", "https://lemmy.tf", "https://lemmy.tgxn.net", "https://lemmy.thanatos.at", "https://lemmy.the-burrow.com", "https://lemmy.the-goblin.net", "https://lemmy.theia.cafe", "https://lemmy.themainframe.org", "https://lemmy.theonecurly.page", "https://lemmy.thepixelproject.com", "https://lemmy.therhys.co.uk", "https://lemmy.thesmokinglounge.club", "https://lemmy.thias.xyz", "https://lemmy.tillicumnet.com", "https://lemmy.timdn.com", "https://lemmy.timon.sh", "https://lemmy.timwaterhouse.com", "https://lemmy.tobyvin.dev", "https://lemmy.today", "https://lemmy.toot.pt", "https://lemmy.towards.vision", "https://lemmy.tr00st.co.uk", "https://lemmy.trippy.pizza", "https://lemmy.ubergeek77.chat", "https://lemmy.umainfo.live", "https://lemmy.uncomfortable.business", "https://lemmy.unfiltered.social", "https://lemmy.uninsane.org", "https://lemmy.utopify.org", "https://lemmy.utveckla.re", "https://lemmy.va-11-hall-a.cafe", "https://lemmy.vanoverloop.xyz", "https://lemmy.vepta.org", "https://lemmy.villa-straylight.social", "https://lemmy.vinodjam.com", "https://lemmy.vip", "https://lemmy.virtim.dev", "https://lemmy.vodkatonic.org", "https://lemmy.vrchat-dev.tech", "https://lemmy.vskr.net", "https://lemmy.vyizis.tech", "https://lemmy.w9r.de", "https://lemmy.webgirand.eu", "https://lemmy.website", "https://lemmy.weckhorst.no", "https://lemmy.weiser.social", "https://lemmy.whalesinspace.de", "https://lemmy.whynotdrs.org", "https://lemmy.wiuf.net", "https://lemmy.wizjenkins.com", "https://lemmy.world", "https://lemmy.wraithsquadrongaming.com", "https://lemmy.wtf", "https://lemmy.wxbu.de", "https://lemmy.wyattsmith.org", "https://lemmy.x01.ninja", "https://lemmy.xce.pt", "https://lemmy.xcoolgroup.com", "https://lemmy.xoynq.com", "https://lemmy.zelinsky.dev", "https://lemmy.zell-mbc.com", "https://lemmy.zip", "https://lemmy.zone", "https://lemmy.zroot.org", "https://lemmy2.addictmud.org", "https://lemmybedan.com", "https://lemmydeals.com", "https://lemmyfi.com", "https://lemmyfly.org", "https://lemmygrad.ml", "https://lemmygrid.com", "https://lemmyis.fun", "https://lemmyngs.social", "https://lemmynsfw.com", "https://lemmyonline.com", "https://lemmypets.xyz", "https://lemmyrs.org", "https://lemmyunchained.net", "https://lemmywinks.com", "https://lemmywinks.xyz", "https://lemnt.telaax.com", "https://lemthony.com", "https://lib.lgbt", "https://libreauto.app", "https://liminal.southfox.me", "https://link.fossdle.org", "https://linkage.ds8.zone", "https://linkopath.com", "https://links.decafbad.com", "https://links.hackliberty.org", "https://links.lowsec.club", "https://links.rocks", "https://links.roobre.es", "https://links.wageoffsite.com", "https://livy.one", "https://lm.bittervets.org", "https://lm.byteme.social", "https://lm.curlefry.net", "https://lm.electrospek.com", "https://lm.gsk.moe", "https://lm.halfassmart.net", "https://lm.inu.is", "https://lm.kalinowski.dev", "https://lm.korako.me", "https://lm.m0e.space", "https://lm.madiator.cloud", "https://lm.melonbread.dev", "https://lm.paradisus.day", "https://lm.put.tf", "https://lm.qtt.no", "https://lm.runnerd.net", "https://lm.sethp.cc", "https://lm.suitwaffle.com", "https://lm.williampuckering.com", "https://lmmy.io", "https://lmmy.net", "https://lmmy.tvdl.dev", "https://lmmy.ylwsgn.cc", "https://lmy.dotcomitsa.website", "https://lmy.drundo.com.au", "https://local106.com", "https://localghost.org", "https://localhost", "https://localhost", "https://localhost", "https://localhost", "https://localhost", "https://logophilia.net", "https://lolimbeer.com", "https://lostcheese.com", "https://lsmu.schmurian.xyz", "https://lucitt.social", "https://mander.xyz", "https://matejc.com", "https://matts.digital", "https://mayheminc.win", "https://mcr.town", "https://meganice.online", "https://melly.0x-ia.moe", "https://merv.news", "https://mesita.link", "https://midwest.social", "https://milksteak.org", "https://mindshare.space", "https://mlem.a-smol-cat.fr", "https://mobilemmohub.com", "https://monero.house", "https://monero.town", "https://monyet.cc", "https://moose.best", "https://moot.place", "https://moto.teamswollen.org", "https://mujico.org", "https://mydomain.ml", "https://mydomain.ml", "https://mydomain.ml", "https://mylem.my", "https://mylemmy.win", "https://narod.city", "https://negativenull.com", "https://neodrain.net", "https://netmonkey.tech", "https://news.cosocial.ca", "https://news.deghg.org", "https://news.idlestate.org", "https://nlemmy.nl", "https://no.lastname.nz", "https://nonewfriends.club", "https://normalcity.life", "https://notdigg.com", "https://notlemmy.notawebsite.fr", "https://notlemmy.site", "https://novoidspace.com", "https://nrsk.no", "https://nunu.dev", "https://nwdr.club", "https://occult.social", "https://oceanbreeze.earth", "https://odin.lanofthedead.xyz", "https://omg.qa", "https://opendmz.social", "https://orava.dev", "https://orzen.games", "https://outpost.zeuslink.net", "https://partizle.com", "https://pasta.faith", "https://pathfinder.social", "https://pathofexile-discuss.com", "https://pawb.social", "https://philly.page", "https://pootusmaximus.xyz", "https://popplesburger.hilciferous.nl", "https://poptalk.scrubbles.tech", "https://possumpat.io", "https://posta.no", "https://preserve.games", "https://programming.dev", "https://proit.org", "https://psychedelia.ink", "https://purrito.kamartaj.xyz", "https://pwzle.com", "https://quex.cc", "https://r-sauna.fi", "https://r.rosettast0ned.com", "https://r.stoi.cc", "https://r196.club", "https://rabbitea.rs", "https://radiation.party", "https://rammy.site", "https://rational-racoon.de", "https://rblind.com", "https://re.tei.li", "https://read.widerweb.org", "https://readit.space", "https://red.cyberhase.de", "https://reddit.moonbeam.town", "https://reddthat.com", "https://retarded.dev", "https://ripo.st", "https://rlyeh.cc", "https://rustyshackleford.cfd", "https://s.jape.work", "https://sambaspy.com", "https://scif6.nsalanparty.com", "https://seattlelunarsociety.org", "https://sedd.it", "https://seemel.ink", "https://selfhosted.forum", "https://sffa.community", "https://sh.itjust.works", "https://sha1.nl", "https://shinobu.cloud", "https://shitposting.monster", "https://shork.online", "https://sigmet.io", "https://silicon-dragon.com", "https://slangenettet.pyjam.as", "https://slrpnk.net", "https://sneakernet.social", "https://snkkis.me", "https://snuv.win", "https://soccer.forum", "https://social.coalition.space", "https://social.cyb3r.dog", "https://social.dn42.us", "https://social.fossware.space", "https://social.fr4me.io", "https://social.ggbox.fr", "https://social.hamington.net", "https://social.jears.at", "https://social.nerdhouse.io", "https://social.nerdswire.de", "https://social.nerdswire.de", "https://social.poisson.me", "https://social.sour.is", "https://social.vmdk.ca", "https://social2.blahajspin.lol", "https://solstice.etbr.top", "https://sopuli.xyz", "https://sowhois.gay", "https://spgrn.com", "https://stammtisch.hallertau.social", "https://stanx.page", "https://stars.leemoon.network", "https://startrek.website", "https://sub.rdls.dev", "https://sub.wetshaving.social", "https://sublight.one", "https://suppo.fi", "https://support.futbol", "https://support.futbol", "https://surlesworld.com", "https://szmer.info", "https://tabletop.place", "https://tagpro.lol", "https://talka.live", "https://techy.news", "https://tezzo.f0rk.pl", "https://thaumatur.ge", "https://thegarden-u4873.vm.elestio.app", "https://thegarden.land", "https://thegarden.land", "https://thelemmy.club", "https://theotter.social", "https://thepride.hexodine.com", "https://thesidewalkends.io", "https://thesimplecorner.org", "https://thevapor.space", "https://toast.ooo", "https://toons.zone", "https://tortoisewrath.com", "https://tslemmy.duckdns.org", "https://ttrpg.network", "https://tucson.social", "https://typemi.me", "https://upvote.au", "https://versalife.duckdns.org", "https://vlemmy.net", "https://voxpop.social", "https://wallstreets.bet", "https://waveform.social", "https://wayfarershaven.eu", "https://weiner.zone", "https://werm.social", "https://whata.clusterfsck.com", "https://whatyoulike.club", "https://whiskers.bim.boats", "https://wilbo.tech", "https://wirebase.org", "https://wired.bluemarch.art", "https://wizanons.dev", "https://wolfballs.com", "https://wumbo.buzz", "https://www.jrz.city", "https://www.korzekwa.io", "https://xffxe4.lol", "https://yall.theatl.social", "https://yiffit.net", "https://ymmel.nl", "https://yogibytes.page", "https://zemmy.cc", "https://zerobytes.monster", "https://zoo.splitlinux.org"]);
}

function kbinInstances() {
    /* Retrieved with:
    await (async function () {
        async function callApi(url) {
            const resp = await fetch(url, );
            return await resp.json();
        }
    
        function getNextUrl(json) {
            return json.links.next;
        }
    
        function getInstances(json) {
            return json.data.map((instance) => `https://` + instance.domain);
        }
    
        const instances = [];
        function collectInstances(json) {
            const newInstances = getInstances(json);
            console.log(newInstances);
            instances.push(...newInstances);
        }
    
        let url = "https://fedidb.org/api/web/network/software/servers";
        while(url) {
            console.log(url);
            const json = await callApi(url);
            collectInstances(json);
            url = getNextUrl(json);
            await new Promise(resolve => setTimeout(resolve, 1000));
        }
        return instances.sort();
    })();
    */
    return new Set(["https://champserver.net", "https://community.yshi.org", "https://feddit.online", "https://fedi196.gay", "https://fedia.io", "https://fediverse.boo", "https://forum.fail", "https://frmsn.space", "https://gehirneimer.de", "https://jlailu.social", "https://k.fe.derate.me", "https://karab.in", "https://kayb.ee", "https://kbin.buzz", "https://kbin.chat", "https://kbin.cocopoops.com", "https://kbin.dentora.social", "https://kbin.dk", "https://kbin.donar.dev", "https://kbin.fedi.cr", "https://kbin.korgen.xyz", "https://kbin.lgbt", "https://kbin.lol", "https://kbin.mastodont.cat", "https://kbin.melroy.org", "https://kbin.place", "https://kbin.possum.city", "https://kbin.projectsegfau.lt", "https://kbin.rocks", "https://kbin.run", "https://kbin.sh", "https://kbin.social", "https://kbin.tech", "https://kilioa.org", "https://kopnij.in", "https://longley.ws", "https://nadajnik.org", "https://nerdbin.social", "https://nolani.academy", "https://readit.buzz", "https://remy.city", "https://social.tath.link", "https://streetbikes.club", "https://teacup.social", "https://the.coolest.zone", "https://thebrainbin.org", "https://tuna.cat", "https://wiku.hu"])
}