qutebrowser: Refactor redirects plugin

Make more extensive using of dataclasses for typing and simpler future
refactors.
This commit is contained in:
Marty Oehme 2025-02-14 19:43:41 +01:00
parent 5dfba029d8
commit 77ead6a618
Signed by: Marty
GPG key ID: EDBF2ED917B2EF6A

View file

@ -1,5 +1,6 @@
import random import random
import re import re
from dataclasses import dataclass, field
from typing import Callable from typing import Callable
from urllib import parse from urllib import parse
@ -29,93 +30,74 @@ def fixScribePath(url: QUrl):
return url return url
type Service = dict[str, list[str]] # TODO: Once implemented, delete
# type Service = dict[str, list[str]]
type Redirects = dict[str, Service] type Redirects = dict[str, Service]
@dataclass
class Service:
source: list[str] = field(default_factory=lambda: [])
target: list[str] = field(default_factory=lambda: [])
custom_targets: bool = False
postprocess: Callable[[], str] | None = None
# T = TypeVar("T")
# @dataclass
# class Redirects:
# services: list[Service]
# selector: Callable[[list[str]], str] = lambda c: c[random.randint(0, len(c) - 1)] #TODO: should implement the pick random sel algo from below
# farside_service: str = "farside.link" # "fastsi.de" # TODO: should contain the url for the farside redirector used
redirects: Redirects = { redirects: Redirects = {
"youtube": { "youtube": Service(source=["youtube.com"], target=["invidious"]),
"source": ["youtube.com"], "stackoverflow": Service(
"farside": ["invidious"], source=["stackoverflow.com"], target=["anonymousoverflow"]
}, ),
"stackoverflow": { "lbry": Service(source=["odysee.com"], target=["librarian"]),
"source": ["stackoverflow.com", "askubuntu.com"], "reddit": Service(source=["reddit.com"], target=["redlib"]),
"farside": ["anonymousoverflow"], "instagram": Service(source=["instagram.com"], target=["proxigram"]),
}, "twitter": Service(source=["twitter.com"], target=["nitter"]),
"lbry": { "imdb": Service(source=["imdb.com"], target=["libremdb"]),
"source": ["odysee.com"], "translate": Service(source=["translate.google.com"], target=["lingva"]),
"farside": ["librarian"], "tiktok": Service(source=["tiktok.com"], target=["proxitok"]),
}, "imgur": Service(source=["imgur.com"], target=["rimgo"]),
"reddit": { "medium": Service(
"source": ["reddit.com"], source=["medium.com"], target=["scribe"], postprocess=fixScribePath
"farside": ["redlib"], ),
}, "fandom": Service(source=["fandom.com"], target=["breezewiki"]),
"instagram": { "quora": Service(source=["quora.com"], target=["quetre"]),
"source": ["instagram.com"], "google": Service(source=["google.com"], target=["whoogle"]),
"farside": ["proxigram"], "twitch": Service(
}, source=["twitch.com"],
"twitter": { custom_targets=True,
"source": ["twitter.com"], target=[
"farside": ["nitter"], "https://safetwitch.drgns.space/",
}, "https://safetwitch.projectsegfau.lt/",
"imdb": { "https://stream.whateveritworks.org",
"source": ["imdb.com"], "https://safetwitch.datura.network",
"farside": ["libremdb"], "https://ttv.vern.cc",
}, "https://safetwitch.frontendfriendly.xyz/",
"translate": { "https://ttv.femboy.band",
"source": ["translate.google.com"], "https://twitch.seitan-ayoub.lol",
"farside": ["lingva"], "https://www.ggtyler.dev/other/frontends",
}, "https://lunar.icu",
"tiktok": { "https://twitch.sudovanilla.org",
"source": ["tiktok.com"], "https://safetwitch.r4fo.com",
"farside": ["proxitok"], "https://safetwitch.ducks.party",
}, "https://nogafam.fr",
"imgur": { "https://safetwitch.privacyredirect.com/",
"source": ["imgur.com"], "https://st.ngn.tf/",
"farside": ["rimgo"], "https://safetwitch.darkness.services",
}, "https://4o1x5.dev/privacy-policy/",
"medium": { "https://safetwitch.adminforge.de",
"source": ["medium.com"],
"farside": ["scribe"],
# "postprocess": fixScribePath
},
"fandom": {
"source": ["fandom.com"],
"farside": ["breezewiki"],
},
"quora": {
"source": ["quora.com"],
"farside": ["quetre"],
# "postprocess": lambda url: message.info(f"CALLING QUORA WITH {url}")
},
"google": {
"source": ["google.com"],
"target": [
"search.albony.xyz",
"search.garudalinux.org",
"search.dr460nf1r3.org",
"s.tokhmi.xyz",
"search.sethforprivacy.com",
"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",
], ],
}, ),
"biblioreads": { "goodreads": Service(
"source": ["goodreads.com"], source=["goodreads.com"],
"target": [ custom_targets=True,
target=[
"biblioreads.eu.org", "biblioreads.eu.org",
"biblioreads.vercel.app", "biblioreads.vercel.app",
"biblioreads.mooo.com", "biblioreads.mooo.com",
@ -128,29 +110,11 @@ redirects: Redirects = {
"biblioreads.ducks.party", "biblioreads.ducks.party",
"biblioreads.snine.nl", "biblioreads.snine.nl",
"biblioreads.privacyredirect.com", "biblioreads.privacyredirect.com",
"reads.nezumi.party",
"br.bloat.cat",
"read.canine.tools",
], ],
}, ),
"safetwitch": {
"source": ["twitch.tv"],
"target": [
"safetwitch.drgns.space",
"safetwitch.projectsegfau.lt",
"stream.whateveritworks.org",
"safetwitch.datura.network",
"ttv.vern.cc",
"safetwitch.frontendfriendly.xyz",
"ttv.femboy.band",
"twitch.seitan-ayoub.lol",
"st.ggtyler.dev",
"safetwitch.lunar.icu",
"twitch.sudovanilla.com",
"safetwitch.r4fo.com",
"safetwitch.ducks.party",
"safetwitch.nogafam.fr",
"safetwitch.privacyredirect.com",
"st.ngn.tf",
],
},
} }
@ -167,19 +131,17 @@ 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()):
url = _farside_redirect( url = _farside_redirect(url, _pick_random(service.target))
url, _pick_random(service["farside" if "farside" in service else "target"])
)
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): if service.postprocess:
url = service["postprocess"](url) url = service.postprocess()
def _farside_redirect(url: QUrl, service: str, use_fastside: bool = True) -> QUrl: def _farside_redirect(url: QUrl, service: str, use_fastside: bool = False) -> QUrl:
try: try:
url.setHost("fastside.link" if use_fastside else "farside.link") url.setHost("fastside.link" if use_fastside else "farside.link")
url.setPath(f"/{service}{url.path()}") url.setPath(f"/{service}{url.path()}")
@ -193,12 +155,11 @@ def _pick_random[T](choices: list[T]) -> T:
def _should_be_redirected( def _should_be_redirected(
# TODO: Update to use typedefs/classes instead of this jumble
host: str, host: str,
redirects: Redirects = redirects, redirects: Redirects = redirects,
) -> Service | None: ) -> Service | 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):
return service return service
return None return None