Since farside linking currently does not work we take the work into our own hands.
215 lines
6.6 KiB
Python
215 lines
6.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
|
|
|
|
|
|
@dataclass
|
|
class Service:
|
|
source: list[str] = field(default_factory=lambda: [])
|
|
target: list[str] = field(default_factory=lambda: [])
|
|
custom_targets: bool = False
|
|
preprocess: Callable[[QUrl], QUrl] | None = None
|
|
postprocess: Callable[[QUrl], QUrl] | None = None
|
|
|
|
def __contains__(self, item: str):
|
|
for source in self.source:
|
|
if re.search(source, item):
|
|
return True
|
|
return False
|
|
|
|
|
|
def scribe_global_identity(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.
|
|
"""
|
|
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
|
|
|
|
|
|
def breezewiki_host_to_path(url: QUrl):
|
|
host = url.host()
|
|
if wiki := host[0 : host.find(".fandom.com")]:
|
|
url.setPath(f"/{wiki}{url.path()}")
|
|
return url
|
|
|
|
|
|
default_services = [
|
|
Service(source=["youtube.com"], target=["invidious"]),
|
|
Service(source=["stackoverflow.com"], target=["anonymousoverflow"]),
|
|
Service(source=["odysee.com"], target=["librarian"]),
|
|
Service(source=["reddit.com"], target=["redlib"]),
|
|
Service(source=["instagram.com"], target=["proxigram"]),
|
|
Service(source=["twitter.com"], target=["nitter"]),
|
|
Service(source=["imdb.com"], target=["libremdb"]),
|
|
Service(source=["tiktok.com"], target=["proxitok"]),
|
|
Service(source=["imgur.com"], target=["rimgo"]),
|
|
Service(
|
|
source=["medium.com"], target=["scribe"], postprocess=scribe_global_identity
|
|
),
|
|
Service(
|
|
source=["fandom.com"], target=["breezewiki"], preprocess=breezewiki_host_to_path
|
|
),
|
|
Service(source=["quora.com"], target=["quetre"]),
|
|
Service(source=["google.com"], target=["whoogle"]),
|
|
Service(source=["translate.google.com"], target=["lingva", "simplytranslate"]),
|
|
Service(source=["deepl.com"], target=["simplytranslate"]),
|
|
Service(source=["bandcamp.com"], target=["tent"]),
|
|
Service(
|
|
custom_targets=True,
|
|
source=["genius.com"],
|
|
target=[
|
|
"dumb.privacydev.net",
|
|
"dumb.privacydev.net",
|
|
"dm.vern.cc",
|
|
"sing.whatever.social",
|
|
"dumb.nunosempere.com",
|
|
"dumb.lunar.icu",
|
|
"dumb.esmailelbob.xyz",
|
|
],
|
|
),
|
|
Service(
|
|
custom_targets=True,
|
|
source=["pinterest.com"],
|
|
target=[
|
|
"pain.thirtysix.pw",
|
|
"pt.bloat.cat",
|
|
"painterest.gitro.xyz",
|
|
],
|
|
),
|
|
Service(
|
|
custom_targets=True,
|
|
source=["tumblr.com"],
|
|
target=[
|
|
"pb.bloat.cat",
|
|
"tb.opnxng.com",
|
|
"priviblur.pussthecat.org",
|
|
"priviblur.thebunny.zone",
|
|
"priviblur.gitro.xyz",
|
|
"priviblur.canine.tools",
|
|
],
|
|
),
|
|
Service(
|
|
custom_targets=True,
|
|
source=["twitch.com"],
|
|
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",
|
|
"twitch.sudovanilla.org",
|
|
"safetwitch.r4fo.com",
|
|
"safetwitch.ducks.party",
|
|
"safetwitch.privacyredirect.com",
|
|
"st.ngn.tf",
|
|
"safetwitch.darkness.services",
|
|
"safetwitch.adminforge.de",
|
|
],
|
|
),
|
|
Service(
|
|
custom_targets=True,
|
|
source=["goodreads.com"],
|
|
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",
|
|
],
|
|
),
|
|
]
|
|
|
|
|
|
@dataclass
|
|
class Redirects:
|
|
services: list[Service] = field(default_factory=lambda: default_services)
|
|
selector: Callable[[list[str]], str] = lambda c: c[
|
|
random.randint(0, len(c) - 1)
|
|
] # selection algorithm
|
|
farside_service: str = (
|
|
"farside.link" # Contains url for farside-like redirector (e.g. 'fastsi.de')
|
|
)
|
|
|
|
def __post_init__(self):
|
|
interceptor.register(self.intercept)
|
|
|
|
def intercept(self, request: interceptor.Request) -> None:
|
|
# TODO: Implement config check (maybe 'privacy.redirect = False?')
|
|
# 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 url in self:
|
|
try:
|
|
request.redirect(self.get(url))
|
|
except RedirectException as e:
|
|
message.error(str(e))
|
|
|
|
def get(self, url: QUrl) -> QUrl:
|
|
service = self.get_service(url)
|
|
if not service:
|
|
return url
|
|
|
|
foss_host = self.selector(service.target)
|
|
if service.preprocess:
|
|
url = service.preprocess(url)
|
|
|
|
try:
|
|
if service.custom_targets:
|
|
url.setHost(foss_host)
|
|
else:
|
|
url.setHost(self.farside_service)
|
|
url.setPath(f"/{foss_host}{url.path()}")
|
|
except RedirectException as e:
|
|
message.error(str(e))
|
|
|
|
if service.postprocess:
|
|
url = service.postprocess(url)
|
|
return url
|
|
|
|
def get_service(self, url: QUrl) -> Service | None:
|
|
host = url.host()
|
|
for service in self.services:
|
|
if host in service:
|
|
return service
|
|
|
|
def __contains__(self, item: QUrl):
|
|
if self.get_service(item):
|
|
return True
|
|
return False
|
|
|
|
|
|
_ = Redirects()
|