Compare commits
5 commits
c19dbefb2c
...
2ecdb81f62
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ecdb81f62 | |||
| 53f2c49385 | |||
| 77ead6a618 | |||
| 5dfba029d8 | |||
| 6a6dfe3a6e |
6 changed files with 211 additions and 213 deletions
|
|
@ -3,16 +3,16 @@ from typing import cast
|
||||||
|
|
||||||
# pylint: disable=C0111
|
# pylint: disable=C0111
|
||||||
from qutebrowser.config.config import ConfigContainer # noqa: F401
|
from qutebrowser.config.config import ConfigContainer # noqa: F401
|
||||||
from qutebrowser.config.configfiles import ConfigAPI # noqa: F401
|
from qutebrowser.config.configfiles import ConfigAPI
|
||||||
|
|
||||||
config: ConfigAPI = cast(ConfigAPI, config) # noqa: F821 pylint: disable=E0602,C0103
|
config: ConfigAPI = cast(ConfigAPI, config) # noqa: F821 pylint: disable=E0602,C0103
|
||||||
c: ConfigContainer = cast(ConfigContainer, c) # noqa: F821 pylint: disable=E0602,C0103
|
c: ConfigContainer = cast(ConfigContainer, c) # noqa: F821 pylint: disable=E0602,C0103
|
||||||
|
|
||||||
|
|
||||||
# Autogenerated config.py
|
# Autogenerated config.py
|
||||||
# Documentation:
|
# Documentation:
|
||||||
# qute://help/configuring.html
|
# qute://help/configuring.html
|
||||||
# qute://help/settings.html
|
# qute://help/settings.html
|
||||||
|
|
||||||
# load additional settings configured via autoconfig.yml
|
# load additional settings configured via autoconfig.yml
|
||||||
_ = config.load_autoconfig()
|
_ = config.load_autoconfig()
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ config.source("alias.py")
|
||||||
config.source("maps.py")
|
config.source("maps.py")
|
||||||
config.source("content.py")
|
config.source("content.py")
|
||||||
config.source("searchengines.py")
|
config.source("searchengines.py")
|
||||||
config.source("redirects.py")
|
config.source("fossredirect.py")
|
||||||
|
|
||||||
# Tab-Bar
|
# Tab-Bar
|
||||||
# have tab bar on the right, not on the top
|
# have tab bar on the right, not on the top
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ js_whitelist = [
|
||||||
"*://news.ycombinator.com/*",
|
"*://news.ycombinator.com/*",
|
||||||
"*://old.reddit.com/*",
|
"*://old.reddit.com/*",
|
||||||
"*://translate.google.com/*",
|
"*://translate.google.com/*",
|
||||||
|
"*://hub.docker.com/*",
|
||||||
"chrome://*/*",
|
"chrome://*/*",
|
||||||
"file://*",
|
"file://*",
|
||||||
"qute://*/*",
|
"qute://*/*",
|
||||||
|
|
|
||||||
203
qutebrowser/config/fossredirect.py
Normal file
203
qutebrowser/config/fossredirect.py
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
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=["genius.com"], target=["dumb"]),
|
||||||
|
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=["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()
|
||||||
|
|
@ -1,207 +0,0 @@
|
||||||
import random
|
|
||||||
import re
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
type Service = dict[str, list[str]]
|
|
||||||
type Redirects = dict[str, Service]
|
|
||||||
|
|
||||||
|
|
||||||
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",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"biblioreads": {
|
|
||||||
"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",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"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",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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["farside" if "farside" in service else "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)
|
|
||||||
|
|
||||||
|
|
||||||
def _farside_redirect(url: QUrl, service: str, use_fastside: bool = True) -> 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(
|
|
||||||
# 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"]:
|
|
||||||
if re.search(source, host):
|
|
||||||
return service
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
interceptor.register(rewrite)
|
|
||||||
|
|
@ -9,7 +9,7 @@ key = "73BA40D5AFAF49C9"
|
||||||
[git]
|
[git]
|
||||||
sign-on-push = true
|
sign-on-push = true
|
||||||
subprocess = true
|
subprocess = true
|
||||||
private-commits = "description(glob:'wip:*')" # refuse to push WIP commits
|
private-commits = "description(glob:'wip:*') | description(glob:'private:*')" # refuse to push WIP commits
|
||||||
|
|
||||||
[ui]
|
[ui]
|
||||||
diff-editor = ["nvim", "-c", "DiffEditor $left $right $output"]
|
diff-editor = ["nvim", "-c", "DiffEditor $left $right $output"]
|
||||||
|
|
@ -32,7 +32,7 @@ concat(
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[revsets]
|
[revsets]
|
||||||
log = "@ | ancestors(trunk()..(visible_heads() & mine()), 2) | trunk()"
|
log = "ancestors(@, 5) | ancestors(trunk()..(visible_heads() & mine()), 2) | trunk()"
|
||||||
|
|
||||||
[revset-aliases]
|
[revset-aliases]
|
||||||
"bases" = "dev"
|
"bases" = "dev"
|
||||||
|
|
|
||||||
|
|
@ -62,5 +62,6 @@ alias jb="jj log -r 'ancestors(heads(all()), 3)'"
|
||||||
|
|
||||||
alias jrb="jj rebase"
|
alias jrb="jj rebase"
|
||||||
|
|
||||||
|
# remote work
|
||||||
|
alias jrv="jj git remote list"
|
||||||
alias jp="jj git push"
|
alias jp="jj git push"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue