qutebrowser: Init
This also makes it the default browser.
This commit is contained in:
parent
58e6cad052
commit
821367af3f
|
@ -14,6 +14,7 @@
|
|||
./neovim
|
||||
./pass.nix
|
||||
./programs.nix
|
||||
./qutebrowser
|
||||
./scripts
|
||||
./sway
|
||||
./tmate.nix
|
||||
|
|
|
@ -143,7 +143,7 @@ in
|
|||
] ++ lib.optionals nixosConfig.sbruder.gui.enable [
|
||||
# communication
|
||||
claws-mail # email client that looks ugly but just works
|
||||
firefox-esr # the least bad browser
|
||||
firefox-esr # a bad browser
|
||||
((mumble.override { pulseSupport = true; }).overrideAttrs (o: o // {
|
||||
patches = o.patches ++ [
|
||||
# TODO: remove patch once stable release supports this
|
||||
|
|
308
users/simon/modules/qutebrowser/default.nix
Normal file
308
users/simon/modules/qutebrowser/default.nix
Normal file
|
@ -0,0 +1,308 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
inherit ((import ../common.nix).colorschemes) solarized;
|
||||
|
||||
setOptionForeachPattern = option: value: patterns:
|
||||
let
|
||||
formatValue = value:
|
||||
if lib.isBool value
|
||||
then (if value then "True" else "False")
|
||||
else
|
||||
(if lib.isString value
|
||||
then "r\"${value}\""
|
||||
else (toString value));
|
||||
in
|
||||
lib.concatMapStringsSep
|
||||
"\n"
|
||||
(pattern: "config.set(\"${option}\", ${formatValue value}, \"${pattern}\")")
|
||||
patterns;
|
||||
|
||||
permissionVideo = [
|
||||
"https://chat.sbruder.de"
|
||||
"https://meet.jalr.de"
|
||||
];
|
||||
permissionAudio = [
|
||||
] ++ permissionVideo; # capturing video almost always also requires capturing audio
|
||||
permissionNotifications = [
|
||||
"https://chat.sbruder.de"
|
||||
"https://teams.microsoft.com"
|
||||
];
|
||||
|
||||
cookieExceptions = [
|
||||
# Microsoft Teams
|
||||
# https://docs.microsoft.com/en-us/microsoftteams/troubleshoot/teams-sign-in/sign-in-loop#resolution
|
||||
# TODO: remove when I don’t have to use this garbage any more
|
||||
"https://microsoft.com"
|
||||
"https://microsoftonline.com"
|
||||
"https://teams.skype.com"
|
||||
"https://teams.microsoft.com"
|
||||
"https://sfbassets.com"
|
||||
"https://skypeforbusiness.com"
|
||||
];
|
||||
in
|
||||
{
|
||||
programs.qutebrowser = {
|
||||
enable = true;
|
||||
aliases = {
|
||||
q = "tab-close"; # one tab
|
||||
qa = "close"; # one window
|
||||
"qa!" = "quit"; # everything
|
||||
};
|
||||
keyBindings = {
|
||||
normal = {
|
||||
",rm" = "spawn -u readability";
|
||||
|
||||
# reasonable tab cycling
|
||||
J = "tab-prev";
|
||||
K = "tab-next";
|
||||
gJ = "tab-move -";
|
||||
gK = "tab-move +";
|
||||
|
||||
# mpv
|
||||
",mv" = "spawn mpv --profile=clear-speed {url}";
|
||||
",ma" = "spawn mpv --player-operation-mode=pseudo-gui --ytdl-format=251/bestaudio/best {url}";
|
||||
",mq" = "spawn umpv {url}";
|
||||
",Mv" = "hint links spawn mpv --profile=clear-speed {hint-url}";
|
||||
",Ma" = "hint links spawn mpv --player-operation-mode=pseudo-gui --ytdl-format=251/bestaudio/best {hint-url}";
|
||||
",Mq" = "hint links spawn umpv {hint-url}";
|
||||
};
|
||||
};
|
||||
searchEngines = {
|
||||
DEFAULT = "https://bangs.sbruder.de/eval?engine=https://duckduckgo.com/?q=%25s&query={}";
|
||||
};
|
||||
settings = {
|
||||
colors =
|
||||
let
|
||||
fgbg = fg: bg: { inherit fg bg; };
|
||||
topbottom = colour: { top = colour; bottom = colour; };
|
||||
in
|
||||
with solarized; {
|
||||
completion = rec {
|
||||
fg = base1;
|
||||
odd.bg = base02;
|
||||
even.bg = base03;
|
||||
match.fg = green;
|
||||
scrollbar = fgbg base1 base03;
|
||||
category = {
|
||||
inherit (fgbg yellow base03) fg bg;
|
||||
border = topbottom base03;
|
||||
};
|
||||
item.selected = {
|
||||
inherit (fgbg base1 base01) fg bg;
|
||||
border = topbottom base01;
|
||||
inherit match;
|
||||
};
|
||||
};
|
||||
contextmenu = {
|
||||
disabled = fgbg base0 base02;
|
||||
menu = fgbg base1 base03;
|
||||
selected = fgbg base1 base01;
|
||||
};
|
||||
downloads = {
|
||||
bar.bg = base03;
|
||||
start = fgbg base03 blue;
|
||||
stop = fgbg base03 cyan;
|
||||
error.fg = red;
|
||||
};
|
||||
hints = {
|
||||
inherit (fgbg base03 yellow) fg bg;
|
||||
match.fg = base1;
|
||||
};
|
||||
keyhint = {
|
||||
inherit (fgbg base1 base03) fg bg;
|
||||
suffix.fg = base1;
|
||||
};
|
||||
messages = {
|
||||
error = {
|
||||
inherit (fgbg base03 red) fg bg;
|
||||
border = red;
|
||||
};
|
||||
warning = {
|
||||
inherit (fgbg base03 violet) fg bg;
|
||||
border = violet;
|
||||
};
|
||||
info = {
|
||||
inherit (fgbg base1 base03) fg bg;
|
||||
border = base03;
|
||||
};
|
||||
};
|
||||
prompts = {
|
||||
inherit (fgbg base1 base03) fg bg;
|
||||
border = base03;
|
||||
selected = fgbg base1 base01;
|
||||
};
|
||||
statusbar = {
|
||||
normal = fgbg green base03;
|
||||
insert = fgbg base03 blue;
|
||||
passthrough = fgbg base03 cyan;
|
||||
private = fgbg base03 base02;
|
||||
command = {
|
||||
inherit (fgbg base1 base03) fg bg;
|
||||
private = fgbg base1 base03;
|
||||
};
|
||||
caret = {
|
||||
inherit (fgbg base03 violet) fg bg;
|
||||
selection = fgbg base03 blue;
|
||||
};
|
||||
progress.bg = blue;
|
||||
url.fg = base1;
|
||||
url.error.fg = red;
|
||||
url.hover.fg = base1;
|
||||
url.success.http.fg = cyan;
|
||||
url.success.https.fg = green;
|
||||
url.warn.fg = violet;
|
||||
};
|
||||
|
||||
tabs = rec {
|
||||
bar.bg = base03;
|
||||
even = fgbg base1 base03;
|
||||
odd = even;
|
||||
indicator = {
|
||||
start = blue;
|
||||
stop = cyan;
|
||||
error = red;
|
||||
};
|
||||
selected = rec {
|
||||
even = fgbg base02 green;
|
||||
odd = even;
|
||||
};
|
||||
pinned = {
|
||||
inherit even odd selected;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# UI
|
||||
scrolling.smooth = true;
|
||||
completion.web_history.max_items = 0; # no history
|
||||
|
||||
# Fonts
|
||||
fonts = {
|
||||
web = {
|
||||
family = rec {
|
||||
serif = "Georgia";
|
||||
sans_serif = "PT Sans";
|
||||
standard = sans_serif;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Behaviour
|
||||
auto_save.session = true;
|
||||
session.lazy_restore = true;
|
||||
content.autoplay = false;
|
||||
downloads.location.directory = "/tmp";
|
||||
editor.command = [ "alacritty" "-e" "nvim" "-f" "{file}" "-c" "normal {line}G{column0}l" ];
|
||||
spellcheck.languages = [ "de-DE" "en-GB" ];
|
||||
url.default_page = "about:blank";
|
||||
url.start_pages = [ "about:blank" ];
|
||||
|
||||
# Privacy
|
||||
content.cookies.accept = "no-3rdparty";
|
||||
content.headers.user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0";
|
||||
content.headers.accept_language = "en-US,en;q=0.5";
|
||||
|
||||
# Filtering (many don’t get used yet due to lack of cosmetic filtering)
|
||||
# https://github.com/gorhill/uBlock/blob/master/assets/assets.json
|
||||
content.blocking.adblock.lists = [
|
||||
"https://easylist.to/easylist/easylist.txt"
|
||||
"https://easylist.to/easylist/easyprivacy.txt"
|
||||
"https://easylist.to/easylist/fanboy-social.txt"
|
||||
"https://easylist.to/easylistgermany/easylistgermany.txt"
|
||||
"https://filters.adtidy.org/extension/ublock/filters/17.txt"
|
||||
"https://filters.adtidy.org/extension/ublock/filters/3.txt"
|
||||
"https://filters.adtidy.org/extension/ublock/filters/4.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/annoyances.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/badlists.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/badware.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/privacy.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/resource-abuse.txt"
|
||||
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/unbreak.txt"
|
||||
"https://secure.fanboy.co.nz/fanboy-annoyance.txt"
|
||||
"https://secure.fanboy.co.nz/fanboy-antifacebook.txt"
|
||||
"https://secure.fanboy.co.nz/fanboy-cookiemonster.txt"
|
||||
];
|
||||
};
|
||||
extraConfig = /* python */ ''
|
||||
import glob
|
||||
|
||||
c.content.user_stylesheets = glob.glob("${config.xdg.configHome}/qutebrowser/userstyles/*.css")
|
||||
|
||||
c.qt.environ = {
|
||||
# otherwise results in severe banding (https://github.com/qutebrowser/qutebrowser/issues/5528)
|
||||
"QT_WAYLAND_DISABLE_WINDOWDECORATION": "0",
|
||||
}
|
||||
|
||||
c.content.headers.custom = {
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
||||
}
|
||||
|
||||
c.tabs.padding["top"] = 3
|
||||
c.tabs.padding["bottom"] = 3
|
||||
|
||||
# Permissions
|
||||
${setOptionForeachPattern "content.media.audio_capture" true permissionAudio}
|
||||
${setOptionForeachPattern "content.media.audio_video_capture" true permissionVideo}
|
||||
${setOptionForeachPattern "content.media.video_capture" true permissionVideo}
|
||||
${setOptionForeachPattern "content.notifications.enabled" true permissionNotifications}
|
||||
|
||||
# Cookie exceptions
|
||||
${setOptionForeachPattern "content.cookies.accept" "all" cookieExceptions}
|
||||
'';
|
||||
};
|
||||
|
||||
xdg.configFile =
|
||||
let
|
||||
replaceExtension = newExtension: filename: "${lib.concatStringsSep "." (lib.init (lib.splitString "." filename))}.${newExtension}";
|
||||
|
||||
regularFilesIn = dir: lib.filterAttrs
|
||||
(_: v: v == "regular")
|
||||
(builtins.readDir (./. + "/${dir}"));
|
||||
|
||||
compileScss = name: file: pkgs.runCommand (replaceExtension "css" name) { } ''
|
||||
${pkgs.sassc}/bin/sassc ${file} $out
|
||||
'';
|
||||
in
|
||||
{
|
||||
"qutebrowser/bookmarks/urls".source = config.lib.file.mkOutOfStoreSymlink "${config.xdg.dataHome}/qutebrowser/synced-bookmarks/bookmarks";
|
||||
"qutebrowser/quickmarks".source = config.lib.file.mkOutOfStoreSymlink "${config.xdg.dataHome}/qutebrowser/synced-bookmarks/quickmarks";
|
||||
} // (lib.mapAttrs'
|
||||
(k: _: lib.nameValuePair "qutebrowser/greasemonkey/${k}" { source = ./userscripts + "/${k}"; })
|
||||
(regularFilesIn "userscripts")) // (lib.mapAttrs'
|
||||
(k: _: lib.nameValuePair "qutebrowser/userstyles/${replaceExtension "css" k}" { source = compileScss k (./userstyles + "/${k}"); })
|
||||
(regularFilesIn "userstyles"));
|
||||
|
||||
xdg.dataFile = lib.mapAttrs'
|
||||
(dict: sha256: lib.nameValuePair
|
||||
"qutebrowser/qtwebengine_dictionaries/${dict}.bdic"
|
||||
{
|
||||
source = (pkgs.fetchurl {
|
||||
url = "https://chromium.googlesource.com/chromium/deps/hunspell_dictionaries/+/18e09b9197a3b1d771c077c530d1a4ebad04c167/${dict}.bdic?format=TEXT";
|
||||
inherit sha256;
|
||||
postFetch = ''
|
||||
base64 -d "$out" > "$TMPDIR/decoded"
|
||||
mv "$TMPDIR/decoded" "$out"
|
||||
'';
|
||||
});
|
||||
})
|
||||
{
|
||||
"de-DE-3-0" = "sha256-B2pHBwDb0Kpiu4s9JMNOE0C9/oPLvPwDXOly8jwUBAA=";
|
||||
"en-GB-9-0" = "sha256-c8eaQQ+AkgwpsFX3upB9k0A7BajBfQDo5wVO22L3Maw=";
|
||||
};
|
||||
|
||||
home.packages = [
|
||||
(pkgs.writeShellScriptBin "qbmarks" /* bash */ ''
|
||||
set -euo pipefail
|
||||
|
||||
git() {
|
||||
echo "[$] git $@"
|
||||
command git -C "${config.xdg.dataHome}/qutebrowser/synced-bookmarks" "$@"
|
||||
}
|
||||
|
||||
git commit --no-gpg-sign -a -m "Sync on $(hostname)" || true
|
||||
git pull --rebase
|
||||
git push
|
||||
'')
|
||||
];
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// ==UserScript==
|
||||
// @name Bandcamp: Add volume slider
|
||||
// @include https://*.bandcamp.com/*
|
||||
// @include https://sewerslvt.com/*
|
||||
// @include https://store.sigurros.com/*
|
||||
// ==/UserScript==
|
||||
function setVolume(volume) {
|
||||
document.querySelectorAll("audio").forEach(el => el.volume = volume / 100)
|
||||
localStorage.setItem("volume", volume)
|
||||
}
|
||||
|
||||
function loadStoredVolume() {
|
||||
return localStorage.getItem("volume") ? Number(localStorage.getItem("volume")) : 25
|
||||
}
|
||||
|
||||
const volumeControlContainer = document.createElement("div")
|
||||
volumeControlContainer.style.position = "fixed"
|
||||
volumeControlContainer.style.top = 0
|
||||
volumeControlContainer.style.left = 0
|
||||
volumeControlContainer.style["z-index"] = 10000
|
||||
const volumeControlSlider = document.createElement("input")
|
||||
volumeControlSlider.type = "range"
|
||||
volumeControlSlider.min = 0
|
||||
volumeControlSlider.max = 100
|
||||
volumeControlSlider.value = loadStoredVolume()
|
||||
volumeControlSlider.addEventListener("input", e => {setVolume(e.target.value)})
|
||||
volumeControlContainer.appendChild(volumeControlSlider)
|
||||
document.body.appendChild(volumeControlContainer)
|
||||
|
||||
setInterval(() => {setVolume(loadStoredVolume())}, 1000)
|
|
@ -0,0 +1,56 @@
|
|||
// ==UserScript==
|
||||
// @name nginx: Better directory index
|
||||
// @include http://localhost:8888/torrent/download/*
|
||||
// @include https://ci.sbruder.de/nix-store/*
|
||||
// ==/UserScript==
|
||||
|
||||
// https://stackoverflow.com/a/14919494
|
||||
function humanFileSize(bytes) {
|
||||
const thresh = 1024
|
||||
if(Math.abs(bytes) < thresh) {
|
||||
return bytes + ' B'
|
||||
}
|
||||
const units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']
|
||||
var u = -1;
|
||||
do {
|
||||
bytes /= thresh;
|
||||
++u;
|
||||
} while(Math.abs(bytes) >= thresh && u < units.length - 1);
|
||||
return bytes.toFixed(1)+' '+units[u]
|
||||
}
|
||||
|
||||
|
||||
function textToA(line) {
|
||||
let outerElement = document.createElement('div')
|
||||
outerElement.innerHTML = line
|
||||
return outerElement.getElementsByTagName('a')[0]
|
||||
}
|
||||
|
||||
function parseLine(line) {
|
||||
const href = textToA(line).href
|
||||
const filename = href.substr(-1) === '/' ? decodeURIComponent(href.split('/').slice(-2, -1)[0]) : decodeURIComponent(href.split('/').pop())
|
||||
const size = line.split(' ').pop()
|
||||
return {
|
||||
href: href,
|
||||
filename: filename,
|
||||
size: size
|
||||
}
|
||||
}
|
||||
|
||||
function processLine(line) {
|
||||
meta = parseLine(line)
|
||||
if (meta.filename.endsWith('.aria2') || meta.filename.endsWith('.torrent') || meta.filename === 'dht.dat' || meta.filename === 'torrents' || meta.filename === 'torrents.old' || meta.filename === 'history.csv') {
|
||||
return ''
|
||||
}
|
||||
return `<tr><td><a href="${meta.href}">${meta.filename}</a></td><td>${meta.size === '-' ? '-' : humanFileSize(meta.size)}</td></tr>`
|
||||
}
|
||||
|
||||
const collator = new Intl.Collator('kn', {numeric: true})
|
||||
|
||||
document.querySelector('pre').outerHTML = '<table style="font-family: monospace;"><tr><td><a href="../">../</a></td><td>-</td></tr>' + document.querySelector('pre').innerHTML
|
||||
.split('\n')
|
||||
.filter(line => line !== '')
|
||||
.filter(line => line !== '<a href="../">../</a>')
|
||||
.map(processLine)
|
||||
.sort(collator.compare)
|
||||
.join('\n') + '</table>'
|
|
@ -0,0 +1,9 @@
|
|||
// ==UserScript==
|
||||
// @name Invidious Redirect
|
||||
// @include http://www.youtube.com/*
|
||||
// @include https://www.youtube.com/*
|
||||
// @run-at document-start
|
||||
// ==/UserScript==
|
||||
|
||||
document.close();
|
||||
window.location.replace(window.location.href.replace(/www\.youtube\.com/, "iv.sbruder.xyz").replace("/shorts/", "/watch?v="))
|
|
@ -0,0 +1,9 @@
|
|||
// ==UserScript==
|
||||
// @name Libreddit Redirect
|
||||
// @include https://www.reddit.com/*
|
||||
// @include https://old.reddit.com/*
|
||||
// @run-at document-start
|
||||
// ==/UserScript==
|
||||
|
||||
document.close();
|
||||
window.location.replace(window.location.href.replace(/(old|www)?\.reddit\.com/, "libreddit.sbruder.xyz"))
|
|
@ -0,0 +1,8 @@
|
|||
// ==UserScript==
|
||||
// @name Nitter Redirect
|
||||
// @include https://twitter.com/*
|
||||
// @run-at document-start
|
||||
// ==/UserScript==
|
||||
|
||||
document.close();
|
||||
window.location.replace(window.location.href.replace(/twitter\.com/, "nitter.sbruder.xyz"))
|
|
@ -0,0 +1,16 @@
|
|||
// ==UserScript==
|
||||
// @name Per-Domain Userstyles
|
||||
// @include *
|
||||
// @run-at document-start
|
||||
// @author Original by Olmo Kramer
|
||||
// ==/UserScript==
|
||||
|
||||
(() => {
|
||||
document.addEventListener("readystatechange", () => {
|
||||
if (document.readyState == "interactive") {
|
||||
const doc = document.documentElement
|
||||
doc.setAttribute("data-qb-url", window.location.href)
|
||||
doc.setAttribute("data-qb-domain", window.location.host)
|
||||
}
|
||||
})
|
||||
})()
|
|
@ -0,0 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name Es heißt TEAMS
|
||||
// @include https://teams.microsoft.com/*
|
||||
// ==/UserScript==
|
||||
|
||||
// pfusch
|
||||
setInterval(() => {Array.from(document.querySelectorAll(".teams-title")).map(el => {el.innerHTML = "TEAMS"; el.style='font-family: "Comic Sans MS";'})}, 10000)
|
6
users/simon/modules/qutebrowser/userstyles/AriaNg.scss
Normal file
6
users/simon/modules/qutebrowser/userstyles/AriaNg.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
[data-qb-domain="torrent.sbruder.de"],
|
||||
[data-qb-url^="http://localhost:8888/torrent/"] {
|
||||
body {
|
||||
user-select: unset !important;
|
||||
}
|
||||
}
|
22
users/simon/modules/qutebrowser/userstyles/monospace.scss
Normal file
22
users/simon/modules/qutebrowser/userstyles/monospace.scss
Normal file
|
@ -0,0 +1,22 @@
|
|||
[data-qb-domain="pad.sbruder.de"] .CodeMirror {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
[data-qb-domain="github.com"] {
|
||||
code,
|
||||
pre,
|
||||
tt,
|
||||
.blob-code-inner,
|
||||
.text-mono {
|
||||
font-family: monospace !important;
|
||||
}
|
||||
}
|
||||
|
||||
[data-qb-domain="git.sbruder.de"] {
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace !important;
|
||||
}
|
||||
}
|
|
@ -167,6 +167,7 @@ in
|
|||
assigns = {
|
||||
"2" = [
|
||||
{ app_id = "firefox"; }
|
||||
{ app_id = "org.qutebrowser.qutebrowser"; }
|
||||
#{ class="Chromium"; }
|
||||
];
|
||||
"3" = [
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
enable = nixosConfig.sbruder.gui.enable;
|
||||
defaultApplications =
|
||||
let
|
||||
browser = "firefox.desktop";
|
||||
browser = "org.qutebrowser.qutebrowser.desktop";
|
||||
in
|
||||
{
|
||||
"application/pdf" = "org.pwmt.zathura.desktop";
|
||||
|
|
Loading…
Reference in a new issue