Since farside is apparently also not capable of correctly redirecting to invidious (the one functioning instance), we are doing it manually.
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=["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=["youtube.com"], target=["inv.nadeko.net"]),
|
|
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()
|