qutebrowser: Use farside for dynamic redirects

The redirector can now be fed with either a list of targets to pick from
(as before) or a "farside" entry which points to a farside service
redirect or multiple.

The dict entry then looks like:

```python
"quora": {
    "source": ["quora.com"],
    "farside": ["quetre"],
}
```

It has the source service url as usual, but then instead of a "target"
entry contains a "farside" entry.

A redirect dict entry can take both "target" and "farside" entries, but
will then always give precedence to farside choices.

This should go a long way in helping keep OSS frontends up to date. It
now mostly depends on farside entries in turn being updated.
One potential concern is the new centralization in relying on farside as
the redirect authority.
This commit is contained in:
Marty Oehme 2024-02-05 12:09:23 +01:00
parent a91f553f58
commit 20b9d432ac
Signed by: Marty
GPG key ID: EDBF2ED917B2EF6A

View file

@ -1,6 +1,8 @@
import random import random
from urllib import parse
import re import re
from typing import Any, Callable
from urllib import parse
from qutebrowser.api import interceptor from qutebrowser.api import interceptor
from qutebrowser.extensions.interceptors import QUrl, RedirectException from qutebrowser.extensions.interceptors import QUrl, RedirectException
from qutebrowser.utils import message from qutebrowser.utils import message
@ -30,157 +32,81 @@ def fixScribePath(url: QUrl):
redirects = { redirects = {
"youtube": { "youtube": {
"source": ["youtube.com"], "source": ["youtube.com"],
"target": [ "farside": ["invidious"],
"invidious.no-logs.com", },
"inv.citw.lgbt", "stackoverflow": {
"invidious.privacydev.net", "source": ["stackoverflow.com"],
"inv.tux.pizza", "farside": ["anonymousoverflow"],
"invidious.einfachzocken.eu",
"invidious.perennialte.ch",
"invidious.fdn.fr",
"invidious.nerdvpn.de",
"inv.zzls.xyz",
"invidious.private.coffee",
"invidious.projectsegfau.lt",
"invidious.lunar.icu",
"yewtu.be",
"iv.melmac.space",
"iv.datura.network",
"piped.kavin.rocks",
],
}, },
"lbry": { "lbry": {
"source": ["odysee.com"], "source": ["odysee.com"],
"target": [ "farside": ["librarian"],
"lbry.bcow.xyz",
"odysee.076.ne.jp",
"librarian.pussthecat.org",
"lbry.mutahar.rocks",
"lbry.vern.cc",
],
}, },
"reddit": { "reddit": {
"source": ["reddit.com"], "source": ["reddit.com"],
"target": [ "farside": ["redlib"],
"teddit.ggc-project.de", },
"teddit.kavin.rocks", "instagram": {
"teddit.zaggy.nl", "source": ["instagram.com"],
"teddit.namazso.eu", "farside": ["proxigram"],
"teddit.nautolan.racing",
"teddit.tinfoil-hat.net",
"teddit.domain.glass",
"libreddit.kavin.rocks",
"safereddit.com",
"reddit.invak.id",
"reddit.simo.sh",
"libreddit.strongthany.cc",
"libreddit.domain.glass",
"libreddit.pussthecat.org",
"libreddit.kylrth.com",
"libreddit.privacydev.net",
"l.opnxng.com",
"libreddit.oxymagnesium.com",
"reddit.utsav2.dev",
"libreddit.freedit.eu",
"lr.artemislena.eu",
"snoo.habedieeh.re",
],
}, },
"twitter": { "twitter": {
"source": ["twitter.com"], "source": ["twitter.com"],
"target": [ "farside": ["nitter"],
"nitter.net",
"nitter.42l.fr",
"nitter.fdn.fr",
"nitter.1d4.us",
"nitter.kavin.rocks",
"nitter.unixfox.eu",
"nitter.namazso.eu",
"nitter.moomoo.me",
"bird.trom.tf",
"nitter.it",
"twitter.censors.us",
"nitter.grimneko.de",
"twitter.076.ne.jp",
"n.l5.ca",
"unofficialbird.com",
"nitter.ungovernable.men",
],
}, },
"imdb": { "imdb": {
"source": ["imdb.com"], "source": ["imdb.com"],
"target": [ "farside": ["libremdb"],
"libremdb.iket.me",
"libremdb.pussthecat.org",
"ld.vern.cc",
"binge.whatever.social",
"libremdb.lunar.icu",
],
}, },
"translate": { "translate": {
"source": ["translate.google.com"], "source": ["translate.google.com"],
"target": [ "farside": ["lingva"],
"lingva.ml",
"translate.igna.wtf",
"translate.plausibility.cloud",
"translate.projectsegfau.lt",
"translate.dr460nf1r3.org",
"lingva.garudalinux.org",
"translate.jae.fi",
],
}, },
"tiktok": { "tiktok": {
"source": ["tiktok.com"], "source": ["tiktok.com"],
"target": [ "farside": ["proxitok"],
"proxitok.pabloferreiro.es",
"proxitok.pussthecat.org",
"tok.habedieeh.re",
"proxitok.privacydev.net",
"proxitok.odyssey346.dev",
"tok.artemislena.eu",
"tok.adminforge.de",
"proxitok.manasiwibi.com",
"tik.hostux.net",
"tt.vern.cc",
"proxitok.mha.fi",
"proxitok.pufe.org",
"proxitok.marcopisco.com",
"cringe.whatever.social",
"proxitok.lunar.icu",
],
}, },
"imgur": { "imgur": {
"source": ["imgur.com"], "source": ["imgur.com"],
"target": [ "farside": ["rimgo"],
"imgur.artemislena.eu",
"ri.zzls.xyz",
"rimgo.bus-hit.me",
"rimgo.fascinated.cc",
"rimgo.hostux.net",
"rimgo.kling.gg",
"rimgo.lunar.icu",
"rimgo.marcopisco.com",
"rimgo.privacytools.io",
"rimgo.projectsegfau.lt",
"rimgo.pussthecat.org",
"rimgo.totaldarkness.net",
"rimgo.whateveritworks.org",
],
}, },
"medium": { "medium": {
"source": ["medium.com"], "source": ["medium.com"],
"target": [ "farside": ["scribe"],
"scribe.rip", # "postprocess": fixScribePath
"scribe.citizen4.eu", },
"scribe.bus-hit.me", "fandom": {
"sc.vern.cc", "source": ["fandom.com"],
], "farside": ["breezewiki"],
"postprocess": fixScribePath, },
"quora": {
"source": ["quora.com"],
"farside": ["quetre"],
# "postprocess": lambda url: message.info(f"CALLING QUORA WITH {url}")
}, },
"google": { "google": {
"source": ["google.com"], "source": ["google.com"],
"target": [ "target": [
"search.albony.xyz",
"search.garudalinux.org",
"search.dr460nf1r3.org",
"s.tokhmi.xyz",
"search.sethforprivacy.com",
"whoogle.dcs0.hu", "whoogle.dcs0.hu",
"gowogle.voring.me",
"whoogle.privacydev.net",
"wg.vern.cc",
"whoogle.hxvy0.gq",
"whoogle.hostux.net",
"whoogle.lunar.icu",
"wgl.frail.duckdns.org",
"whoogle.no-logs.com",
"whoogle.ftw.lol",
"whoogle-search--replitcomreside.repl.co",
"search.notrustverify.ch",
"whoogle.datura.network",
"whoogle.yepserver.xyz",
"search.nezumi.party",
], ],
}, },
} }
@ -199,18 +125,42 @@ def rewrite(request: interceptor.Request) -> None:
url = request.request_url url = request.request_url
if service := _should_be_redirected(url.host()): if service := _should_be_redirected(url.host()):
# TODO integrate pinging and always surf to fastest? if "farside" in service:
target = service["target"][random.randint(0, len(service["target"]) - 1)] url = _farside_redirect(url, _pick_random(service["farside"]))
if target is not None and url.setHost(target) is not False: else:
if "postprocess" in service: srv = _pick_random(service["target"])
url = service["postprocess"](url) url = _target_redirect(url, srv)
try: try:
request.redirect(url) request.redirect(url)
except RedirectException as e: except RedirectException as e:
message.error(str(e)) message.error(str(e))
if "postprocess" in service and isinstance(service["postprocess"], Callable):
url = service["postprocess"](url)
def _should_be_redirected(host: str, redirects: dict = redirects) -> dict | None: def _farside_redirect(url: QUrl, service: str) -> QUrl:
try:
url.setHost("farside.link")
url.setPath(f"/{service}{url.path()}")
except RedirectException as e:
message.error(str(e))
return url
def _target_redirect(url: QUrl, target: str) -> QUrl:
if target is not None and url.setHost(target) is not False:
return url
return url
def _pick_random(choices: list) -> Any:
return choices[random.randint(0, len(choices) - 1)]
def _should_be_redirected(
host: str, redirects: dict = redirects
) -> dict[str, list] | None:
for service in redirects.values(): for service in redirects.values():
for source in service["source"]: for source in service["source"]:
if re.search(source, host): if re.search(source, host):