sjehuda / Proxify Links

/*

## ⛓️ Proxify Links
### _Rewrite links to privacy-oriented and open-source proxy frontends._

Proxify Links userscript replaces links to privacy-oriented frontends, such as Scribe, Nitter, Libreddit, etc.

---

#### Recommended Userscripts

#### 🥸 [Proxy Redirect](https://openuserjs.org/scripts/sjehuda/Proxy_Redirect)
Redirect to privacy respecting proxy frontends.

---

#### Upcoming changes
 - ~~Identifying URLs (use Blacklist and Whitelist);~~
 - ~~Act on viewport (use Event Listener);~~
 - Improve event listener to act on nested hyperlinks;
 - Improve event listener to act on viewport instead of click or mouseover;
 - ~~Check instance http status using [GM.xmlHttpRequest](https://sourceforge.net/p/greasemonkey/wiki/GM_xmlhttpRequest/)~~.

---

#### <!-- img src="https://raw.githubusercontent.com/KDE/falkon/master/logo.png" height="30" alt="Falkon" title="Download Falkon Browser"/ --> Help enhancing userscript support for <span style='color:MediumPurple'>Falkon web browser</span>
C++ developers, please help [Falkon](https://falkon.org/) web browser‬ to bring [better support](https://bugs.kde.org/show_bug.cgi?id=466533) for [GM.xmlHttpRequest](https://sourceforge.net/p/greasemonkey/wiki/GM_xmlhttpRequest/).

If you find this program useful, please help Falkon so we would also be able to enjoy this program. Web browsers that respect our privacy are rare. That's why Falkon is important.

_Sincerely,
Schimon Jehudah, Adv._

*/

// ==UserScript== 
// @name        Proxify Links
// @author      Schimon Jehudah, Adv.
// @homepageURL https://openuserjs.org/scripts/sjehuda/Proxify_Links
// @supportURL  https://openuserjs.org/scripts/sjehuda/Proxify_Links/issues
// @updateURL   https://openuserjs.org/meta/sjehuda/Proxify_Links.meta.js
// @downloadURL https://openuserjs.org/install/sjehuda/Proxify_Links.user.js
// @copyright   2023, Schimon Jehudah (http://schimon.i2p)
// @license     AGPL-3.0-only; https://www.gnu.org/licenses/agpl-3.0.en.html
// @namespace   i2p.schimon.proxify-links
// @description Correct links to privacy respecting proxy frontends
// @run-at      document-end
// @version     23.06.10
// @grant       GM_xmlhttpRequest
// @grant       GM.xmlHttpRequest
// @match       *://*/*
// @connect     0011.lt
// @connect     076.ne.jp
// @connect     1d4.us
// @connect     2syis2nnyytz6jnusnjurva4swlaizlnleiks5mjp46phuwjbdjqwgqd.onion
// @connect     40two.app
// @connect     42l.fr
// @connect     777.tf
// @connect     actionsack.com
// @connect     adminforge.de
// @connect     akisblack.dev
// @connect     albony.xyz
// @connect     alefvanoon.xyz
// @connect     artemislena.eu
// @connect     asynchronousexchange.com
// @connect     batsense.net
// @connect     bibliogram.art
// @connect     biblioreads.ga
// @connect     biblioreads.ml
// @connect     bloatcat.tk
// @connect     btdig.i2p
// @connect     btdig.com
// @connect     btdigggink2pdqzqrik3blmqemsbntpzwxottujilcdjfz56jumzfsyd.onion
// @connect     bus-hit.me
// @connect     cadence.moe
// @connect     catfluori.de
// @connect     cblgh.org
// @connect     censors.us
// @connect     citizen4.eu
// @connect     cowfee.moe
// @connect     crewz.me
// @connect     cn.i2p
// @connect     cthd.icu
// @connect     datatunnel.xyz
// @connect     domain.glass
// @connect     duckdns.org
// @connect     dynabyte.ca
// @connect     ebnar.xyz
// @connect     esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion
// @connect     esmailelbob.xyz
// @connect     etsi.me
// @connect     exarius.org
// @connect     farside.link
// @connect     fdn.fr
// @connect     flokinet.to
// @connect     flux.industries
// @connect     fmac.xyz
// @connect     foss.wtf
// @connect     froth.zone
// @connect     ggc-project.de
// @connect     gnu.style
// @connect     grimneko.de
// @connect     hostux.net
// @connect     hyperborea.cloud
// @connect     iket.me
// @connect     il.ax
// @connect     incogsnoo.com
// @connect     invak.id
// @connect     jamiethalacker.dev
// @connect     jeikobu.net
// @connect     jewtube.i2p
// @connect     josias.dev
// @connect     jpope.org
// @connect     k62ptris7p72aborr4zoanee7xai6wguucveptwgxs5vbgt7qzpq.b32.i2p
// @connect     kavin.rocks
// @connect     kylrth.com
// @connect     ledditqo2mxfvlgobxnlhrkq4dh34jss6evfkdkb2thlvy6dn4f4gpyd.onion
// @connect     libredd.it
// @connect     libreddit.de
// @connect     libreddit.eu.org
// @connect     libreddit.hu
// @connect     libreddit.nl
// @connect     lingva.ml
// @connect     lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion
// @connect     lunar.icu
// @connect     melmac.space
// @connect     mint.lgbt
// @connect     moeyy.cn
// @connect     mutahar.rocks
// @connect     moomoo.me
// @connect     mywire.org
// @connect     namazso.eu
// @connect     mdosch.de
// @connect     monocles.de
// @connect     neet.works
// @connect     neuters.de
// @connect     netlify.app
// @connect     nitter.ca
// @connect     nitter.hu
// @connect     nitter.it
// @connect     nitter.net
// @connect     nixnet.services
// @connect     no-logs.com
// @connect     northboot.xyz
// @connect     nttr.stream
// @connect     odyssey346.dev
// @connect     ononoki.org
// @connect     ooguy.com
// @connect     openstreetmap.org
// @connect     osi.kr
// @connect     oversold.host
// @connect     owacon.moe
// @connect     pabloferreiro.es
// @connect     paulgo.io
// @connect     phreedom.club
// @connect     piped.video
// @connect     poketube.fun
// @connect     privacy.com.de
// @connect     projectsegfau.lt
// @connect     procurx.pt
// @connect     prvcy.eu
// @connect     puffyan.us
// @connect     pussthecat.org
// @connect     r.nf
// @connect     rabbit-company.com
// @connect     rasp.fr
// @connect     resrv.org
// @connect     riverside.rocks
// @connect     rtrace.io
// @connect     scribe.rip
// @connect     searx.be
// @connect     searx.ninja
// @connect     searx.ru
// @connect     sethforprivacy.com
// @connect     simplytranslate.org
// @connect     slipfox.xyz
// @connect     smnz.de
// @connect     snopyta.org
// @connect     sny.sh
// @connect     some-things.org
// @connect     sp-codes.de
// @connect     spike.codes
// @connect     spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion
// @connect     strongthany.cc
// @connect     stuehieyr.com
// @connect     sugoma.tk
// @connect     syncpundit.com
// @connect     teddit.i2p
// @connect     teddit.net
// @connect     tedditfyn6idalzso5wam5qd3kdtxoljjhbrbbx34q2xkcisvshuytad.onion
// @connect     theanonymouse.xyz
// @connect     tinfoil-hat.net
// @connect     tiekoetter.com
// @connect     tokhmi.xyz
// @connect     totaldarkness.net
// @connect     trom.tf
// @connect     tromdienste.de
// @connect     tux.land
// @connect     tuxcloud.net
// @connect     tyil.nl
// @connect     unixfox.eu
// @connect     unofficialbird.com
// @connect     userscripts-mirror.org
// @connect     vernapl3lpo3huqdx3pjzxqgdgavxjlmdskbvejh2gfqgmjuyvxq.b32.i2p
// @connect     vernaqj2qr2pijpgvf3od6ssc3ulz3nv52gwr3hba5l6humuzmgq.b32.i2p
// @connect     vernmzgraj6aaoafmehupvtkkynpaa67rxcdj2kinwiy6konn6rq.b32.i2p
// @connect     vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion
// @connect     vern.cc
// @connect     vern.i2p
// @connect     voidnet.tech
// @connect     vojkovic.xyz
// @connect     voring.me
// @connect     walkx.org
// @connect     webheberg.info
// @connect     weblibre.org
// @connect     whatever.social
// @connect     whatevertinfoil.de
// @connect     wikiless.i2p
// @connect     wikiless.org
// @connect     winscloud.net
// @connect     xn--17b.net
// @connect     yewtu.be
// @connect     yonalee.eu
// @connect     ytmous.i2p
// @connect     xanny.family
// @connect     yacy.iko.soy
// @connect     zackptg5.com
// @connect     zaggy.nl
// @connect     zhaocloud.net
// @icon        data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48dGV4dCB5PSIuOWVtIiBmb250LXNpemU9IjkwIj7im5PvuI88L3RleHQ+PC9zdmc+Cg==
// ==/UserScript==

