Make more extensive using of dataclasses for typing and simpler future refactors.
168 lines
5.6 KiB
Python
168 lines
5.6 KiB
Python
import random
|
|
import re
|
|
from dataclasses import dataclass, field
|
|
from typing import Callable
|
|
from urllib import parse
|
|
|
|
from qutebrowser.api import interceptor
|
|
from qutebrowser.extensions.interceptors import QUrl, RedirectException
|
|
from qutebrowser.utils import message
|
|
|
|
|
|
def fixScribePath(url: QUrl):
|
|
"""Fix external medium blog to scribe translation.
|
|
Some paths from medium will go through a 'global identity'
|
|
path which messes up the actual url path we want to go
|
|
to and puts it in queries. This puts it back on the path.
|
|
"""
|
|
# double unquoting necessary!
|
|
# I suppose we double-wrap it earlier somewhere?
|
|
# unquoted = parse.unquote(
|
|
# url.path(options=QUrl.ComponentFormattingOption.FullyEncoded)
|
|
# )
|
|
path = parse.unquote(f"{url.path()}{url.query()}", encoding="ascii")
|
|
url.setQuery(None)
|
|
new_path = re.sub(r"m/global-identity-2redirectUrl=", "", path)
|
|
url.setPath(
|
|
parse.quote(new_path),
|
|
mode=QUrl.ParsingMode.StrictMode,
|
|
)
|
|
return url
|
|
|
|
|
|
# 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": 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",
|
|
],
|
|
),
|
|
"goodreads": Service(
|
|
source=["goodreads.com"],
|
|
custom_targets=True,
|
|
target=[
|
|
"biblioreads.eu.org",
|
|
"biblioreads.vercel.app",
|
|
"biblioreads.mooo.com",
|
|
"bl.vern.cc",
|
|
"biblioreads.lunar.icu",
|
|
"read.whateveritworks.org",
|
|
"biblioreads.privacyfucking.rocks",
|
|
"read.seitan-ayoub.lol",
|
|
"read.freedit.eu",
|
|
"biblioreads.ducks.party",
|
|
"biblioreads.snine.nl",
|
|
"biblioreads.privacyredirect.com",
|
|
"reads.nezumi.party",
|
|
"br.bloat.cat",
|
|
"read.canine.tools",
|
|
],
|
|
),
|
|
}
|
|
|
|
|
|
def rewrite(request: interceptor.Request) -> None:
|
|
# if config.get(name="content.oss_redirects") is False:
|
|
# return
|
|
|
|
if (
|
|
request.resource_type != interceptor.ResourceType.main_frame
|
|
or request.request_url.scheme() in {"data", "blob"}
|
|
):
|
|
return
|
|
|
|
url = request.request_url
|
|
|
|
if service := _should_be_redirected(url.host()):
|
|
url = _farside_redirect(url, _pick_random(service.target))
|
|
try:
|
|
request.redirect(url)
|
|
except RedirectException as e:
|
|
message.error(str(e))
|
|
|
|
if service.postprocess:
|
|
url = service.postprocess()
|
|
|
|
|
|
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()}")
|
|
except RedirectException as e:
|
|
message.error(str(e))
|
|
return url
|
|
|
|
|
|
def _pick_random[T](choices: list[T]) -> T:
|
|
return choices[random.randint(0, len(choices) - 1)]
|
|
|
|
|
|
def _should_be_redirected(
|
|
host: str,
|
|
redirects: Redirects = redirects,
|
|
) -> Service | None:
|
|
for service in redirects.values():
|
|
for source in service.source:
|
|
if re.search(source, host):
|
|
return service
|
|
return None
|
|
|
|
|
|
interceptor.register(rewrite)
|