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 re
from dataclasses import dataclass, field
from typing import Callable
from urllib import parse
@ -29,93 +30,74 @@ def fixScribePath(url: QUrl):
return url
type Service = dict[str, list[str]]
# TODO: Once implemented, delete
# type Service = dict[str, list[str]]
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 = {
"youtube": {
"source": ["youtube.com"],
"farside": ["invidious"],
},
"stackoverflow": {
"source": ["stackoverflow.com", "askubuntu.com"],
"farside": ["anonymousoverflow"],
},
"lbry": {
"source": ["odysee.com"],
"farside": ["librarian"],
},
"reddit": {
"source": ["reddit.com"],
"farside": ["redlib"],
},
"instagram": {
"source": ["instagram.com"],
"farside": ["proxigram"],
},
"twitter": {
"source": ["twitter.com"],
"farside": ["nitter"],
},
"imdb": {
"source": ["imdb.com"],
"farside": ["libremdb"],
},
"translate": {
"source": ["translate.google.com"],
"farside": ["lingva"],
},
"tiktok": {
"source": ["tiktok.com"],
"farside": ["proxitok"],
},
"imgur": {
"source": ["imgur.com"],
"farside": ["rimgo"],
},
"medium": {
"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",
"youtube": Service(source=["youtube.com"], target=["invidious"]),
"stackoverflow": Service(
source=["stackoverflow.com"], target=["anonymousoverflow"]
),
"lbry": Service(source=["odysee.com"], target=["librarian"]),
"reddit": Service(source=["reddit.com"], target=["redlib"]),
"instagram": Service(source=["instagram.com"], target=["proxigram"]),
"twitter": Service(source=["twitter.com"], target=["nitter"]),
"imdb": Service(source=["imdb.com"], target=["libremdb"]),
"translate": Service(source=["translate.google.com"], target=["lingva"]),
"tiktok": Service(source=["tiktok.com"], target=["proxitok"]),
"imgur": Service(source=["imgur.com"], target=["rimgo"]),
"medium": Service(
source=["medium.com"], target=["scribe"], postprocess=fixScribePath
),
"fandom": Service(source=["fandom.com"], target=["breezewiki"]),
"quora": Service(source=["quora.com"], target=["quetre"]),
"google": Service(source=["google.com"], target=["whoogle"]),
"twitch": Service(
source=["twitch.com"],
custom_targets=True,
target=[
"https://safetwitch.drgns.space/",
"https://safetwitch.projectsegfau.lt/",
"https://stream.whateveritworks.org",
"https://safetwitch.datura.network",
"https://ttv.vern.cc",
"https://safetwitch.frontendfriendly.xyz/",
"https://ttv.femboy.band",
"https://twitch.seitan-ayoub.lol",
"https://www.ggtyler.dev/other/frontends",
"https://lunar.icu",
"https://twitch.sudovanilla.org",
"https://safetwitch.r4fo.com",
"https://safetwitch.ducks.party",
"https://nogafam.fr",
"https://safetwitch.privacyredirect.com/",
"https://st.ngn.tf/",
"https://safetwitch.darkness.services",
"https://4o1x5.dev/privacy-policy/",
"https://safetwitch.adminforge.de",
],
},
"biblioreads": {
"source": ["goodreads.com"],
"target": [
),
"goodreads": Service(
source=["goodreads.com"],
custom_targets=True,
target=[
"biblioreads.eu.org",
"biblioreads.vercel.app",
"biblioreads.mooo.com",
@ -128,29 +110,11 @@ redirects: Redirects = {
"biblioreads.ducks.party",
"biblioreads.snine.nl",
"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
if service := _should_be_redirected(url.host()):
url = _farside_redirect(
url, _pick_random(service["farside" if "farside" in service else "target"])
)
url = _farside_redirect(url, _pick_random(service.target))
try:
request.redirect(url)
except RedirectException as e:
message.error(str(e))
if "postprocess" in service and isinstance(service["postprocess"], Callable):
url = service["postprocess"](url)
if service.postprocess:
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:
url.setHost("fastside.link" if use_fastside else "farside.link")
url.setPath(f"/{service}{url.path()}")
@ -193,12 +155,11 @@ def _pick_random[T](choices: list[T]) -> T:
def _should_be_redirected(
# TODO: Update to use typedefs/classes instead of this jumble
host: str,
redirects: Redirects = redirects,
) -> Service | None:
for service in redirects.values():
for source in service["source"]:
for source in service.source:
if re.search(source, host):
return service
return None