//TODO
//Rebrand: Open Redirect, Proxy Redirect
//Rebrand: Proxitize link, FreeLink, LibreProxy, Open Link, Proxy Direct, Proxy Link, Proxy Redirect

// @makyen
// /greasemonkey/greasemonkey/issues/3160#issuecomment-1456758080
const gmXmlhttpRequest = typeof GM_xmlhttpRequest === 'function' ? GM_xmlhttpRequest : GM.xmlHttpRequest;

var
  attemptCounter = 0,
  hyperLink, originalColor, hostname, pathname,
  code, cord, hash, lang, para, paras,
  farside, partedURL, path, proxyArray, urlArray, instance, modURL, newURL;

const urls = {
'exclude' : [
{
'addr' : 'gist.github.com',
'host' : 'gist.github.com',
'path' : [],
'text' : ['View on GitHub'],
},
{
'addr' : 'github.com',
'host' : 'github.com',
// not-href -> perhaps starts with, ends with and inclusive
'path' : [
  'actions', 'archive', 'blame', 'blob', 'codespaces', 'collections',
  'commit', 'compare', 'contribute', 'customer-stories', 'delete',
  'discussions', 'edit', 'enterprise', 'events', 'features', 'graphs',
  'issues', 'login', 'marketplace', 'notifications', 'orgs', 'pricing',
  'projects', 'pull', 'pulse', 'releases', 'security', 'sessions',
  'settings', 'signup', 'solutions', 'sponsors', 'tags', 'team',
  'topics', 'tree', 'trending', 'wiki'
  ],
'text' : ['View on GitHub'],
},
{
'addr' : 'imdb.com',
'host' : 'imdb.com',
'path' : ['reviews'],
},
{
'addr' : 'medium.com',
'host' : 'medium.com',
'path' : ['c/', 'fit/', 'format:', 'resize:fit:', 'v2/'],
},
{
'addr' : 'stackoverflow.com/questions/',
'host' : 'stackoverflow.com',
'path' : ['tagged', 'users'], // /questions/tagged
},
{
'addr' : 'www.torrentdownload.info',
'host' : 'torrentdownload.info',
'path' : ['feed_latest', 'search?q='],
},
{
'addr' : 'torrentz.eu',
'host' : 'torrentz.eu',
'path' : ['search?f='],
},
{
'addr' : 'torrentz.me',
'host' : 'torrentz.me',
'path' : ['search?f='],
},
{
'addr' : 'torrentz2.eu',
'host' : 'torrentz2.eu',
'path' : ['search?f='],
},
{
'addr' : 'torrentz2.is',
'host' : 'torrentz2.is',
'path' : ['search?f='],
},
{
'addr' : 'youtube.com',
'host' : 'youtube.com',
'path' : ['users'],
}
], // hosts, paths and texts to exclude

'includeByHostname' : [
{
'addr' : 'bandcamp.com',
'host' : 'bandcamp.com',
},
{
'addr' : 'bilibili.com',
'host' : 'bilibili.com',
},
{
'addr' : 'fandom.com',
'host' : 'fandom.com',
},
{
'addr' : 'gist.github.com',
'host' : 'gist.github.com',
},
{
'addr' : 'github.com',
'host' : 'github.com',
},
{
'addr' : 'gitlab.com',
'host' : 'gitlab.com',
},
{
'addr' : 'goodreads.com',
'host' : 'goodreads.com',
},
{
'addr' : 'imdb.com',
'host' : 'imdb.com',
},
{
'addr' : 'imgur.com',
'host' : 'imgur.com',
},
{
'addr' : 'instagram.com',
'host' : 'instagram.com',
},
{
'addr' : 'invidious-invidious.invidious.svc.cluster.local:3000',
'host' : 'invidious-invidious.invidious.svc.cluster.local:3000',
},
{
'addr' : 'medium.com',
'host' : 'medium.com',
},
{
'addr' : 'moovitapp.com',
'host' : 'moovitapp.com',
},
{
'addr' : 'odysee.com',
'host' : 'odysee.com',
},
{
'addr' : 'reddit.com',
'host' : 'reddit.com',
},
{
'addr' : 'old.reddit.com',
'host' : 'old.reddit.com',
},
{
'addr' : 'quora.com',
'host' : 'quora.com',
},
{
'addr' : 'reuters.com',
'host' : 'reuters.com',
},
{
'addr' : 'tiktok.com',
'host' : 'tiktok.com',
},
{
'addr' : 'www.torrentdownload.info',
'host' : 'torrentdownload.info',
},
{
'addr' : 'torrentz.eu',
'host' : 'torrentz.eu',
},
{
'addr' : 'torrentz.me',
'host' : 'torrentz.me',
},
{
'addr' : 'torrentz2.eu',
'host' : 'torrentz2.eu',
},
{
'addr' : 'torrentz2.is',
'host' : 'torrentz2.is',
},
{
'addr' : 'twitter.com',
'host' : 'twitter.com',
},
{
'addr' : 'urbandictionary.com',
'host' : 'urbandictionary.com',
},
{
'addr' : 'userscripts.org',
'host' : 'userscripts.org',
},
{
'addr' : 'wikimap.toolforge.org',
'host' : 'wikimap.toolforge.org',
},
{
'addr' : 'search.yahoo.co.jp',
'host' : 'yahoo.co.jp',
},
{
'addr' : 'youtu.be',
'host' : 'youtu.be',
}
], // hosts to include

'includeBySLD' : [
{
'addr' : 'reddit.com', // old.reddit.com
'host' : 'reddit',
},
{
'addr' : 'wikipedia.org',
'host' : 'wikipedia',
}
], // hosts to include by second-level-domain

'includeByPathnameAndSLD' : [
{
'addr' : 'google.com',
'host' : 'google',
'path' : ['search'],
}
], // hosts to include by pathname and second-level-domain

'includeByPathname' : [
{
'addr' : 'bt4g.org/magnet/',
'host' : 'bt4g.org',
'path' : ['magnet'],
},
{
'addr' : 'bing.com/(maps|search)',
'host' : 'bing.com',
'path' : ['maps', 'search'],
},
{
'addr' : 'fandom.com/wiki',
'host' : 'fandom.com',
'path' : ['wiki'],
},
{
'addr' : 'google.com/maps',
'host' : 'google.com',
'path' : ['maps'],
},
{
'addr' : 'stackoverflow.com/questions/',
'host' : 'stackoverflow.com',
'path' : ['questions'],
},
{
'addr' : 'yahoo.com/search',
'host' : 'yahoo.com',
'path' : ['search'],
},
{
'addr' : '(www|ul).waze.com/(live-map|ul)',
'host' : 'waze.com',
'path' : ['live-map', 'ul'],
},
{
'addr' : 'yandex.com/(maps|search)',
'host' : 'yandex.com',
'path' : ['maps', 'search'],
},
{ // THIS PART OF CODE BELONGS TO FJYT
'addr' : 'youtube-nocookie.com',
'host' : 'youtube-nocookie.com',
'path' : ['@', 'channel', 'watch'],
},
{ // THIS PART OF CODE BELONGS TO FJYT
'addr' : 'youtube.com',
'host' : 'youtube.com',
'path' : ['@', 'channel', 'watch'],
}
], // hosts to include by pathname

};

const proxy = {
'anonymousoverflow' : [
'http://anonymousoverflow.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion/',
'http://ao.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/',
'http://vernmzgraj6aaoafmehupvtkkynpaa67rxcdj2kinwiy6konn6rq.b32.i2p/',
'https://anonymousoverflow.esmailelbob.xyz',
'https://anonymousoverflow.vern.cc',
'https://ao.bloatcat.tk/',
//'https://ao.foss.wtf',
//'https://ao.vern.cc',
'https://code.whatever.social',
'https://stackoverflow.vern.cc',
//'https://overflow.777.tf',
'https://overflow.adminforge.de',
'https://overflow.hostux.net',
'https://overflow.lunar.icu',
'https://overflow.smnz.de'
], // AnonymousOverflow
'bibliogram' : [
'http://qsuiaf4jio2yaxdbj6ljte3jmr6m7g333rujoilbtipjeawnou26frad.onion',
'https://bib.actionsack.com',
'https://bib.riverside.rocks',
'https://biblio.alefvanoon.xyz',
'https://bibliogram.1d4.us',
'https://bibliogram.art',
'https://bibliogram.domain.glass',
'https://bibliogram.esmailelbob.xyz',
'https://bibliogram.froth.zone',
'https://bibliogram.pussthecat.org',
'https://bibliogram.snopyta.org',
'https://farside.link/bibliogram',
'https://insta.trom.tf',
'https://insta.tromdienste.de'
], // Bibliogram
'biblioreads' : [
'http://biblioreads.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'http://bl.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://vernapl3lpo3huqdx3pjzxqgdgavxjlmdskbvejh2gfqgmjuyvxq.b32.i2p',
'https://biblioreads.ga',
'https://biblioreads.ml',
'https://biblioreads.esmailelbob.xyz',
'https://biblioreads.lunar.icu',
'https://biblioreads.netlify.app',
'https://bl.vern.cc'
], // BiblioReads
'btdigg' : [
'https://btdig.com',
'http://btdigggink2pdqzqrik3blmqemsbntpzwxottujilcdjfz56jumzfsyd.onion/',
'http://btdig.i2p'
], // BTDigg
'breezewiki' : [
'https://antifandom.com',
//'https://breeze.777.tf',
'https://breeze.hostux.net',
//'https://breezewiki.com',
'https://breezewiki.pussthecat.org',
'https://bw.artemislena.eu',
'https://bw.projectsegfau.lt'
], // BreezeWiki
'cloudtube' : [
'https://tube.cadence.moe'
], // CloudTube
'gothub' : [
'https://dev.gh.akisblack.dev',
//'https://gh.777.tf',
'https://gh.akisblack.dev',
'https://gh.bloatcat.tk/',
'https://gh.creller.net',
'https://gh.fascinated.cc',
//'https://gh.odyssey346.dev',
'https://gh.phreedom.club',
'https://gh.riverside.rocks',
//'https://gh.vern.cc',
'https://gothub.dev.projectsegfau.lt',
'https://gothub.esmailelbob.xyz',
'https://gothub.lunar.icu',
'https://gothub.no-logs.com',
'https://gothub.projectsegfau.lt',
'https://gothub.xbdm.fun'
], // GotHub
'imgin' : [
'https://farside.link/imgin',
'https://imgin.voidnet.tech'
], // imgin
'invidious' : [
'http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion',
'http://euxxcnhsynwmfidvhjf6uzptsmh4dipkmgdmcmxxuo7tunp3ad2jrwyd.onion',
'http://grwp24hodrefzvjjuccrkw3mjq4tzhaaq32amf33dzpmuxe7ilepcmad.onion',
'http://inv.cn.i2p',
'http://inv.vern.i2p',
'http://jewtube.i2p',
'http://ytmous.i2p',
'http://invidious.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'http://invidious.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion',
'http://iv.odysfvr23q5wgt7i456o5t3trw2cw5dgn56vbjfbq2m7xsc5vqbqpcyd.onion',
'http://kbjggqkzv65ivcqj6bumvp337z6264huv5kpkwuv6gu5yjiskvan7fad.onion',
'http://ng27owmagn5amdm7l5s3rsqxwscl5ynppnis5dqcasogkyxcfqn7psid.onion',
'http://osbivz6guyeahrwp2lnwyjk2xos342h4ocsxyqrlaopqjuhwn2djiiyd.onion',
'http://pa7eextqat4wg35onzs4cnlhqa3gvzen243bcbrng67zyla4fqya.b32.i2p',
'http://qwikxxt6jvggxzxe2v2fuzro5j7ibgphxmblmri6wkj5vpicdbo2kwad.onion',
'http://u2cvlit75owumwpy4dj2hsmvkq7nvrclkpht7xgyye2pyoxhpmclkrad.onion',
'http://verni6dr4qxjgjumnvesxerh5rvhv6oy5ddeibaqy5d7tgbiiyfa.b32.i2p',
'http://w6ijuptxiku4xpnnaetxvnkc5vqcdu7mgns2u77qefoixi63vbvnpnqd.onion',
'https://farside.link/invidious',
'https://inv.bp.projectsegfau.lt',
'https://inv.odyssey346.dev',
'https://inv.riverside.rocks',
'https://inv.vern.cc',
'https://invidious.0011.lt',
'https://invidious.baczek.me',
'https://invidious.domain.glass',
'https://invidious.esmailelbob.xyz',
'https://invidious.flokinet.to',
'https://invidious.garudalinux.org',
'https://invidious.kavin.rocks',
'https://invidious.lunar.icu',
'https://invidious.mutahar.rocks',
'https://invidious.namazso.eu',
'https://invidious.nerdvpn.de',
'https://invidious.no-logs.com',
//'https://invidious.osi.kr',
'https://invidious.privacydev.net',
'https://invidious.projectsegfau.lt',
'https://invidious.sethforprivacy.com',
'https://invidious.slipfox.xyz',
'https://invidious.snopyta.org',
'https://invidious.qwik.space',
'https://invidious.tiekoetter.com',
'https://invidious.tinfoil-hat.net',
//'https://invidious.weblibre.org',
'https://invidious-us.kavin.rocks',
'https://iv.ggtyler.dev',
'https://iv.melmac.space',
//'https://tube.cthd.icu',
'https://y.com.sb',
'https://yewtu.be',
'https://yt.artemislena.eu',
'https://yt.funami.tech',
'https://yt.oelrichsgarcia.de',
'https://vid.puffyan.us',
'https://watch.thekitty.zone',
//'https://youtube.076.ne.jp',
'https://youtube.owacon.moe',
'https://yt.artemislena.eu'
], // Invidious
'laboratory' : [
'https://lab.bloatcat.tk'
], // Laboratory
'libmedium' : [
'http://md.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://vernaqj2qr2pijpgvf3od6ssc3ulz3nv52gwr3hba5l6humuzmgq.b32.i2p',
'https://libmedium.batsense.net',
'https://md.vern.cc',
'https://medium.hostux.net'
], // LibMedium
'libreddit' : [
'http://ecue64ybzvn6vjzl37kcsnwt4ycmbsyf74nbttyg7rkc3t3qwnj7mcyd.onion',
'http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion',
'http://inytumdgnri7xsqtvpntjevaelxtgbjqkuqhtf6txxhwbll2fwqtakqd.onion',
'http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion',
'http://kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion',
'http://lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion',
'http://ledditqo2mxfvlgobxnlhrkq4dh34jss6evfkdkb2thlvy6dn4f4gpyd.onion',
'http://libreddit.2syis2nnyytz6jnusnjurva4swlaizlnleiks5mjp46phuwjbdjqwgqd.onion',
'http://libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion',
'http://libredoxhxwnmsb6dvzzd35hmgzmawsq5i764es7witwhddvpc2razid.onion',
'http://liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion',
'http://ol5begilptoou34emq2sshf3may3hlblvipdjtybbovpb7c7zodxmtqd.onion',
'http://qwikxx4xqvhdyyazkrw7pwdpdppfnmn7j2n6cvq5zecm4atbppaslzad.onion',
'http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion',
'http://woo5ugmoomzbtaq6z46q4wgei5mqmc6jkafqfi5c37zni7xc4ymq.b32.i2p',
'https://farside.link/libreddit',
'https://discuss.whatever.social',
//'https://de.leddit.xyz',
//'https://leddit.xyz',
//'https://libreddit.40two.app',
'https://libreddit.albony.xyz',
//'https://libreddit.alefvanoon.xyz',
//'https://libreddit.autarkic.org',
//'https://libreddit.awesomehub.io',
'https://libreddit.bloatcat.tk/',
'https://libreddit.bus-hit.me',
'https://libreddit.crewz.me',
//'https://libreddit.database.red',
'https://libreddit.datatunnel.xyz',
'https://libreddit.de',
'https://libreddit.domain.glass',
//'https://libreddit.dothq.co',
//'https://libreddit.drivet.xyz',
'https://libreddit.esmailelbob.xyz',
'https://libreddit.eu.org/',
'https://libreddit.flux.industries',
'https://libreddit.hu',
//'https://libreddit.igna.rocks',
'https://libredd.it',
'https://libreddit.jamiethalacker.dev',
'https://libreddit.kavin.rocks',
'https://libreddit.kylrth.com',
//'https://libreddit.lunar.icu',
'https://libreddit.mutahar.rocks',
'https://libreddit.nl',
'https://libreddit.no-logs.com',
'https://libreddit.northboot.xyz',
'https://libreddit.pabloferreiro.es',
'https://libreddit.privacy.com.de',
'https://libreddit.pussthecat.org',
'https://libreddit.qwik.space',
//'https://libreddit.silkky.cloud',
'https://libreddit.some-things.org',
'https://libreddit.spike.codes',
'https://libreddit.strongthany.cc',
'https://libreddit.sugoma.tk',
'https://libreddit.tiekoetter.com',
'https://libreddit.totaldarkness.net',
'https://libreddit.winscloud.net',
'https://libreddit.yonalee.eu',
'https://lr.cowfee.moe',
'https://lr.foss.wtf',
'https://lr.mint.lgbt',
'https://lr.oversold.host',
'https://lr.riverside.rocks',
'https://lr.slipfox.xyz',
//'https://lr.stilic.ml',
'https://r.nf',
'https://r.walkx.org',
//'https://reddi.tk',
'https://reddit.artemislena.eu',
'https://reddit.invak.id',
//'https://reddit.phii.me',
'https://reddit.rtrace.io',
'https://reddit.stuehieyr.com',
'https://safereddit.com'
], // libreddit
'libremdb' : [
'http://ld.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://libremdb.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'http://vernz3ubrntql4wrgyrssd6u3qzi36zrhz2agbo6vibzbs5olk2q.b32.i2p',
'https://binge.whatever.social',
'https://ld.vern.cc',
'https://libremdb.esmailelbob.xyz',
'https://libremdb.iket.me',
'https://libremdb.pussthecat.org',
//'https://libremdbeu.herokuapp.com',
'https://libremdb.jeikobu.net',
'https://libremdb.lunar.icu',
'https://lmdb.hostux.net',
'https://lmdb.tokhmi.xyz',
'https://farside.link/libremdb'
], // libremdb
'librarian' : [
'http://5znbzx2xcymhddzekfjib3isgqq4ilcyxa2bsq6vqmnvbtgu4f776lqd.onion',
'http://bxewpsswttslepw27w2hhxhlizwm7l7y54x3jw5cfrb64hb6lgc557ad.onion',
'http://lbry.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://librarian.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'https://lbn.frail.duckdns.org',
'https://lbry.mywire.org',
'https://lbry.ooguy.com',
'https://lbry.projectsegfau.lt',
'https://lbry.slipfox.xyz',
'https://lbry.vern.cc',
'https://librarian.esmailelbob.xyz',
'https://librarian.pussthecat.org',
//'https://odysee.076.ne.jp',
'https://odysee.owacon.moe',
'https://farside.link/librarian'
], // librarian
'librex' : [
'http://7huurwog32tny663wkglrhozfoyqyqmsuxjbd7dtudccx44awjda.b32.i2p',
'http://fcnfg6avz45hqzwbneekq57u2mqbnwa7veyvjcc4dndqbatvkjlaj7yd.onion',
'http://f7ssz7l3biu4fugwctfpcx4txg5yq4gqhrt473ledsuc3ivtd3omniid.onion',
'http://librex.revvybrr6pvbx4n3j4475h4ghw4elqr4t5xo2vtd3gfpu2nrsnhh57id.onion',
'http://librex.zzlsghu6mvvwyy75mvga6gaf4znbp3erk5xwfzedb4gg6qqh2j6rlvid.onion',
'http://lqbchqljxiwl3bbjt4vqe76luovk5ly6khqhg7mt5qcqfn6e4sbq.b32.i2p',
'http://lx.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://revekebotog64xrrammtsmjwtwlg3vqyzwdurzt2pu6botg4bejq.b32.i2p',
'http://search.cepyxplublbyw2f4axy4pyztfbxmf63lrt2c7uwv6wl4iixz53czload.onion',
'http://search.swxoebbpeqiiixyhbuh3vbw53pdrmtbiaj2sqveol6kkn5rpapfi4aad.onion',
'http://vernziqfqvweijfaacmwazohgpdo2bt2ib2jlupt2pwwu27bhgxq.b32.i2p',
'https://buscar.weblibre.org',
'https://librex.baczek.me',
'https://librex.bloatcat.tk',
'https://librex.mikata.ru',
'https://librex.myroware.eu',
'https://librex.pufe.org',
'https://librex.ratakor.com',
'https://librex.retro-hax.net',
'https://librex.revvy.de',
'https://librex.zzls.xyz',
'https://lx.drain.win',
'https://lx.vern.cc',
'https://search.ahwx.org',
'https://search.davidovski.xyz',
'https://search.femboy.hu',
'https://search.funami.tech',
'https://search.madreyk.xyz',
'https://search.milivojevic.in.rs',
'https://search.pabloferreiro.es',
'https://search.sesu.cc',
'https://search.tildevarsh.in',
'https://search.zeroish.xyz',
'https://farside.link/librex'
], // LibreX
'lieu' : [
'https://lieu.cblgh.org'
], // Lieu
'lingva' : [
'https://farside.link/lingva',
'https://lingva.ml',
'https://lingva.pussthecat.org',
'https://farside.link/lingva'
], // Lingva
'map' : [
'https://facilmap.org',
'https://www.openstreetmap.org'
], // Maps
'mikuinvidious' : [
//'https://mi.resrv.org',
'https://moeyy.cn/mikuinvidious',
'https://mikuinv-gs.vern.cc',
'https://mikuinv.resrv.org'
], // MikuInvidious
'neuters' : [
'https://neuters.de'
], // Neuters
'nitter' : [
'http://tm4rwkeysv3zz3q5yacyr4rlmca2c4etkdobfvuqzt6vsfsu4weq.b32.i2p',
'http://qwikxx2erhx6qrymued6ox2qkf2yeogjwypqvzoif4fqkljixasr6oid.onion',
'https://bird.trom.tf',
'https://birdsite.xanny.family',
'https://de.nttr.stream',
'https://farside.link/nitter',
'https://n.hyperborea.cloud',
'https://nitter.1d4.us',
'https://nitter.42l.fr',
'https://nitter.actionsack.com',
'https://nitter.bus-hit.me',
'https://nitter.ca',
'https://nitter.domain.glass',
//'https://nitter.eu',
'https://nitter.fdn.fr',
//'https://nitter.ggc-project.de',
'https://nitter.grimneko.de',
'https://nitter.hostux.net',
'https://nitter.hu',
'https://nitter.it',
//'https://nitter.kavin.rocks',
//'https://nitter.koyu.space',
'https://nitter.moomoo.me',
'https://nitter.namazso.eu',
'https://nitter.net',
'https://nitter.no-logs.com',
//'https://nitter.pussthecat.org',
'https://nitter.qwik.space',
'https://nitter.sethforprivacy.com',
'https://nitter.slipfox.xyz',
'https://nitter.sneed.network',
'https://nitter.unixfox.eu',
'https://nttr.stream',
'https://read.whatever.social',
//'https://twitter.076.ne.jp',
'https://twitter.censors.us',
'https://twitter.owacon.moe',
'https://unofficialbird.com'
], // Nitter
'piped' : [
'https://farside.link/piped',
'https://il.ax',
'https://piped.adminforge.de',
'https://piped.chauvet.pro',
'https://piped.esmailelbob.xyz',
'https://piped.garudalinux.org',
'https://piped.hostux.net',
'https://piped.hostux.net',
'https://piped.in.projectsegfau.lt',
'https://piped.kavin.rocks',
'https://piped.lunar.icu',
'https://piped.mint.lgbt',
'https://piped.mha.fi',
'https://piped.moomoo.me',
'https://piped.no-logs.com',
'https://piped.palveluntarjoaja.eu',
'https://piped.privacy.com.de',
'https://piped.privacydev.net',
'https://piped.projectsegfau.lt',
'https://piped.qdi.fi',
'https://piped.smnz.de',
'https://piped.tokhmi.xyz',
'https://piped.tokhmi.xyz',
'https://piped.video',
'https://piped.us.projectsegfau.lt',
'https://watch.leptons.xyz',
'https://watch.whatever.social',
'https://watch.whatevertinfoil.de',
'https://yt.777.tf'
], // Piped
'pipedmaterial' : [
//'https://ngp.piped.xn--17b.net',
'https://piped-material.ftp.sh',
'https://piped-material.xn--17b.net'
], // Piped Material
'poketube' : [
'https://poketube.fun',
//'https://pt.zzls.xyz'
], // PokeTube
'proxitok' : [
'https://cringe.whatever.social',
'https://proxitok.pabloferreiro.es',
'https://proxitok.lunar.icu',
'https://proxitok.esmailelbob.xyz',
'https://proxitok.pabloferreiro.es',
'https://proxitok.privacy.com.de',
'https://proxitok.privacydev.net',
'https://proxitok.pufe.org',
'https://proxitok.pussthecat.org',
'https://tok.adminforge.de',
'https://tok.artemislena.eu',
'https://tok.habedieeh.re',
'https://tok.thekitty.zone',
'https://tik.hostux.net',
'https://tiktok.chauvet.pro',
'https://tt.vern.cc',
'https://farside.link/proxitok'
], // ProxiTok
'quetre' : [
'http://ask.habeehrhadazsw3izbrbilqajalfyqqln54mrja3iwpqxgcuxnus7eid.onion',
'http://qr.vern.i2p',
'http://qr.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://quetre.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'http://quetre.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion',
'http://quora.cepyxplublbyw2f4axy4pyztfbxmf63lrt2c7uwv6wl4iixz53czload.onion',
//'https://que.wilbvr.me',
'https://quetre.iket.me',
'https://quetre.pussthecat.org',
'https://quetre.tokhmi.xyz',
'https://quetre.projectsegfau.lt',
'https://quetre.esmailelbob.xyz',
//'https://quetre.odyssey346.dev',
'https://quetre.privacydev.net',
'https://ask.habedieeh.re',
'https://quetre.marcopisco.com',
'https://quetre.blackdrgn.nl',
'https://quetre.pufe.org',
'https://quetre.lunar.icu',
'https://quora.femboy.hu',
'https://quora.vern.cc',
'https://farside.link/quetre'
], // Quetre
'rimgo' : [
'https://farside.link/rimgo',
//'https://i.bcow.xyz',
//'https://img.riverside.rocks',
'https://rimgo.bus-hit.me',
'https://rimgo.hostux.net',
'https://rimgo.pussthecat.org',
'https://rimgo.totaldarkness.net',
'https://rimgo.vern.cc'
], // rimgo
'ruraldictionary' : [
'http://rd.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://ruraldictionary.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'http://vern5cxiaufqvhv4hu5ypkvw3tiwvuinae4evdbqzrioql6s2sha.b32.i2p',
'https://isdoingyour.mom',
'https://rd.bloatcat.tk',
'https://rd.vern.cc',
'https://ruraldictionary.esmailelbob.xyz'
], // Rural Dictionary
 'scribe' : [
'https://farside.link/scribe',
'https://scribe.bus-hit.me',
'https://scribe.citizen4.eu',
'https://scribe.froth.zone',
'https://scribe.nixnet.services',
'https://scribe.rip'
], // Scribe
'searx' : [
'https://dynabyte.ca',
'https://etsi.me',
//'https://farside.link/searx',
'https://farside.link/searxng',
//'https://monocles.de',
'https://procurx.pt',
'https://northboot.xyz',
'https://paulgo.io',
'https://recherche.facil.services',
'https://s.zhaocloud.net',
'https://search.asynchronousexchange.com',
'https://search.exarius.org',
'https://search.jpope.org',
'https://search.mdosch.de',
'https://search.neet.works',
'https://search.ononoki.org',
'https://search.rabbit-company.com',
'https://search.vojkovic.xyz',
'https://search.zzls.xyz',
'https://searx.be',
'https://searx.catfluori.de',
'https://searx.divided-by-zero.eu',
'https://searx.domain.glass',
'https://searx.dresden.network',
'https://searx.ebnar.xyz',
'https://searx.fmac.xyz',
'https://searx.foss.wtf',
'https://searx.gnu.style',
//'https://searx.jaska.cc',
'https://searx.mha.fi',
'https://searx.ninja',
'https://searx.prvcy.eu',
'https://searx.rasp.fr',
'https://searx.ru',
'https://searx.sp-codes.de',
'https://searx.stuehieyr.com',
'https://searx.theanonymouse.xyz',
'https://searx.tiekoetter.com',
'https://searx.tux.land',
'https://searx.tuxcloud.net',
'https://searx.tyil.nl',
'https://searx.webheberg.info',
'https://searxng.no-logs.com',
'https://searxng.zackptg5.com',
'https://swag.pw',
'https://sx.catgirl.cloud',
], // SearXNG
'simplytranslate' : [
'https://farside.link/simplytranslate',
'https://simplytranslate.esmailelbob.xyz',
'https://simplytranslate.org',
'https://simplytranslate.pussthecat.org',
//'https://st.alefvanoon.xyz',
'https://st.bloatcat.tk/',
'https://st.manerakai.com',
'https://tl.slipfox.xyz',
'https://translate.bus-hit.me',
'https://translate.josias.dev',
'https://translate.namazso.eu',
'https://translate.northboot.xyz',
'https://translate.riverside.rocks',
'https://translate.syncpundit.com',
'https://translate.tiekoetter.com'
], // SimplyTranslate
'spot' : [
'https://search.ggc-project.de',
], // Spot
'teddit' : [
'http://[200:5e4b:515c:e42b:3e73:6fbf:2f11:779d]',
'http://k62ptris7p72aborr4zoanee7xai6wguucveptwgxs5vbgt7qzpq.b32.i2p',
'http://teddit.i2p',
'http://tedditfyn6idalzso5wam5qd3kdtxoljjhbrbbx34q2xkcisvshuytad.onion',
'https://farside.link/teddit',
'https://incogsnoo.com',
'https://teddit.adminforge.de',
//'https://teddit.alefvanoon.xyz',
'https://teddit.bus-hit.me',
//'https://teddit.domain.glass',
'https://teddit.froth.zone',
//'https://teddit.ggc-project.de',
'https://teddit.hostux.net',
'https://teddit.httpjames.space/',
'https://teddit.namazso.eu',
'https://teddit.no-logs.com',
'https://teddit.net',
'https://teddit.pussthecat.org',
'https://teddit.sethforprivacy.com',
//'https://teddit.tinfoil-hat.net',
'https://teddit.totaldarkness.net',
'https://teddit.zaggy.nl'
], // teddit
'tent' : [
'https://tent.sny.sh',
'https://tent.bloatcat.tk'
], // Tent
'uso' : [
'https://userscripts-mirror.org'
], // UserScripts.org
'waybackclassic' : [
'http://waybackclassic.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion',
'https://waybackclassic.esmailelbob.xyz',
'https://wayback-classic.net'
], // Wayback Classic
'wikiless' : [
'http://wikiless.i2p',
'https://farside.link/wikiless',
//'https://wiki.604kph.xyz',
'https://wiki.froth.zone',
//'https://wikiless.alefvanoon.xyz',
'https://wikiless.bloatcat.tk/',
//'https://wikiless.lunar.icu',
'https://wikiless.northboot.xyz',
'https://wikiless.org',
'https://wiki.adminforge.de',
'https://wiki.slipfox.xyz',
'https://wikiless.esmailelbob.xyz',
'https://wikiless.funami.tech',
//'https://wikiless.sethforprivacy.com',
'https://wikiless.tiekoetter.com'
], // Wikiless
'whoogle' : [
'http://nuifgsnbb2mcyza74o7illtqmuaqbwu4flam3cdmsrnudwcmkqur37qd.onion',
'http://whoglqjdkgt2an4tdepberwqz3hk7tjo4kqgdnuj77rt7nshw2xqhqad.onion',
'http://whoogle.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion',
'http://whoogle.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion',
'http://verneks7rfjptpz5fpii7n7nrxilsidi2qxepeuuf66c3tsf4nhq.b32.i2p',
'https://farside.link/whoogle',
'https://google.owacon.moe',
'https://gowogle.voring.me',
//'https://s.alefvanoon.xyz',
'https://s.tokhmi.xyz',
'https://search.albony.xyz',
'https://search.dr460nf1r3.org',
'https://search.foss.wtf',
'https://search.garudalinux.org',
'https://search.sethforprivacy.com',
'https://wgl.frail.duckdns.org',
'https://wg.vern.cc',
'https://whoogle.dcs0.hu',
'https://whoogle.esmailelbob.xyz',
'https://whoogle.hxvy0.gq',
'https://whoogle.lunar.icu',
'https://whoogle.hostux.net',
'https://whoogle.link',
'https://whoogle.no-logs.com',
'https://whoogle.privacydev.net'
], // Whoogle
'yacy' : [
'https://51.79.164.235:8443',
'https://58.179.103.130:49153',
'https://76.9.226.109:8444',
'https://78.55.177.108:8443',
'https://85.199.74.98:8443',
'https://93.190.202.83:8443',
'https://109.230.224.225:8443',
'https://162.210.6.138:8443',
'https://176.31.104.225:8448',
//'https://185.243.10.140:8443',
'https://farside.link/yacy',
'https://search.yacy.net',
'https://www.gumx.de:8091',
'https://yacy.iko.soy'
], // YaCy
};

  // FIXME https://wiki.postmarketos.org/wiki/BQ_Aquaris_X5_(bq-paella)#Installation
  // <a href="https://www.youtube.com/watch?v=4NpS1uqTjlQ" rel="noreferrer"><img alt="Bq-paella-installation-tutorial.jpg" src="/images/thumb/c/ce/Bq-paella-installation-tutorial.jpg/256px-Bq-paella-installation-tutorial.jpg" decoding="async" width="256" height="144" srcset="/images/thumb/c/ce/Bq-paella-installation-tutorial.jpg/384px-Bq-paella-installation-tutorial.jpg 1.5x, /images/thumb/c/ce/Bq-paella-installation-tutorial.jpg/512px-Bq-paella-installation-tutorial.jpg 2x"></a>

  // FIXME http://xlunch.org/
  // <div id="downloads" class="clearfix" align="center">
  //        <a href="https://gh.odyssey346.dev/Tomas-M/xlunch/archive/v4.7.4.zip" id="download-zip" class="button" rel="noreferrer"><span>Download xlunch v4.7.4.zip &nbsp;&nbsp;</span></a>
  //        <a href="https://gothub.lunar.icu/Tomas-M/xlunch/archive/v4.7.4.tar.gz" id="download-tar-gz" class="button" rel="noreferrer"><span>Download xlunch v4.7.4.tar.gz &nbsp;&nbsp;</span></a>
  //        <a href="https://github.com/Tomas-M/xlunch" id="view-on-github" class="button" rel="noreferrer"><span>View on GitHub &nbsp;&nbsp;</span></a>
  // </div>

// /questions/29896128/add-event-listener-on-every-link

// try also infocus, focus or similar
//document.body.addEventListener("click", function(e) {

// FIXME Wrong link might change if cursor moves to
// another link when 'init' has engaged (maybe async)

// FIXME Not working with a which contains img
// See https://www.tribler.org/

/*

TODO Scan 'e.target.childNodes' until 'A' (link) is found

https://vitejs.dev/

<div class="action" data-v-b00ba1cd=""><a class="VPButton medium alt" href="https://github.com/vitejs/vite" rel="noreferrer" data-v-b00ba1cd="" data-v-22914356="">View on GitHub</a></div>

*/

document.body.addEventListener("mouseover", function(e) { // mouseover works with keyboard too
  if (e.target && e.target.nodeName == "A") {
    // In earlier version, "promise" api was utilized
    // Function init returned value from function xhr()
    // which received values from pickURL() and settURL().
    //   mod = init(link.href, link.outerText);
    //   if (mod) {
    //     link.href = mod
    //   }
    // In this version, the final stage is done inside xhr()
    hyperLink = e.target;
    // TODO Pass false for "synchronous: false"
    init(hyperLink.href, hyperLink.outerText);
  } // else if e.target.hasChildNodes()
});

/* TODO handle all links on page
for (const link of document.querySelectorAll('a[href^="http"]')) {
  // TODO Pass true for "synchronous: true"
  mod = init(link.href, link.outerText);
  if (mod) {
    link.href = mod
  }
}
*/

function init(link, text) {
  let url;
  try {
    url = new URL(link);  // Why url api accepts elements?
  } catch (err) {
    //console.warn(url);
    //console.error(err);
    return;
  }

  let host = url.hostname
  let path = url.pathname
  
  // check by excluded
  for (let i = 0; i < urls.exclude.length; i++) {
    //if (host.endsWith(urls.exclude[i].host)) {
    //if (host.match(urls.exclude[i].host)) {
    if (host == urls.exclude[i].host ||
        host == 'www.' + urls.exclude[i].host) {
      for (let j = 0; j < urls.exclude[i].path.length; j++) {
        if (path.includes('/' + urls.exclude[i].path[j])) {
          return; // exit further check
        }
      }
      if (urls.exclude[i].text) {
        for (let j = 0; j < urls.exclude[i].text.length; j++) {
          if (text.match(urls.exclude[i].text[j])) {
            return; // exit further check
          }
        }
      }
    }
  }

  // continue to includeByHostname
  for (let i = 0; i < urls.includeByHostname.length; i++) {
    // perhaps use 'match' and create a new object.array for domains with multiple subdomains
    if (host == urls.includeByHostname[i].host ||
        host == 'www.' + urls.includeByHostname[i].host) {
    //if (host.endsWith(urls.includeByHostname[i].host)) {
      return xhr(link);
    }
  }

  // continue to specific
  for (let i = 0; i < urls.includeByPathname.length; i++) {
    if (host.endsWith(urls.includeByPathname[i].host)) {
      for (let j = 0; j < urls.includeByPathname[i].path.length; j++) {
        if (path.startsWith('/' + urls.includeByPathname[i].path[j])) {
          return xhr(link);
        }
      }
    }
  }

  // continue to second-level-domain
  for (let i = 0; i < urls.includeBySLD.length; i++) {
    partedHost = host.split('.');
    if (partedHost[partedHost.length-2].match(urls.includeBySLD[i].host)) {
      return xhr(link);
    }
  }

  // continue to second-level-domain and path
  for (let i = 0; i < urls.includeByPathnameAndSLD.length; i++) {
    partedHost = host.split('.');
    if (partedHost[partedHost.length-2].match(urls.includeByPathnameAndSLD[i].host)) {
      for (let j = 0; j < urls.includeByPathnameAndSLD[i].path.length; j++) {
        if (path.startsWith('/' + urls.includeByPathnameAndSLD[i].path[j])) {
          return xhr(link);
        }
      }
    }
  }
}

// TODO Remove href and restore href
function linkOnProgress() {
  //originalColor = hyperLink.style.color;
  hyperLink.style.color = 'aquamarine';
  //hyperLink.innerHTML = `↻ ${hyperLink.innerHTML}`;
  //hyperLink.setAttribute('proxy-redirect', 'loading');
  hyperLink.title = 'Looking up for online proxy';
}

function linkOnSuccess() {
  //hyperLink.innerHTML = hyperLink.innerHTML.replace('↻ ','');
  //hyperLink.removeAttribute('proxy-redirect');
  hyperLink.removeAttribute('title');
  //hyperLink.style.color = originalColor;
  hyperLink.style.color = 'forestgreen';
  hyperLink.removeAttribute('style');
}

function linkOnError() {
  //hyperLink.innerHTML.replace('↻','⚠');
  //hyperLink.setAttribute('proxy-redirect', 'warning'); // ⚠
  hyperLink.style.color = 'orange';
  //hyperLink.innerHTML = `⚠ ${hyperLink.innerHTML}`;
  hyperLink.title = 'Proxy online state check was not possible, Please refresh and try again in case the offered page is offline.';
}

function linkOnFail() {
  //hyperLink.innerHTML.replace('↻','⚠');
  //hyperLink.setAttribute('proxy-redirect', 'warning'); // ⚠
  hyperLink.style.color = 'red';
  //hyperLink.innerHTML = `⚠ ${hyperLink.innerHTML}`;
  hyperLink.title = 'Found no online proxy';
}

function xhr(url) {
  instance = pickURL(url);
  gmXmlhttpRequest({
    method: 'GET',
    url: instance,
    //synchronous: true,
    onprogress: linkOnProgress(),
    onload: function(response) {
      if (response.finalUrl.startsWith(instance)) {
        hyperLink.href = settURL();
        linkOnSuccess();
      } else {
        //instance = instance.slice(instance.lastIndexOf('/')+1);
        //instance = instance.replace(/\./g,'-');
        console.warn('Instance URL ' + instance + ' might be out of service. URL has changed. Please report this to the developer.');
        if (maxAttempts()) {
          // Warning sign ⚠ or Strikethrough link and add attribute title says "no proxy found"
          linkOnFail();
          console.warn(`Max attempts for URL ${url} reached.`);
          return;
        }
        maxAttempts();
        xhr();
      }
    },
    onerror: function(response) {
      console.warn(`It appears that GM.xmlHttpRequest is not able to bypass Content Security Policy. Response status: ${response.status} . See Falkon web browser issue at https://bugs.kde.org/show_bug.cgi?id=466533`);
      farside = true;
      hyperLink.href = settURL();
      linkOnError();
    }
  });
}

function maxAttempts() {
  attemptCounter = attemptCounter + 1;
  if (attemptCounter == urlArray.length) { return true; }
}

function setValue(para) {
  if (partedURL.searchParams.get(para)) {
    para = [para];
    return pickParameters(para);
  } else {
    return 'auto';
  }
}

function pickParameters(para) {
  for (let i = 0; i < para.length; i++) {
    if (partedURL.searchParams.get(para[i])) {
      para = partedURL.searchParams.get(para[i]);
      partedURL.searchParams.delete(para[i]);
      return para;
    }
  }
}

function pickURL(url) {

  try {
    partedURL = new URL(url);
  } catch (err) {
    //console.log(url);
    //console.error(err);
    return;
  }

  hostname = partedURL.hostname;
  pathname = partedURL.pathname;

  switch (true) {

    case hostname.endsWith('bandcamp.com'):
      urlArray = proxy.tent;
      break;

    case hostname.endsWith('bilibili.com'):
      urlArray = proxy.mikuinvidious;
      break;

    case hostname.endsWith('bt4g.org'):
    case hostname.endsWith('torrentdownload.info'):
    case hostname.endsWith('torrentz.eu'):
    case hostname.endsWith('torrentz.me'):
    case hostname.endsWith('torrentz2.is'):
      urlArray = proxy.btdigg;
      break;

    case hostname.endsWith('fandom.com'):
      urlArray = proxy.breezewiki;
      break;

    case hostname.endsWith('github.com'):
      urlArray = proxy.gothub;
      break;

    case hostname.endsWith('gitlab.com'):
      urlArray = proxy.laboratory;
      break;

    case hostname.endsWith('goodreads.com'):
      urlArray = proxy.biblioreads;
      break;

    // TODO quadkey (mapquest)
    // NOTE quadkeyToTile(quadkey) See /mapbox/tilebelt
    case hostname.endsWith('wikimap.toolforge.org'):
    case (hostname.endsWith('moovitapp.com') &&
          partedURL.search.includes('tll')):
    case (hostname.endsWith('bing.com') &&
          pathname.startsWith('/maps')):
    case (hostname.includes('google.') &&
          pathname.startsWith('/maps')):
    case (hostname.includes('waze.com') &&
          pathname.startsWith('/live-map')):
    case (hostname.includes('waze.com') &&
          pathname.startsWith('/ul')):
    case (hostname.includes('yandex.') &&
          pathname.startsWith('/maps')):
      urlArray = proxy.map;
      break;

    case hostname.endsWith('imdb.com'):
      urlArray = proxy.libremdb;
      break;

    case hostname.endsWith('imgur.com'):
      //proxyArray = [proxy.imgin, proxy.rimgo];
      proxyArray = [proxy.rimgo];
      break;
/*
    case hostname.endsWith('instagram.com'):
      urlArray = proxy.bibliogram;
      break;
*/
    case hostname.endsWith('medium.com'):
      proxyArray = [proxy.libmedium, proxy.scribe];
      break;

    case hostname.endsWith('odysee.com'):
      urlArray = proxy.librarian;
      break;

    case hostname.endsWith('quora.com'):
      urlArray = proxy.quetre;
      break;

    case hostname.endsWith('reddit.com'):
      proxyArray = [proxy.libreddit, proxy.teddit];
      break;

    case hostname.endsWith('reuters.com'):
      urlArray = proxy.neuters;
      break;

    // FIXME
    case (hostname.startsWith('search.yahoo.')):
    case (pathname.startsWith('/search')):
    case (hostname.includes('yandex.') &&
          pathname.startsWith('/search')):
    case (hostname.includes('yahoo.') &&
          pathname.startsWith('/search')):
    case (hostname.includes('bing.') &&
          pathname.startsWith('/search')):
    case (hostname.includes('google.') &&
          pathname.startsWith('/search')):
      proxyArray = [proxy.librex, proxy.lieu,
                    proxy.searx, proxy.spot,
                    proxy.whoogle
                   ];
      break;

    case hostname.endsWith('stackoverflow.com'):
      urlArray = proxy.anonymousoverflow;
      break;

    case hostname.endsWith('tiktok.com'):
      urlArray = proxy.proxitok;
      break;

    case (hostname.endsWith('translate.yandex.com')):
          // FIXME website blocks us from redirecting
          // function setTimeout() seems to not work
          // consider different approach/way
    case (hostname.endsWith('translate.google.com')):
      proxyArray = [proxy.lingva, proxy.simplytranslate];
      break;

    case hostname.endsWith('twitter.com'):
      urlArray = proxy.nitter;
      break;

    case hostname.endsWith('urbandictionary.com'):
      urlArray = proxy.ruraldictionary;
      break;

    case hostname.endsWith('userscripts.org'):
      urlArray = proxy.uso;
      break;

    case hostname.endsWith('wikipedia.org'):
      urlArray = proxy.wikiless;
      break;

    case hostname.endsWith('youtu.be'):
    case hostname.endsWith('youtube.com'):
    case hostname.endsWith('youtube-nocookie.com'):
    case hostname.endsWith('invidious-invidious.invidious.svc.cluster.local:3000'):
      proxyArray = [proxy.cloudtube, proxy.invidious,
                    proxy.piped, proxy.pipedmaterial,
                    proxy.poketube
                   ];
      break;

    //default:
    //  return target;

  }

  // proxy select
  if (proxyArray) {
    urlArray = proxyArray[Math.floor(Math.random()*proxyArray.length)];
  }

  // instance select
  return urlArray[Math.floor(Math.random()*urlArray.length)];

}

// Settlement
function settURL() {
  let newPath;
  switch (urlArray) {

    // consider function setTimeout()
    case proxy.bibliogram:
      if (!pathname.includes('accounts/login')) {
        newPath = `/u/${para}`;
      } else {
        if (partedURL.searchParams.get('next')) {
          para = ['next'];
          para = pickParameters(para);
          newPath = `/u/${para}`;
        }
      }
      break;

    case proxy.breezewiki:
      // extract wiki name
      partedHost = hostname.split('.');
      if (partedHost.length === 3 || partedHost.length === 4) {
        brand = partedHost[0];
      }
      newPath = `/${brand}${pathname}`;
      break;

    case proxy.btdigg:
      // extract sha1sum
      //hash = pathname.split('/')[2];
      hash = pathname.split('/');
      for (let i = 0; i < hash.length; i++) {
        if (hash[i].length === 40) {
          hash = hash[i];
          break;
        }
      }
      newPath = `/${hash}`;
      break;

    case proxy.cloudtube:
    case proxy.invidious:
    case proxy.piped:
    case proxy.pipedmaterial:
    case proxy.poketube:
      if (partedURL.searchParams.get('v')) {
        para = ['v'];
        para = pickParameters(para);
        newPath = `/watch?v=${para}`;
      }
      break;

    case proxy.gothub:
      if (hostname.endsWith('gist.github.com')) {
        newPath = `/gist${pathname}`;
      }
      break;

    case proxy.laboratory:
      newPath = '/' + hostname + pathname;
      break;

    case proxy.libmedium:
      partedHost = hostname.split('.');
      if (partedHost.length === 3 || partedHost.length === 4) {
        name = partedHost[0];
      }
      newPath = `/@${name}${pathname}`;
      break;

    case proxy.librex:
      // extract search parameter
      para = ['q','text','p'];
      para = pickParameters(para);
      newPath = `/search.php?q=${para}`;
      break;

    case proxy.lingva:
      // extract text parameter
      paras = ['sl','tl','text'];

      for (let i = 0; i < paras.length; i++) {
        paras[i] = setValue(paras[i]);
      }

      //if (paras[2] === 'auto') { paras[2] = ''; }
      
      if ((paras[0] == 'auto') && (paras[1] == 'auto')) {
        newPath = `/${paras[2]}`;
      } else {
        newPath = `/${paras[0]}/${paras[1]}/${paras[2]}`;
      }
      break;

    case proxy.map:
      // extract coordinations
      /*
      if (pathname.includes('@')) {
        cord = pathname.split('/')[2].split('&')[0].slice(1);
        cord = cord.split(',');
      }
      newPath = '/#map=' + cord[2].slice(0, 1) +
             '/' + cord[0] + '/' + cord[1];
      */
      let lat, lon, zoom;
      // extract coordinations
      if (partedURL.search.includes('%7E')) { // %7E is ~
        para = ['cp'];
        cord = pickParameters(para);
        cord = cord.split('~');
        para = ['lvl'];
        zoom = pickParameters(para);
        lat = cord[0];
        lon = cord[1];
      } else
      if (partedURL.search.includes('to')) {
        para = ['to'];
        cord = pickParameters(para);
        cord = cord.slice(3).split(',');
        lat = cord[0];
        lon = cord[1];
      } else
      if (pathname.includes('ul') &&
          partedURL.search.includes('ll')) {
        para = ['ll'];
        cord = pickParameters(para);
        cord = cord.split(',');
        para = ['zoom'];
        zoom = pickParameters(para);
        lat = cord[0];
        lon = cord[1];
      } else
      if (partedURL.search.includes('ll')) {
        para = ['ll'];
        cord = pickParameters(para);
        cord = cord.split(',');
        para = ['z'];
        zoom = pickParameters(para);
        lat = cord[0];
        lon = cord[1];
      } else
      if (partedURL.search.includes('tll')) {
        para = ['tll'];
        cord = pickParameters(para);
        cord = cord.split('_');
        lat = cord[0];
        lon = cord[1];
      } else
      if (pathname.includes('@')) {
        partedPath = pathname.split('/')
        for (let i = 0; i < partedPath.length; i++) {
          if (partedPath[i].startsWith('@')) {
            cord = partedPath[i].split(',');
          }
        }
        lat = cord[0].slice(1);
        lon = cord[1];
        zoom = cord[2];
        //newPath = `/#map=${cord[2].slice(0, 2)}/${cord[0].slice(1)}/${cord[1]}`;
        //newPath = `/#map=${cord[2]}/${cord[0].slice(1)}/${cord[1]}`;
        //newPath = `/#${cord[2]}/${cord[0].slice(1)}/${cord[1]}/`;
      }

      if (lat && lon && zoom) {
        newPath = `/#${zoom}/${lat}/${lon}/`;
      } else
      if (lat && lon && !zoom) {
        newPath = `/#10/${lat}/${lon}/`;
      }

      if (!newPath && partedURL.searchParams.get('q')) {
        para = ['q'];
        para = pickParameters(para);
        newPath = `/search?query=${para}`;
        instance = 'https://www.openstreetmap.org';
      }
      break;

    case proxy.lieu:
    case proxy.searx:
    case proxy.whoogle:
      // extract search parameter
      para = ['q','text','p'];
      para = pickParameters(para);
      newPath = `/search?q=${para}`;
      break;

    case proxy.mikuinvidious:
      if (!hostname.startsWith('www.')) {
        partedHost = hostname.split('.');
        if (partedHost.length === 3 || partedHost.length === 4) {
          name = partedHost[0];
        }
        newPath = `/${name}${pathname}`;
      }
      break;

    case proxy.tent:
      partedHost = hostname.split('.');
      if (partedHost.length === 3 || partedHost.length === 4) {
        artist = partedHost[0];
      }
      partedPath = pathname.split('/');
      type = partedPath[1];
      name = partedPath[2];
      if (name) {
        newPath = `/release.php?artist=${artist}&type=${type}&name=${name}`;
      } else {
        newPath = `/release.php?artist=${artist}&type=${type}`;
      }
      break;

    case proxy.wikiless:
      // extract language code
      partedHost = hostname.split('.');
      if (partedHost.length === 3 || partedHost.length === 4) {
        lang = partedHost[0];
      }
      newPath = `${pathname}?lang=${lang}`;
      break;

    case proxy.yacy:
      // extract search parameter
      para = ['q','text','p'];
      //pickParameters(paras); // works even when just calling the function?
      para = pickParameters(para);
      newPath = `/yacysearch.html?query=${para}`;
      break;

  }

  if (!newPath || newPath == '/') {
    newPath = pathname + partedURL.search + partedURL.hash;
  }

  if (farside) {
    if (urlArray.filter(str => str.includes('farside.link')).length) {
      instance = urlArray.filter(str => str.includes('farside.link'))[0];
    }
  }

  //return new URL(instance + newPath);
  modURL = new URL(instance + newPath);
  return modURL;

}