From 9e24c44c5339e1df78a89015d169ee3ae6dc85fa Mon Sep 17 00:00:00 2001
From: Hadi <112569860+anotherhadi@users.noreply.github.com>
Date: Sat, 18 Apr 2026 00:44:22 +0200
Subject: [PATCH] A lot of QOL changement, remove Zen, config Qutebrowser,
update a lot of things
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
---
flake.lock | 70 +-
flake.nix | 24 +-
home/programs/brave/default.nix | 30 -
home/programs/fetch/default.nix | 367 ------
home/programs/ghostty/default.nix | 5 +
home/programs/group/basic-apps.nix | 21 +
home/programs/group/cybersecurity.nix | 5 +-
home/programs/group/dev.nix | 31 +-
home/programs/group/misc.nix | 4 +-
home/programs/nixy/default.nix | 2 -
home/programs/qutebrowser/bookmarks.nix | 468 ++++++-
home/programs/qutebrowser/default.nix | 39 +-
.../greasemonkey/dont-track-me-google.user.js | 826 ++++++++++++
.../i-dont-care-about-cookies.user.js | 984 ++++++++++++++
.../return-youtube-dislike.user.js | 704 ++++++++++
.../greasemonkey/sponsorblock-lite.user.js | 1146 +++++++++++++++++
.../greasemonkey/startpage-no-ads.user.js | 18 +
.../tracking-token-stripper.user.js | 191 +++
home/programs/qutebrowser/keybindings.nix | 15 +
home/programs/qutebrowser/quickmarks.nix | 5 -
home/programs/qutebrowser/search.nix | 30 +
home/programs/qutebrowser/settings.nix | 41 +
home/programs/qutebrowser/userscripts.nix | 27 +
home/programs/spicetify/default.nix | 2 +
home/programs/thunar/default.nix | 35 +-
home/programs/zathura/default.nix | 15 -
home/programs/zen/bookmarks.nix | 171 ---
home/programs/zen/default.nix | 95 --
home/programs/zen/keyboard-shortcuts.nix | 299 -----
home/programs/zen/policies.nix | 44 -
home/programs/zen/search.nix | 162 ---
home/programs/zen/settings.nix | 66 -
home/programs/zen/spaces.nix | 13 -
home/system/hyprland/bindings.nix | 53 +-
home/system/hyprland/default.nix | 22 +-
hosts/laptop/configuration.nix | 2 -
hosts/laptop/home.nix | 30 +-
hosts/pph/configuration.nix | 25 -
hosts/pph/hardware-configuration.nix | 31 -
hosts/pph/home.nix | 62 -
hosts/pph/secrets/default.nix | 43 -
hosts/pph/secrets/secrets.yaml | 18 -
hosts/pph/variables.nix | 42 -
hosts/server/configuration.nix | 1 -
hosts/server/home.nix | 22 +-
nixos/clamav.nix | 12 -
nixos/home-manager.nix | 10 +-
nixos/nvidia.nix | 5 -
nixos/utils.nix | 3 -
49 files changed, 4559 insertions(+), 1777 deletions(-)
delete mode 100644 home/programs/fetch/default.nix
create mode 100644 home/programs/group/basic-apps.nix
create mode 100644 home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js
create mode 100644 home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js
create mode 100644 home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js
create mode 100644 home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js
create mode 100644 home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js
create mode 100644 home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js
create mode 100644 home/programs/qutebrowser/keybindings.nix
delete mode 100644 home/programs/qutebrowser/quickmarks.nix
create mode 100644 home/programs/qutebrowser/search.nix
create mode 100644 home/programs/qutebrowser/settings.nix
create mode 100644 home/programs/qutebrowser/userscripts.nix
delete mode 100644 home/programs/zathura/default.nix
delete mode 100644 home/programs/zen/bookmarks.nix
delete mode 100644 home/programs/zen/default.nix
delete mode 100644 home/programs/zen/keyboard-shortcuts.nix
delete mode 100644 home/programs/zen/policies.nix
delete mode 100644 home/programs/zen/search.nix
delete mode 100644 home/programs/zen/settings.nix
delete mode 100644 home/programs/zen/spaces.nix
delete mode 100644 hosts/pph/configuration.nix
delete mode 100644 hosts/pph/hardware-configuration.nix
delete mode 100644 hosts/pph/home.nix
delete mode 100644 hosts/pph/secrets/default.nix
delete mode 100644 hosts/pph/secrets/secrets.yaml
delete mode 100644 hosts/pph/variables.nix
delete mode 100644 nixos/clamav.nix
diff --git a/flake.lock b/flake.lock
index b1e522b..ed8abef 100644
--- a/flake.lock
+++ b/flake.lock
@@ -119,22 +119,6 @@
"type": "github"
}
},
- "betterfox": {
- "flake": false,
- "locked": {
- "lastModified": 1775763269,
- "narHash": "sha256-cICl9WpAWdrzbQTjEnAXMiZ4tlC/YL3yiD4JtikPfkI=",
- "owner": "yokoffing",
- "repo": "Betterfox",
- "rev": "a9b4b8803aebd3a87492f0936db5a3c8513ae522",
- "type": "github"
- },
- "original": {
- "owner": "yokoffing",
- "repo": "Betterfox",
- "type": "github"
- }
- },
"blog": {
"inputs": {
"bun2nix": "bun2nix",
@@ -599,27 +583,6 @@
"type": "github"
}
},
- "home-manager_2": {
- "inputs": {
- "nixpkgs": [
- "zen-browser",
- "nixpkgs"
- ]
- },
- "locked": {
- "lastModified": 1774991950,
- "narHash": "sha256-kScKj3qJDIWuN9/6PMmgy5esrTUkYinrO5VvILik/zw=",
- "owner": "nix-community",
- "repo": "home-manager",
- "rev": "f2d3e04e278422c7379e067e323734f3e8c585a7",
- "type": "github"
- },
- "original": {
- "owner": "nix-community",
- "repo": "home-manager",
- "type": "github"
- }
- },
"hyprcursor": {
"inputs": {
"hyprlang": [
@@ -1192,16 +1155,16 @@
},
"nixpkgs-stable": {
"locked": {
- "lastModified": 1767313136,
- "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=",
+ "lastModified": 1776221942,
+ "narHash": "sha256-FbQAeVNi7G4v3QCSThrSAAvzQTmrmyDLiHNPvTF2qFM=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d",
+ "rev": "1766437c5509f444c1b15331e82b8b6a9b967000",
"type": "github"
},
"original": {
"owner": "nixos",
- "ref": "nixos-25.05",
+ "ref": "nixos-25.11",
"repo": "nixpkgs",
"type": "github"
}
@@ -1504,7 +1467,6 @@
"root": {
"inputs": {
"awesome-wallpapers": "awesome-wallpapers",
- "betterfox": "betterfox",
"blog": "blog",
"bun2nix": "bun2nix_2",
"caelestia-cli": "caelestia-cli",
@@ -1521,8 +1483,7 @@
"nvf": "nvf",
"sops-nix": "sops-nix",
"spicetify-nix": "spicetify-nix",
- "stylix": "stylix",
- "zen-browser": "zen-browser"
+ "stylix": "stylix"
}
},
"sops-nix": {
@@ -1942,27 +1903,6 @@
"repo": "xdg-desktop-portal-hyprland",
"type": "github"
}
- },
- "zen-browser": {
- "inputs": {
- "home-manager": "home-manager_2",
- "nixpkgs": [
- "nixpkgs"
- ]
- },
- "locked": {
- "lastModified": 1775744672,
- "narHash": "sha256-Qg3Wnn3WYiiii35CE9kE+XX4ooSFzupAnGC1/NjI5C8=",
- "owner": "0xc000022070",
- "repo": "zen-browser-flake",
- "rev": "14a238beb0621977e9bf04cba68919d5650deea9",
- "type": "github"
- },
- "original": {
- "owner": "0xc000022070",
- "repo": "zen-browser-flake",
- "type": "github"
- }
}
},
"root": "root",
diff --git a/flake.nix b/flake.nix
index e26fa90..e6a8954 100644
--- a/flake.nix
+++ b/flake.nix
@@ -7,7 +7,7 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
- nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05";
+ nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.11";
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1";
stylix.url = "github:danth/stylix";
@@ -35,14 +35,6 @@
url = "github:Gerg-L/spicetify-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
- betterfox = {
- url = "github:yokoffing/Betterfox";
- flake = false;
- };
- zen-browser = {
- url = "github:0xc000022070/zen-browser-flake";
- inputs.nixpkgs.follows = "nixpkgs";
- };
# Server
# FIXME: Deleted repo for now
# eleakxir.url = "github:anotherhadi/eleakxir";
@@ -73,20 +65,6 @@
];
};
- pph = nixpkgs.lib.nixosSystem {
- modules = [
- {
- nixpkgs.overlays = [];
- _module.args = {
- inherit inputs;
- };
- }
- inputs.home-manager.nixosModules.home-manager
- inputs.stylix.nixosModules.stylix
- inputs.nix-index-database.nixosModules.default
- ./hosts/pph/configuration.nix
- ];
- };
# Jack is my server
jack = nixpkgs.lib.nixosSystem {
modules = [
diff --git a/home/programs/brave/default.nix b/home/programs/brave/default.nix
index 28c1da8..07dcc0b 100644
--- a/home/programs/brave/default.nix
+++ b/home/programs/brave/default.nix
@@ -35,13 +35,6 @@
];
extensions = let
ids = [
- "cjpalhdlnbpafiamejdnhcphjbkeiagm" # ublock origin
- "dbepggeogbaibhgnhhndojpepiihcmeb" # vimium
- "eimadpbcbfnmbkopoojfekhnkhdbieeh" # dark reader
- "pkehgijcmpdhfbdbbnkijodmdjhbjlgp" # privacy badger
- "ghmbeldphafepmbegfdlkpapadhbakde" # proton pass
- "mmjbdbjnoablegbkcklggeknkfcjkjia" # custom new tab page
- "oabailhgoobiboghkmlppflobceplfde" # Enable Clipboard
];
in
map (id: {inherit id;}) ids;
@@ -82,27 +75,4 @@
categories = ["Network" "WebBrowser"];
};
};
-
- # =================================================================
- # BRAVE SETTINGS (via brave://flags)
- # =================================================================
-
- # These need to be set manually in brave://flags on first launch:
- # - Enable Tab Groups (UI)
- # - Enable Parallel Downloading
- # - Enable Reader Mode
- # - GPU Rasterization: Enabled
- # - Override software rendering list: Enabled
- #
- # Privacy settings (brave://settings/privacy):
- # - Block trackers & ads: Aggressive
- # - Block all fingerprinting
- # - Upgrade connections to HTTPS
- # - Block scripts: Off (breaks sites, use uBlock instead)
- # - Block cookies: Only 3rd party
- #
- # Appearance (brave://settings/appearance):
- # - Show home button: Off
- # - Show bookmarks bar: Only on new tab
- # - Use wide address bar: On
}
diff --git a/home/programs/fetch/default.nix b/home/programs/fetch/default.nix
deleted file mode 100644
index ef92e43..0000000
--- a/home/programs/fetch/default.nix
+++ /dev/null
@@ -1,367 +0,0 @@
-# Nerdfetch, a simple system info script written in bash
-# Source: https://github.com/ThatOneCalculator/NerdFetch
-{pkgs, ...}: let
- nerdfetch = pkgs.writeShellScriptBin "nerdfetch" ''
- ostype="$(uname)"
-
- version=8.1.1
- font=nerd
- distrotype=none
- osi=""
- ki=""
- ri=""
- pi=""
- ui=""
- ci=""
-
- case $1 in
- "-p")
- font=phosphor
- osi=""
- ki=""
- ri=""
- pi=""
- ui=""
- ci=""
- ;;
- "-c")
- font=cozette
- ki="♥"
- ri=""
- pi=""
- ui=""
- ci=""
- ;;
- "-e")
- font=emoji
- osi="🐧"
- ki="💓"
- ri="🐐"
- pi="📦"
- ui="☕"
- ci="🎨"
- ;;
- "-v")
- echo "NerdFetch $version"
- exit
- ;;
- "-h")
- echo "Flags:
- -c: Cozette font
- -p: Phosphor font
- -e: Emoji font
- -v: Version"
- exit
- ;;
- esac
-
- if command -v getprop 1>/dev/null; then
- distrotype=android
- fi
- kernel="$(echo $(uname -r) | cut -d'-' -f1-1)"
- case $ostype in
- *"Linux"*)
- if [ $distrotype = android ]; then
- host="$(hostname)"
- USER="$(whoami)"
- os="Android $(getprop ro.build.version.release)"
- case $font in
- phosphor) osi="" ;;
- emoji) osi="🤖" ;;
- *) osi="" ;;
- esac
- else
- host="$(cat /proc/sys/kernel/hostname)"
- . /etc/os-release
- if [ -f /bedrock/etc/bedrock-release ]; then
- os="$(brl version)"
- else
- os="''${PRETTY_NAME}"
- if [ $font = nerd ]; then
- case $(echo $ID | sed 's/ .*//') in
- debian) osi="" ;;
- arch) osi="" ;;
- endeavouros) osi="" ;;
- fedora) osi="" ;;
- gentoo) osi="" ;;
- rhel) osi="" ;;
- slackware) osi="" ;;
- void) osi="" ;;
- alpine) osi="" ;;
- nixos) osi="" ;;
- artix) osi="" ;;
- exherbo) osi="" ;;
- mageia) osi="" ;;
- manjaro) osi="" ;;
- opensuse) osi="" ;;
- solus) osi="" ;;
- ubuntu) osi="" ;;
- mint) osi="" ;;
- trisquel) osi="" ;;
- puppy) osi="" ;;
- coreos) osi="" ;;
- mx) osi="" ;;
- vanilla) osi="" ;;
- pop_os) osi="" ;;
- raspbian) osi="" ;;
- deepin) osi="" ;;
- almalinux) osi="" ;;
- garuda) osi="" ;;
- centos) osi="" ;;
- rocky) osi="" ;;
- esac
- elif [ $font = cozette ]; then
- case $(echo $ID | sed 's/ .*//') in
- debian) osi="" ;;
- arch) osi="" ;;
- fedora) osi="" ;;
- gentoo) osi="" ;;
- slackware) osi="" ;;
- void) osi="" ;;
- alpine) osi="" ;;
- nixos) osi="" ;;
- mageia) osi="" ;;
- manjaro) osi="" ;;
- opensuse) osi="" ;;
- ubuntu) osi="" ;;
- mint) osi="" ;;
- coreos) osi="" ;;
- centos) osi="" ;;
- esac
- fi
- fi
- fi
- shell=$(basename "$SHELL")
- ;;
- *"Darwin"*)
- host="$(hostname -f | sed -e 's/^[^.]*\.//')"
- mac_product="$(/usr/libexec/PlistBuddy -c "Print:ProductName" /System/Library/CoreServices/SystemVersion.plist)"
- mac_version="$(/usr/libexec/PlistBuddy -c "Print:ProductVersion" /System/Library/CoreServices/SystemVersion.plist)"
- os="''${mac_product} ''${mac_version}"
- case $font in
- nerd) osi="" ;;
- phosphor) osi="" ;;
- cozette) osi="" ;;
- emoji) osi="🍎" ;;
- esac
- ;;
- *"FreeBSD"*)
- host="$(hostname)"
- distrotype=bsd
- os="FreeBSD $(freebsd-version | sed 's/-.*//')"
- case $font in
- nerd) osi="" ;;
- phosphor) osi="" ;;
- cozette) osi="" ;;
- emoji) osi="😈" ;;
- esac
- ;;
- *"OpenBSD"*)
- host="$(hostname)"
- distrotype=bsd
- os="OpenBSD $(uname -r)"
- case $font in
- nerd) osi="" ;;
- phosphor) osi="" ;;
- cozette) osi="⌘" ;;
- emoji) osi="🐡" ;;
- esac
- ;;
- *"NetBSD"*)
- host="$(hostname)"
- distrotype=netbsd
- os="NetBSD $(uname -r)"
- case $font in
- nerd) osi="" ;;
- phosphor) osi="" ;;
- cozette) osi="" ;;
- emoji) osi="🚩" ;;
- esac
- ;;
- *)
- os="Unix-like"
- host="host"
- ;;
- esac
-
- ## PACKAGE MANAGER AND PACKAGES DETECTION
-
- MANAGER=$(which nix-env pkg flatpak yum zypper dnf rpm dpkg-query brew port pacman xbps-query emerge cave apk kiss pmm /usr/sbin/slackpkg bulge birb yay paru pacstall cpm pmm eopkg getprop 2>/dev/null)
- manager=$(basename "$MANAGER")
- if [ $distrotype = netbsd ]; then
- manager="pkg_info-netbsd"
- fi
- case $manager in
- cpm) packages="$(cpm C)" ;;
- flatpak) packages="$(flatpak list --app | wc -l)" ;;
- brew) packages="$(printf '%s\n' "$(brew --cellar)/"* | wc -l)" ;;
- port) packages="$(port installed | wc -l)" ;;
- dpkg-query) packages="$(dpkg-query -f '${"binary:Package"}\n' -W | wc -l)" ;;
- rpm) packages="$(rpm -qa --last | wc -l)" ;;
- yum) packages="$(yum list installed | wc -l)" ;;
- dnf) packages="$(dnf list installed | wc -l)" ;;
- zypper) packages="$(zypper se | wc -l)" ;;
- pacman) packages="$(pacman -Q | wc -l)" ;;
- yay) packages="$(yay -Q | wc -l)" ;;
- paru) packages="$(paru -Q | wc -l)" ;;
- pacstall) packages="$(pacstall -L | wc -l)" ;;
- kiss) packages="$(kiss list | wc -l)" ;;
- emerge) packages="$(qlist -I | wc -l)" ;;
- pkg) packages="$(pkg info | wc -l | tr -d ' ')" ;;
- cave) packages="$(cave show installed-slots | wc -l)" ;;
- xbps-query) packages="$(xbps-query -l | wc -l)" ;;
- nix-env) packages="$(nix-store -q --requisites /run/current-system/sw | wc -l)" ;;
- apk) packages="$(apk list --installed | wc -l)" ;;
- pmm) packages="$(/bedrock/libexec/pmm pacman pmm -Q 2>/dev/null | wc -l)" ;;
- eopkg) packages="$(eopkg li | wc -l)" ;;
- /usr/sbin/slackpkg) packages="$(ls /var/log/packages | wc -l)" ;;
- bulge) packages="$(bulge list | wc -l)" ;;
- birb) packages="$(birb --list-installed | wc -l)" ;;
- pkg_info)
- packages="$(pkg_info -A | wc -l)"
- manager="pkg"
- ;;
- pkg_info-netbsd)
- packages="$(pkg_info -a | wc -l)"
- manager="pkg"
- ;;
- *)
- if [ $distrotype = android ]; then
- packages="$(dpkg-query -f '${"binary:Package"}\n' -W | wc -l)"
- manager="dpkg"
- else
- packages="$(ls /usr/bin | wc -l)"
- manager="bin"
- fi
- ;;
- esac
-
- packages="''${packages#"''${packages%%[![:space:]]*}"}"
- manager=$(echo $manager | sed "s/-query//; s/\/usr\/.*\///")
-
- ## UPTIME DETECTION
-
- if [ $distrotype = android ]; then
- uptime="$(echo $(uptime -p) | cut -c 4-)"
- elif [ $distrotype = bsd ] || [ $distrotype = netbsd ]; then
- uptime="$(uptime | sed -e 's/.* up //; s/, [0-9]* user.*//')"
- else
- case $ostype in
- *"Linux"*)
- IFS=. read -r s _ /dev/null 2>&1; then
- mempercent="($(expr $(expr ''${mem_used} \* 100 / ''${mem_full}))%)"
- fi
-
- ## DEFINE COLORS
-
- bold='[1m'
- black='[30m'
- red='[31m'
- green='[32m'
- yellow='[33m'
- blue='[34m'
- magenta='[35m'
- cyan='[36m'
- white='[37m'
- grey='[90m'
- reset='[0m'
-
- ## USER VARIABLES -- YOU CAN CHANGE THESE
-
- lc="$reset$bold$magenta" # labels
- nc="$reset$bold$magenta" # labels
- hn="$reset$bold$magenta" # labels
- ic="$reset$white" # info
- c0="$reset$grey" # first color
- c1="$reset$white" # second color
- c2="$reset$yellow" # third color
-
- ## OUTPUT
-
- echo """
- ''${c0} ___ ''${nc}''${USER}''${grey}@''${reset}''${hn}''${host}''${reset}
- ''${c0} (''${c1}.. ''${c0}\ ''${lc}''${osi} ''${ic}''${os}''${reset}
- ''${c0} (''${c2}<> ''${c0}| ''${lc}''${ki} ''${ic}''${kernel}''${reset}
- ''${c0} /''${c1}/ \\ ''${c0}\\ ''${lc}''${ri} ''${ic}''${RAM}''${memstat} ''${mempercent}
- ''${c0} ( ''${c1}| | ''${c0}/| ''${lc}''${pi} ''${ic}''${packages} (''${manager})''${reset}
- ''${c2} _''${c0}/\\ ''${c1}__)''${c0}/''${c2}_''${c0}) ''${lc}''${ui} ''${ic}''${uptime}''${reset}
- ''${c2} \/''${c0}-____''${c2}\/''${reset} ''${lc}''${ci} ''${red}███''${green}███''${yellow}███''${blue}███''${magenta}███''${cyan}███''${reset}
- """
- '';
-in {home.packages = [nerdfetch];}
diff --git a/home/programs/ghostty/default.nix b/home/programs/ghostty/default.nix
index f0a48a9..f865234 100644
--- a/home/programs/ghostty/default.nix
+++ b/home/programs/ghostty/default.nix
@@ -1,4 +1,9 @@
{
+ home.sessionVariables = {
+ TERMINAL = "ghostty";
+ TERM = "ghostty";
+ };
+
programs.ghostty = {
enable = true;
installVimSyntax = true;
diff --git a/home/programs/group/basic-apps.nix b/home/programs/group/basic-apps.nix
new file mode 100644
index 0000000..3f79944
--- /dev/null
+++ b/home/programs/group/basic-apps.nix
@@ -0,0 +1,21 @@
+{
+ pkgs,
+ pkgs-stable,
+ ...
+}: {
+ home.packages = with pkgs-stable; [
+ vlc # Video player
+ blanket # White-noise app
+ obsidian # Note taking app
+ textpieces # Manipulate texts
+ resources # Ressource monitor
+ gnome-clocks # Clocks app
+ gnome-text-editor # Basic graphic text editor
+ ticktick # Todo app
+ pinta # Image editor
+ onlyoffice-desktopeditors # Office suite
+
+ signal-desktop # Messaging app
+ element-desktop # Messaging app
+ ];
+}
diff --git a/home/programs/group/cybersecurity.nix b/home/programs/group/cybersecurity.nix
index f01565c..ecf703c 100644
--- a/home/programs/group/cybersecurity.nix
+++ b/home/programs/group/cybersecurity.nix
@@ -1,14 +1,13 @@
{
- pkgs,
+ pkgs-stable,
inputs,
...
}: {
- home.packages = with pkgs; [
+ home.packages = with pkgs-stable; [
wireshark
nmap
john
hashcat
- # inputs.eleakxir.packages.${stdenv.hostPlatform.system}.leak-utils
# Web
caido
diff --git a/home/programs/group/dev.nix b/home/programs/group/dev.nix
index 0fb7f94..60c22a4 100644
--- a/home/programs/group/dev.nix
+++ b/home/programs/group/dev.nix
@@ -1,19 +1,24 @@
{
pkgs,
+ pkgs-stable,
inputs,
...
}: {
- home.packages = with pkgs; [
- go
- bun
- docker
- nodejs
- python3
- jq
- just
- air
- duckdb
- inputs.bun2nix.packages.${stdenv.hostPlatform.system}.default
- claude-code
- ];
+ home.packages =
+ (with pkgs; [
+ # Unstable: latest toolchain versions preferred for dev
+ go
+ bun
+ nodejs
+ air
+ duckdb
+ claude-code
+ inputs.bun2nix.packages.${stdenv.hostPlatform.system}.default
+ ])
+ ++ (with pkgs-stable; [
+ docker
+ python3
+ jq
+ just
+ ]);
}
diff --git a/home/programs/group/misc.nix b/home/programs/group/misc.nix
index aebf5ff..1cbecce 100644
--- a/home/programs/group/misc.nix
+++ b/home/programs/group/misc.nix
@@ -1,5 +1,5 @@
-{pkgs, ...}: {
- home.packages = with pkgs; [
+{pkgs-stable, ...}: {
+ home.packages = with pkgs-stable; [
peaclock
cbonsai
pipes
diff --git a/home/programs/nixy/default.nix b/home/programs/nixy/default.nix
index d619c87..a7cb0a4 100644
--- a/home/programs/nixy/default.nix
+++ b/home/programs/nixy/default.nix
@@ -33,8 +33,6 @@
";Collect Garbage;nixy gc"
";Clean Boot Menu;nixy cb"
";List generation;nixy listgen"
- ";Hyprland Keybindings;nvim ${configDirectory}/docs/KEYBINDINGS-HYPRLAND.md"
- ";Wallpapers;zen https://github.com/anotherhadi/nixy-wallpapers"
)
# Apply default icons if empty:
diff --git a/home/programs/qutebrowser/bookmarks.nix b/home/programs/qutebrowser/bookmarks.nix
index e0deee9..c2a85ad 100644
--- a/home/programs/qutebrowser/bookmarks.nix
+++ b/home/programs/qutebrowser/bookmarks.nix
@@ -1,10 +1,466 @@
{
- home.file.".local/share/qutebrowser/bookmarks/urls" = {
- text = ''
- https://github.com GitHub
- https://youtube.com YouTube
- https://account.proton.me Proton
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ bookmarkList = [
+ {
+ name = "Proton Mail";
+ url = "https://mail.proton.me";
+ }
+ {
+ name = "Proton Drive";
+ url = "https://drive.proton.me";
+ }
+ {
+ name = "Proton Lumo";
+ url = "https://lumo.proton.me";
+ }
+ {
+ name = "Proton Calendar";
+ url = "https://calendar.proton.me";
+ }
+ {
+ name = "Tools";
+ bookmarks = [
+ {
+ name = "tldr";
+ url = "https://tldr.inbrowser.app/";
+ }
+ {
+ name = "Excalidraw";
+ url = "https://excalidraw.com";
+ }
+ {
+ name = "Cobalt (downloader)";
+ url = "https://cobalt.meowing.de";
+ }
+ {
+ name = "Mazanoke (image)";
+ url = "https://mazanoke.hadi.icu";
+ }
+ {
+ name = "Stirling PDF";
+ url = "https://pdf.hadi.icu";
+ }
+ {
+ name = "Vert";
+ url = "https://vert.sh";
+ }
+ {
+ name = "Markdown to PDF";
+ url = "https://md2file.com";
+ }
+ {
+ name = "Image to Vector";
+ url = "https://www.vectorcascade.com/";
+ }
+ {
+ name = "PrivateBin";
+ url = "https://privatebin.net";
+ }
+ ];
+ }
+ {
+ name = "Social";
+ bookmarks = [
+ {
+ name = "Bluesky";
+ url = "https://bsky.app";
+ }
+ {
+ name = "Reddit";
+ url = "https://reddit.com";
+ }
+ {
+ name = "Youtube";
+ url = "https://youtube.com";
+ }
+ {
+ name = "Instagram";
+ url = "https://instagram.com";
+ }
+ {
+ name = "Github";
+ url = "https://github.com";
+ }
+ {
+ name = "Discord";
+ url = "https://discord.com/channels/@me/";
+ }
+ ];
+ }
+ {
+ name = "Other";
+ bookmarks = [
+ {
+ name = "Startpage Config";
+ url = "https://www.startpage.com/do/mypage.pl?prfe=45d331deb05471d659dba933e7400df51d952bb103da6f6125c0e769a6be1d65610456a479f495ceeee7e97311cf227d7c1bb198de0ceeb193d8cddf9c455c19a409cc35c3e3f542ee27bd7cecd3";
+ }
+ {
+ name = "Hyprland Wiki";
+ url = "https://wiki.hypr.land";
+ }
+ {
+ name = "MyNixOS";
+ url = "https://mynixos.com";
+ }
+ {
+ name = "Nixpkgs";
+ url = "https://github.com/NixOS/nixpkgs";
+ }
+ {
+ name = "Claude";
+ url = "https://claude.ai";
+ }
+ {
+ name = "Gemini";
+ url = "https://gemini.google.com";
+ }
+ {
+ name = "Medium";
+ url = "https://medium.com";
+ }
+ {
+ name = "Maps";
+ url = "https://maps.apple.com";
+ }
+ {
+ name = "Amazon";
+ url = "https://amazon.fr";
+ }
+ ];
+ }
+ {
+ name = "Infosec";
+ bookmarks = [
+ {
+ name = "Nix 4 Cyber";
+ url = "https://n4c.hadi.icu";
+ }
+ {
+ name = "Cyberchef";
+ url = "https://cyberchef.hadi.icu";
+ }
+ {
+ name = "TryHackMe";
+ url = "https://tryhackme.com";
+ }
+ {
+ name = "Root-Me";
+ url = "https://root-me.org";
+ }
+ {
+ name = "Exploit-DB";
+ url = "https://exploit-db.com";
+ }
+ {
+ name = "Crack Station";
+ url = "https://crackstation.net";
+ }
+ {
+ name = "Osint Tracker";
+ url = "https://app.osintracker.com";
+ }
+ ];
+ }
+ ];
+
+ c = config.lib.stylix.colors;
+
+ stripProtocol = url:
+ lib.removePrefix "https://" (lib.removePrefix "http://" url);
+
+ mkCard = item: ''
+
+
+ ${builtins.substring 0 1 item.name}
+
+
+ ${item.name}
+ ${stripProtocol item.url}
+
+ '';
+
+ # Group consecutive root items so they share the same .cards grid
+ grouped = let
+ step = acc: item:
+ if item ? url
+ then acc // {pending = acc.pending ++ [item];}
+ else {
+ groups =
+ acc.groups
+ ++ lib.optional (acc.pending != []) {
+ isRoot = true;
+ items = acc.pending;
+ }
+ ++ [
+ {
+ isRoot = false;
+ item = item;
+ }
+ ];
+ pending = [];
+ };
+ result =
+ lib.foldl' step {
+ groups = [];
+ pending = [];
+ }
+ bookmarkList;
+ in
+ result.groups
+ ++ lib.optional (result.pending != []) {
+ isRoot = true;
+ items = result.pending;
+ };
+
+ mkSection = group:
+ if group.isRoot
+ then ''
+
+
+ ${lib.concatMapStrings mkCard group.items}
+
+
+ ''
+ else ''
+
+
${group.item.name}
+
+ ${lib.concatMapStrings mkCard group.item.bookmarks}
+
+
+ '';
+
+ publicBookmarks =
+ pkgs.writeText "qutebrowser-public-bookmarks"
+ (lib.concatMapStrings (
+ item:
+ if item ? url
+ then "${item.url} ${item.name}\n"
+ else lib.concatMapStrings (b: "${b.url} ${item.name}/${b.name}\n") item.bookmarks
+ )
+ bookmarkList);
+
+ privateBookmarksPath = config.qutebrowser.privateBookmarksPath;
+in {
+ options.qutebrowser.privateBookmarksPath = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ description = "Path to a file containing extra (private) bookmarks to append.";
+ };
+
+ config = {
+ # Fully static HTML — order is preserved, no dependency on qutebrowser's Jinja rendering
+ xdg.dataFile."qutebrowser/bookmarks.html".text = ''
+
+
+
+
+
+ Bookmarks
+
+
+
+
+
+
No results
+ ${lib.concatMapStrings mkSection grouped}
+
+
+
+
+ '';
+
+ home.activation.qutebrowserBookmarks = lib.hm.dag.entryAfter ["setupSecrets" "writeBoundary"] ''
+ mkdir -p ${config.home.homeDirectory}/.config/qutebrowser/bookmarks
+ cat ${publicBookmarks} ${lib.optionalString (privateBookmarksPath != null) ''"${privateBookmarksPath}"''} \
+ > ${config.home.homeDirectory}/.config/qutebrowser/bookmarks/urls
'';
- force = true;
};
}
diff --git a/home/programs/qutebrowser/default.nix b/home/programs/qutebrowser/default.nix
index 0676ddd..16be0e3 100644
--- a/home/programs/qutebrowser/default.nix
+++ b/home/programs/qutebrowser/default.nix
@@ -1,8 +1,17 @@
{...}: {
imports = [
./bookmarks.nix
+ ./search.nix
+ ./keybindings.nix
+ ./settings.nix
+ ./userscripts.nix
];
+ home.sessionVariables = {
+ DEFAULT_BROWSER = "qutebrowser";
+ BROWSER = "qutebrowser";
+ };
+
xdg.mimeApps.defaultApplications = {
"text/html" = ["org.qutebrowser.qutebrowser.desktop"];
"text/xml" = ["org.qutebrowser.qutebrowser.desktop"];
@@ -13,30 +22,16 @@
"x-scheme-handler/qute" = ["org.qutebrowser.qutebrowser.desktop"];
};
+ xdg.desktopEntries.qutebrowser-private = {
+ name = "Qutebrowser (Temp session)";
+ genericName = "Web Browser";
+ exec = "qutebrowser --temp-basedir %U";
+ icon = "qutebrowser";
+ categories = ["Network" "WebBrowser"];
+ };
+
programs.qutebrowser = {
enable = true;
loadAutoconfig = true;
- searchEngines = rec {
- startpage = "https://www.startpage.com/sp/search?q={}";
-
- mynixos = "https://mynixos.com/search?q={}";
- duckduckgo = "https://duckduckgo.com/?q={}";
- google = "https://google.com/search?hl=en&q={}";
- yandex = "https://yandex.com/search/?text={}";
- bing = "https://bing.com/search?q={}";
-
- # shortcuts
- g = google;
- n = mynixos;
- DEFAULT = startpage;
- };
- quickmarks = import ./quickmarks.nix;
- settings = {
- url = rec {
- default_page = "https://www.startpage.com";
- start_pages = [default_page];
- };
- new_instance_open_target = "window";
- };
};
}
diff --git a/home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js b/home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js
new file mode 100644
index 0000000..0b1ede4
--- /dev/null
+++ b/home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js
@@ -0,0 +1,826 @@
+// ==UserScript==
+// @name Don't track me Google
+// @namespace Rob W
+// @description Removes the annoying link-conversion at Google Search/maps/...
+// @version 4.28
+// @icon https://raw.githubusercontent.com/Rob--W/dont-track-me-google/master/icon48.png
+// @supportURL https://github.com/Rob--W/dont-track-me-google/issues
+// @license MIT
+// @run-at document-start
+// @match *://*.google.com/*
+// @match *://*.google.ad/*
+// @match *://*.google.ae/*
+// @match *://*.google.com.af/*
+// @match *://*.google.com.ag/*
+// @match *://*.google.com.ai/*
+// @match *://*.google.al/*
+// @match *://*.google.am/*
+// @match *://*.google.co.ao/*
+// @match *://*.google.com.ar/*
+// @match *://*.google.as/*
+// @match *://*.google.at/*
+// @match *://*.google.com.au/*
+// @match *://*.google.az/*
+// @match *://*.google.ba/*
+// @match *://*.google.com.bd/*
+// @match *://*.google.be/*
+// @match *://*.google.bf/*
+// @match *://*.google.bg/*
+// @match *://*.google.com.bh/*
+// @match *://*.google.bi/*
+// @match *://*.google.bj/*
+// @match *://*.google.com.bn/*
+// @match *://*.google.com.bo/*
+// @match *://*.google.com.br/*
+// @match *://*.google.bs/*
+// @match *://*.google.bt/*
+// @match *://*.google.co.bw/*
+// @match *://*.google.by/*
+// @match *://*.google.com.bz/*
+// @match *://*.google.ca/*
+// @match *://*.google.cd/*
+// @match *://*.google.cf/*
+// @match *://*.google.cg/*
+// @match *://*.google.ch/*
+// @match *://*.google.ci/*
+// @match *://*.google.co.ck/*
+// @match *://*.google.cl/*
+// @match *://*.google.cm/*
+// @match *://*.google.cn/*
+// @match *://*.google.com.co/*
+// @match *://*.google.co.cr/*
+// @match *://*.google.com.cu/*
+// @match *://*.google.cv/*
+// @match *://*.google.com.cy/*
+// @match *://*.google.cz/*
+// @match *://*.google.de/*
+// @match *://*.google.dj/*
+// @match *://*.google.dk/*
+// @match *://*.google.dm/*
+// @match *://*.google.com.do/*
+// @match *://*.google.dz/*
+// @match *://*.google.com.ec/*
+// @match *://*.google.ee/*
+// @match *://*.google.com.eg/*
+// @match *://*.google.es/*
+// @match *://*.google.com.et/*
+// @match *://*.google.fi/*
+// @match *://*.google.com.fj/*
+// @match *://*.google.fm/*
+// @match *://*.google.fr/*
+// @match *://*.google.ga/*
+// @match *://*.google.ge/*
+// @match *://*.google.gg/*
+// @match *://*.google.com.gh/*
+// @match *://*.google.com.gi/*
+// @match *://*.google.gl/*
+// @match *://*.google.gm/*
+// @match *://*.google.gp/*
+// @match *://*.google.gr/*
+// @match *://*.google.com.gt/*
+// @match *://*.google.gy/*
+// @match *://*.google.com.hk/*
+// @match *://*.google.hn/*
+// @match *://*.google.hr/*
+// @match *://*.google.ht/*
+// @match *://*.google.hu/*
+// @match *://*.google.co.id/*
+// @match *://*.google.ie/*
+// @match *://*.google.co.il/*
+// @match *://*.google.im/*
+// @match *://*.google.co.in/*
+// @match *://*.google.iq/*
+// @match *://*.google.is/*
+// @match *://*.google.it/*
+// @match *://*.google.je/*
+// @match *://*.google.com.jm/*
+// @match *://*.google.jo/*
+// @match *://*.google.co.jp/*
+// @match *://*.google.co.ke/*
+// @match *://*.google.com.kh/*
+// @match *://*.google.ki/*
+// @match *://*.google.kg/*
+// @match *://*.google.co.kr/*
+// @match *://*.google.com.kw/*
+// @match *://*.google.kz/*
+// @match *://*.google.la/*
+// @match *://*.google.com.lb/*
+// @match *://*.google.li/*
+// @match *://*.google.lk/*
+// @match *://*.google.co.ls/*
+// @match *://*.google.lt/*
+// @match *://*.google.lu/*
+// @match *://*.google.lv/*
+// @match *://*.google.com.ly/*
+// @match *://*.google.co.ma/*
+// @match *://*.google.md/*
+// @match *://*.google.me/*
+// @match *://*.google.mg/*
+// @match *://*.google.mk/*
+// @match *://*.google.ml/*
+// @match *://*.google.com.mm/*
+// @match *://*.google.mn/*
+// @match *://*.google.ms/*
+// @match *://*.google.com.mt/*
+// @match *://*.google.mu/*
+// @match *://*.google.mv/*
+// @match *://*.google.mw/*
+// @match *://*.google.com.mx/*
+// @match *://*.google.com.my/*
+// @match *://*.google.co.mz/*
+// @match *://*.google.com.na/*
+// @match *://*.google.com.nf/*
+// @match *://*.google.com.ng/*
+// @match *://*.google.com.ni/*
+// @match *://*.google.ne/*
+// @match *://*.google.nl/*
+// @match *://*.google.no/*
+// @match *://*.google.com.np/*
+// @match *://*.google.nr/*
+// @match *://*.google.nu/*
+// @match *://*.google.co.nz/*
+// @match *://*.google.com.om/*
+// @match *://*.google.com.pa/*
+// @match *://*.google.com.pe/*
+// @match *://*.google.com.pg/*
+// @match *://*.google.com.ph/*
+// @match *://*.google.com.pk/*
+// @match *://*.google.pl/*
+// @match *://*.google.pn/*
+// @match *://*.google.com.pr/*
+// @match *://*.google.ps/*
+// @match *://*.google.pt/*
+// @match *://*.google.com.py/*
+// @match *://*.google.com.qa/*
+// @match *://*.google.ro/*
+// @match *://*.google.ru/*
+// @match *://*.google.rw/*
+// @match *://*.google.com.sa/*
+// @match *://*.google.com.sb/*
+// @match *://*.google.sc/*
+// @match *://*.google.se/*
+// @match *://*.google.com.sg/*
+// @match *://*.google.sh/*
+// @match *://*.google.si/*
+// @match *://*.google.sk/*
+// @match *://*.google.com.sl/*
+// @match *://*.google.sn/*
+// @match *://*.google.so/*
+// @match *://*.google.sm/*
+// @match *://*.google.sr/*
+// @match *://*.google.st/*
+// @match *://*.google.com.sv/*
+// @match *://*.google.td/*
+// @match *://*.google.tg/*
+// @match *://*.google.co.th/*
+// @match *://*.google.com.tj/*
+// @match *://*.google.tk/*
+// @match *://*.google.tl/*
+// @match *://*.google.tm/*
+// @match *://*.google.tn/*
+// @match *://*.google.to/*
+// @match *://*.google.com.tr/*
+// @match *://*.google.tt/*
+// @match *://*.google.com.tw/*
+// @match *://*.google.co.tz/*
+// @match *://*.google.com.ua/*
+// @match *://*.google.co.ug/*
+// @match *://*.google.co.uk/*
+// @match *://*.google.com.uy/*
+// @match *://*.google.co.uz/*
+// @match *://*.google.com.vc/*
+// @match *://*.google.co.ve/*
+// @match *://*.google.vg/*
+// @match *://*.google.co.vi/*
+// @match *://*.google.com.vn/*
+// @match *://*.google.vu/*
+// @match *://*.google.ws/*
+// @match *://*.google.rs/*
+// @match *://*.google.co.za/*
+// @match *://*.google.co.zm/*
+// @match *://*.google.co.zw/*
+// @match *://*.google.cat/*
+// @match *://*.google.ng/*
+// @downloadURL https://update.greasyfork.org/scripts/428243/Don%27t%20track%20me%20Google.user.js
+// @updateURL https://update.greasyfork.org/scripts/428243/Don%27t%20track%20me%20Google.meta.js
+// ==/UserScript==
+
+document.addEventListener('mousedown', handlePointerPress, true);
+document.addEventListener('touchstart', handlePointerPress, true);
+document.addEventListener('click', handleClick, true);
+var scriptCspNonce;
+var needsCspNonce = typeof browser !== 'undefined'; // Firefox.
+var preferenceObservers = [];
+setupAggresiveUglyLinkPreventer();
+
+var forceNoReferrer = true;
+var noping = true;
+if (typeof chrome == 'object' && chrome.storage) {
+ (chrome.storage.sync || chrome.storage.local).get({
+ forceNoReferrer: true,
+ // From version 4.7 until 4.11, the preference was the literal value of
+ // the referrer policy.
+ referrerPolicy: 'no-referrer',
+ noping: true,
+ }, function(items) {
+ if (items) {
+ // Migration code (to be removed in the future).
+ if (items.referrerPolicy === '') {
+ // User explicitly allowed referrers to be sent, respect that.
+ items.forceNoReferrer = false;
+ }
+ forceNoReferrer = items.forceNoReferrer;
+ noping = items.noping;
+ callPreferenceObservers();
+ }
+ });
+ chrome.storage.onChanged.addListener(function(changes) {
+ if (changes.forceNoReferrer) {
+ forceNoReferrer = changes.forceNoReferrer.newValue;
+ }
+ if (changes.noping) {
+ noping = changes.noping.newValue;
+ }
+ callPreferenceObservers();
+ });
+}
+
+function callImmediatelyAndOnPreferenceUpdate(callback) {
+ callback();
+ preferenceObservers.push(callback);
+}
+function callPreferenceObservers() {
+ // This method is usually once, and occasionally more than once if the user
+ // changes a preference. For simplicity we don't check whether a pref was
+ // changed before calling a callback - these are cheap anyway.
+ preferenceObservers.forEach(function(callback) {
+ callback();
+ });
+}
+
+function getReferrerPolicy() {
+ return forceNoReferrer ? 'origin' : '';
+}
+
+function updateReferrerPolicy(a) {
+ if (a.referrerPolicy === 'no-referrer') {
+ // "no-referrer" is more privacy-friendly than "origin".
+ return;
+ }
+ var referrerPolicy = getReferrerPolicy();
+ if (referrerPolicy) {
+ a.referrerPolicy = referrerPolicy;
+ }
+}
+
+function handlePointerPress(e) {
+ var a = e.target;
+ while (a && !a.href) {
+ a = a.parentElement;
+ }
+ if (!a) {
+ return;
+ }
+ var inlineMousedown = a.getAttribute('onmousedown');
+ // return rwt(....); // E.g Google search results.
+ // return google.rwt(...); // E.g. sponsored search results
+ // return google.arwt(this); // E.g. sponsored search results (dec 2016).
+ if (inlineMousedown && /\ba?rwt\(/.test(inlineMousedown)) {
+ a.removeAttribute('onmousedown');
+ // Just in case:
+ a.removeAttribute('ping');
+ // In Chrome, removing onmousedown during event dispatch does not
+ // prevent the inline listener from running... So we have to cancel
+ // event propagation just in case.
+ e.stopImmediatePropagation();
+ }
+ if (noping) {
+ a.removeAttribute('ping');
+ }
+ var realLink = getRealLinkFromGoogleUrl(a);
+ if (realLink) {
+ a.href = realLink;
+ // Sometimes, two fixups are needed, on old mobile user agents:
+ // /url?q=https://googleweblight.com/fp?u=... -> ...
+ realLink = getRealLinkFromGoogleUrl(a);
+ if (realLink) {
+ a.href = realLink;
+ }
+ }
+ updateReferrerPolicy(a);
+
+ if (e.eventPhase === Event.CAPTURING_PHASE) {
+ // Our event listener runs first, to sanitize the link.
+ // But the page may have an event handler that modifies the link again.
+ // We can append a listener to the bubbling phase of the (current)
+ // event dispatch to fix the link up again, provided that the page did
+ // not call stopPropagation() or stopImmediatePropagation().
+ var eventOptions = { capture: false, once: true };
+ a.addEventListener(e.type, handlePointerPress, eventOptions);
+ document.addEventListener(e.type, handlePointerPress, eventOptions);
+ }
+}
+
+// This is specifically designed for catching clicks in Gmail.
+// Gmail binds a click handler to a and cancels the event after opening
+// a window with an ugly URL. It uses a blank window + meta refresh in Firefox,
+// which is too crazy to patch. So we just make sure that the browser's default
+// click handler is activated (=open link in new tab).
+// The entry point for this crazy stuff is shown in my comment at
+// https://github.com/Rob--W/dont-track-me-google/issues/2
+function handleClick(e) {
+ if (e.button !== 0) {
+ return;
+ }
+ var a = e.target;
+ while (a && !a.href) {
+ a = a.parentElement;
+ }
+ if (!a) {
+ return;
+ }
+ if (a.dataset && a.dataset.url) {
+ var realLink = getSanitizedIntentUrl(a.dataset.url);
+ if (realLink) {
+ a.dataset.url = realLink;
+ }
+ }
+ if (!location.hostname.startsWith('mail.')) {
+ // This hack was designed for Gmail, but broke other Google sites:
+ // - https://github.com/Rob--W/dont-track-me-google/issues/6
+ // - https://github.com/Rob--W/dont-track-me-google/issues/19
+ // So let's disable it for every domain except Gmail.
+ return;
+ }
+ // TODO: Consider using a.baseURI instead of location in case Gmail ever
+ // starts using
?
+ if (a.origin === location.origin) {
+ // Same-origin link.
+ // E.g. an in-page navigation at Google Docs (#...)
+ // or an attachment at Gmail (https://mail.google.com/mail/u/0?ui=2&...)
+ return;
+ }
+ if (a.protocol !== 'http:' &&
+ a.protocol !== 'https:' &&
+ a.protocol !== 'ftp:') {
+ // Be conservative and don't block too much. E.g. Gmail has special
+ // handling for mailto:-URLs, and using stopPropagation now would
+ // cause mailto:-links to be opened by the platform's default mailto
+ // handler instead of Gmail's handler (=open in new window).
+ return;
+ }
+ if (a.target === '_blank') {
+ e.stopPropagation();
+ updateReferrerPolicy(a);
+ }
+}
+
+/**
+ * @param {URL|HTMLHyperlinkElementUtils} a
+ * @returns {String} the real URL if the given link is a Google redirect URL.
+ */
+function getRealLinkFromGoogleUrl(a) {
+ if (a.protocol !== 'https:' && a.protocol !== 'http:') {
+ return;
+ }
+ var url;
+ if ((a.hostname === location.hostname || a.hostname === 'www.google.com') &&
+ (a.pathname === '/url' || a.pathname === '/local_url' ||
+ a.pathname === '/searchurl/rr.html' ||
+ a.pathname === '/linkredirect')) {
+ // Google Maps / Dito (/local_url?q=
)
+ // Mobile (/url?q=)
+ // Google Meet's chat (/linkredirect?authuser=0&dest=)
+ url = /[?&](?:q|url|dest)=((?:https?|ftp)[%:][^&]+)/.exec(a.search);
+ if (url) {
+ return decodeURIComponent(url[1]);
+ }
+ // Help pages, e.g. safe browsing (/url?...&q=%2Fsupport%2Fanswer...)
+ url = /[?&](?:q|url)=((?:%2[Ff]|\/)[^&]+)/.exec(a.search);
+ if (url) {
+ return a.origin + decodeURIComponent(url[1]);
+ }
+ // Redirect pages for Android intents (/searchurl/rr.html#...&url=...)
+ // rr.html only supports http(s). So restrict to http(s) only.
+ url = /[#&]url=(https?[:%][^&]+)/.exec(a.hash);
+ if (url) {
+ return decodeURIComponent(url[1]);
+ }
+ }
+ // Google Search with old mobile UA (e.g. Firefox 41).
+ if (a.hostname === 'googleweblight.com' && a.pathname === '/fp') {
+ url = /[?&]u=((?:https?|ftp)[%:][^&]+)/.exec(a.search);
+ if (url) {
+ return decodeURIComponent(url[1]);
+ }
+ }
+}
+
+/**
+ * @param {string} intentUrl
+ * @returns {string|undefined} The sanitized intent:-URL if it was an intent URL
+ * with embedded tracking link.
+ */
+function getSanitizedIntentUrl(intentUrl) {
+ if (!intentUrl.startsWith('intent:')) {
+ return;
+ }
+ // https://developer.chrome.com/multidevice/android/intents#syntax
+ var BROWSER_FALLBACK_URL = ';S.browser_fallback_url=';
+ var indexStart = intentUrl.indexOf(BROWSER_FALLBACK_URL);
+ if (indexStart === -1) {
+ return;
+ }
+ indexStart += BROWSER_FALLBACK_URL.length;
+ var indexEnd = intentUrl.indexOf(';', indexStart);
+ indexEnd = indexEnd === -1 ? intentUrl.length : indexEnd;
+
+ var url = decodeURIComponent(intentUrl.substring(indexStart, indexEnd));
+ var realUrl = getRealLinkFromGoogleUrl(newURL(url));
+ if (!realUrl) {
+ return;
+ }
+ return intentUrl.substring(0, indexStart) +
+ encodeURIComponent(realUrl) +
+ intentUrl.substring(indexEnd);
+}
+
+/**
+ * Intercept the .href setter in the page so that the page can never change the
+ * URL to a tracking URL. Just intercepting mousedown/touchstart is not enough
+ * because e.g. on Google Maps, the page rewrites the URL in the contextmenu
+ * event at the bubbling event stage and then stops the event propagation. So
+ * there is no event-driven way to fix the URL. The DOMAttrModified event could
+ * be used, but the event is deprecated, so not a viable long-term solution.
+ */
+function setupAggresiveUglyLinkPreventer() {
+ // This content script runs as document_start, so we can have some assurance
+ // that the methods in the page are reliable.
+ var s = document.createElement('script');
+ if (getScriptCspNonce()) {
+ s.setAttribute('nonce', scriptCspNonce);
+ } else if (document.readyState !== 'complete' && needsCspNonce) {
+ // In Firefox, a page's CSP is enforced for content scripts, so we need
+ // to wait for the document to be loaded (we may be at document_start)
+ // and find a fitting CSP nonce.
+ findScriptCspNonce(setupAggresiveUglyLinkPreventer);
+ return;
+ }
+ s.textContent = '(' + function(getRealLinkFromGoogleUrl) {
+ var proto = HTMLAnchorElement.prototype;
+ // The link target can be changed in many ways, but let's only consider
+ // the .href attribute since it's probably the only used setter.
+ var hrefProp = Object.getOwnPropertyDescriptor(proto, 'href');
+ var hrefGet = Function.prototype.call.bind(hrefProp.get);
+ var hrefSet = Function.prototype.call.bind(hrefProp.set);
+
+ Object.defineProperty(proto, 'href', {
+ configurable: true,
+ enumerable: true,
+ get() {
+ return hrefGet(this);
+ },
+ set(v) {
+ hrefSet(this, v);
+ try {
+ v = getRealLinkFromGoogleUrl(this);
+ if (v) {
+ hrefSet(this, v);
+ }
+ } catch (e) {
+ // Not expected to happen, but don't break the setter if for
+ // some reason the (hostile) page broke the link APIs.
+ }
+ updateReferrerPolicy(this);
+ },
+ });
+ function replaceAMethod(methodName, methodFunc) {
+ // Overwrite the methods without triggering setters, because that
+ // may inadvertently overwrite the prototype, as observed in
+ // https://github.com/Rob--W/dont-track-me-google/issues/52#issuecomment-1596207655
+ Object.defineProperty(proto, methodName, {
+ configurable: true,
+ // All methods that we are overriding are not part of
+ // HTMLAnchorElement.prototype, but inherit.
+ enumerable: false,
+ writable: true,
+ value: methodFunc,
+ });
+ }
+
+ // proto inherits Element.prototype.setAttribute:
+ var setAttribute = Function.prototype.call.bind(proto.setAttribute);
+ replaceAMethod('setAttribute', function(name, value) {
+ // Attribute names are not case-sensitive, but weird capitalizations
+ // are unlikely, so only check all-lowercase and all-uppercase.
+ if (name === 'href' || name === 'HREF') {
+ this.href = value;
+ } else {
+ setAttribute(this, name, value);
+ }
+ });
+
+ // proto inherits EventTarget.prototype.dispatchEvent:
+ var aDispatchEvent = Function.prototype.apply.bind(proto.dispatchEvent);
+ replaceAMethod('dispatchEvent', function() {
+ updateReferrerPolicy(this);
+ return aDispatchEvent(this, arguments);
+ });
+
+ // proto inherits HTMLElement.prototype.click:
+ var aClick = Function.prototype.apply.bind(proto.click);
+ replaceAMethod('click', function() {
+ updateReferrerPolicy(this);
+ return aClick(this, arguments);
+ });
+
+ var rpProp = Object.getOwnPropertyDescriptor(proto, 'referrerPolicy');
+ var rpGet = Function.prototype.call.bind(rpProp.get);
+ var rpSet = Function.prototype.call.bind(rpProp.set);
+
+ var currentScript = document.currentScript;
+ var getReferrerPolicy = Object.getOwnPropertyDescriptor(
+ HTMLScriptElement.prototype,
+ 'referrerPolicy'
+ ).get.bind(currentScript);
+
+ function updateReferrerPolicy(a) {
+ try {
+ if (rpGet(a) === 'no-referrer') {
+ // "no-referrer" is more privacy-friendly than "origin".
+ return;
+ }
+ var referrerPolicy = getReferrerPolicy();
+ if (referrerPolicy) {
+ rpSet(a, referrerPolicy);
+ }
+ } catch (e) {
+ // Not expected to happen, but don't break callers if it happens
+ // anyway.
+ }
+ }
+ currentScript.dataset.jsEnabled = 1;
+ } + ')(' + getRealLinkFromGoogleUrl + ');';
+ callImmediatelyAndOnPreferenceUpdate(function forceNoReferrerChanged() {
+ // Send the desired referrerPolicy value to the injected script.
+ s.referrerPolicy = getReferrerPolicy();
+ });
+ (document.head || document.documentElement).appendChild(s);
+ s.remove();
+ if (!s.dataset.jsEnabled) {
+ cleanLinksWhenJsIsDisabled();
+ if (!needsCspNonce) {
+ needsCspNonce = true;
+ // This is not Firefox, but the script was blocked. Perhaps a CSP
+ // nonce is needed anyway.
+ findScriptCspNonce(function() {
+ if (scriptCspNonce) {
+ setupAggresiveUglyLinkPreventer();
+ }
+ });
+ }
+ } else {
+ // Scripts enabled (not blocked by CSP), run other inline scripts.
+ blockTrackingBeacons();
+ overwriteWindowOpen();
+
+ if (location.hostname === 'docs.google.com') {
+ // Google Docs have simple non-JS interfaces where the ugly links
+ // are hard-coded in the HTML. Remove them (#51).
+ // https://docs.google.com/document/d/.../mobilebasic
+ // https://docs.google.com/spreadsheets/d/.../htmlview
+ cleanLinksWhenJsIsDisabled();
+ }
+ }
+}
+
+// Block sendBeacon requests with destination /gen_204, because Google
+// asynchronously sends beacon requests in response to mouse events on links:
+// https://github.com/Rob--W/dont-track-me-google/issues/20
+//
+// This implementation also blocks other forms of tracking via gen_204 as a side
+// effect. That is not fully intentional, but given the lack of obvious ways to
+// discern such link-tracking events from others, I will block all of them.
+function blockTrackingBeacons() {
+ var s = document.createElement('script');
+ if (getScriptCspNonce()) {
+ s.setAttribute('nonce', scriptCspNonce);
+ }
+ s.textContent = '(' + function() {
+ var navProto = window.Navigator.prototype;
+ var navProtoSendBeacon = navProto.sendBeacon;
+ if (!navProtoSendBeacon) {
+ return;
+ }
+ var sendBeacon = Function.prototype.apply.bind(navProtoSendBeacon);
+
+ // Blocks the following:
+ // gen_204
+ // /gen_204
+ // https://www.google.com/gen_204
+ var isTrackingUrl = RegExp.prototype.test.bind(
+ /^(?:(?:https?:\/\/[^\/]+)?\/)?gen_204(?:[?#]|$)/);
+
+ navProto.sendBeacon = function(url, data) {
+ if (isTrackingUrl(url) && isNoPingEnabled()) {
+ // Lie that the data has been transmitted to avoid fallbacks.
+ return true;
+ }
+ return sendBeacon(this, arguments);
+ };
+
+ var currentScript = document.currentScript;
+ var getElementId = Object.getOwnPropertyDescriptor(
+ Element.prototype,
+ 'id'
+ ).get.bind(currentScript);
+ function isNoPingEnabled() {
+ try {
+ return getElementId() !== '_dtmg_do_not_touch_ping';
+ } catch (e) {
+ return true;
+ }
+ }
+ } + ')();';
+ callImmediatelyAndOnPreferenceUpdate(function nopingChanged() {
+ // Send the noping value to the injected script. The "id" property is
+ // mirrored and can have an arbitrary (string) value, so we use that:
+ s.id = noping ? '' : '_dtmg_do_not_touch_ping';
+ });
+ (document.head || document.documentElement).appendChild(s);
+ s.remove();
+}
+
+// Google sometimes uses window.open() to open ugly links.
+// https://github.com/Rob--W/dont-track-me-google/issues/18
+// https://github.com/Rob--W/dont-track-me-google/issues/41
+function overwriteWindowOpen() {
+ var s = document.createElement('script');
+ if (getScriptCspNonce()) {
+ s.setAttribute('nonce', scriptCspNonce);
+ }
+ s.textContent = '(' + function() {
+ var open = window.open;
+ window.open = function(url, windowName, windowFeatures) {
+ var isBlankUrl = !url || url === "about:blank";
+ try {
+ if (!isBlankUrl) {
+ var a = document.createElement('a');
+ // Triggers getRealLinkFromGoogleUrl via the href setter in
+ // setupAggresiveUglyLinkPreventer.
+ a.href = url;
+ url = a.href;
+ // The origin check exists to avoid adding "noreferrer" to
+ // same-origin popups. That implies noopener and causes
+ // https://github.com/Rob--W/dont-track-me-google/issues/43
+ // And allow any Google domain to support auth popups:
+ // https://github.com/Rob--W/dont-track-me-google/issues/45
+ // And don't bother editing the list if it already contains
+ // "opener" (it would be disabled by "noreferrer").
+ if (a.referrerPolicy && a.origin !== location.origin &&
+ !/\.google\.([a-z]+)$/.test(a.hostname) &&
+ !/\bopener|noreferrer/.test(windowFeatures)) {
+ if (windowFeatures) {
+ windowFeatures += ',';
+ } else {
+ windowFeatures = '';
+ }
+ windowFeatures += 'noreferrer';
+ }
+ }
+ } catch (e) {
+ // Not expected to happen, but don't break callers if it does.
+ }
+ var win = open(url, windowName, windowFeatures);
+ try {
+ if (isBlankUrl && win) {
+ // In Google Docs, sometimes a blank document is opened,
+ // and document.write is used to insert a redirector.
+ // https://github.com/Rob--W/dont-track-me-google/issues/41
+ var doc = win.document;
+ var docWrite = win.Function.prototype.call.bind(doc.write);
+ doc.write = function(markup) {
+ try {
+ markup = fixupDocMarkup(markup);
+ } catch (e) {
+ // Not expected, but don't break callers otherwise.
+ }
+ return docWrite(this, markup);
+ };
+ }
+ } catch (e) {
+ // Not expected to happen, but don't break callers if it does.
+ }
+ return win;
+ };
+ function fixupDocMarkup(html) {
+ html = html || '';
+ html += '';
+ return html.replace(
+ /]*http-equiv=(["']?)refresh\1[^>]*>/i,
+ function(m) {
+ var doc = new DOMParser().parseFromString(m, 'text/html');
+ var meta = doc.querySelector('meta[http-equiv=refresh]');
+ return meta && fixupMetaUrl(meta) || m;
+ });
+ }
+ function fixupMetaUrl(meta) {
+ var parts = /^(\d*;\s*url=)(.+)$/i.exec(meta.content);
+ if (!parts) {
+ return;
+ }
+ var metaPrefix = parts[1];
+ var url = parts[2];
+ var a = document.createElement('a');
+ // Triggers getRealLinkFromGoogleUrl via the href setter in
+ // setupAggresiveUglyLinkPreventer.
+ a.href = url;
+ url = a.href;
+ meta.content = metaPrefix + url;
+
+ var html = meta.outerHTML;
+ if (a.referrerPolicy) {
+ // Google appears to already append the no-referrer
+ // meta tag, but add one just in case it doesn't.
+ html = '' + html;
+ }
+ return html;
+ }
+ } + ')();';
+ (document.head || document.documentElement).appendChild(s);
+ s.remove();
+}
+
+function cleanLinksWhenJsIsDisabled() {
+ // When JavaScript is disabled, Google sets the "href" attribute's value to
+ // an ugly URL. Although the link is rewritten on click, we still need to
+ // rewrite the link even earlier because otherwise the ugly URL is shown in
+ // the tooltip upon hover.
+
+ if (document.readyState == 'complete') {
+ cleanAllLinks();
+ return;
+ }
+
+ // When JS is disabled, the links won't change after the document finishes
+ // loading. Until the DOM has finished loading, use the mouseover event to
+ // beautify links (the DOMContentLoaded may be delayed on slow networks).
+ document.addEventListener('mouseover', handleMouseOver);
+ document.addEventListener('DOMContentLoaded', function() {
+ document.removeEventListener('mouseover', handleMouseOver);
+ cleanAllLinks();
+ }, {once: true});
+
+ function cleanAllLinks() {
+ var as = document.querySelectorAll('a[href]');
+ for (var i = 0; i < as.length; ++i) {
+ var href = getRealLinkFromGoogleUrl(as[i]);
+ if (href) {
+ as[i].href = href;
+ }
+ }
+ }
+
+ function handleMouseOver(e) {
+ var a = e.target;
+ var href = a.href && getRealLinkFromGoogleUrl(a);
+ if (href) {
+ a.href = href;
+ }
+ }
+}
+
+function getScriptCspNonce() {
+ var scripts = document.querySelectorAll('script[nonce]');
+ for (var i = 0; i < scripts.length && !scriptCspNonce; ++i) {
+ scriptCspNonce = scripts[i].nonce;
+ }
+ return scriptCspNonce;
+}
+
+function findScriptCspNonce(callback) {
+ var timer;
+ function checkDOM() {
+ if (getScriptCspNonce() || document.readyState === 'complete') {
+ document.removeEventListener('DOMContentLoaded', checkDOM, true);
+ if (timer) {
+ clearTimeout(timer);
+ }
+ callback();
+ return;
+ }
+ timer = setTimeout(checkDOM, 50);
+ }
+ document.addEventListener('DOMContentLoaded', checkDOM, true);
+ checkDOM();
+}
+
+function newURL(href) {
+ try {
+ return new URL(href);
+ } catch (e) {
+ var a = document.createElement('a');
+ a.href = href;
+ return a;
+ }
+}
diff --git a/home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js b/home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js
new file mode 100644
index 0000000..025d961
--- /dev/null
+++ b/home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js
@@ -0,0 +1,984 @@
+// ==UserScript==
+// @name I don't care about cookies
+// @name:vi Tôi không quan tâm về cookie
+// @name:zh-CN 我不关心cookie
+// @name:zh-TW 我不關心cookie
+// @name:ja クッキーについては気にしない
+// @name:ru Я не забочусь о куки
+// @namespace http://tampermonkey.net/
+// @version 2025.01.03.2
+// @description Remove cookie warnings from almost all websites! Auto accept cookies and remove annoying cookie popups
+// @description:vi Loại bỏ cảnh báo cookie từ hầu hết các trang web! Tự động chấp nhận cookie và xóa các popup cookie phiền phức
+// @description:zh-CN 自动接受cookie并移除烦人的cookie弹窗
+// @description:zh-TW 自動接受cookie並移除煩人的cookie彈窗
+// @description:ru Автоматическое принятие cookie и удаление надоедливых всплывающих окон
+// @description:ja 自動承認cookieと迷惑なポップアップを削除
+// @author Yuusei
+// @match *://*/*
+// @grant none
+// @icon https://lh3.googleusercontent.com/sCLTYpGX0VcVootQ_XaFQ9saRIhVWu79ngSzY5eTZ5evRpJ_Q27OdvxA4RrOoZXP7Q4enFh-u6VhxObcJLfARw1g=s60
+// @compatible chrome
+// @compatible edge
+// @compatible firefox
+// @compatible safari
+// @run-at document-start
+// @license gpl-3.0-only
+// @downloadURL https://update.greasyfork.org/scripts/522645/I%20don%27t%20care%20about%20cookies.user.js
+// @updateURL https://update.greasyfork.org/scripts/522645/I%20don%27t%20care%20about%20cookies.meta.js
+// ==/UserScript==
+
+(function () {
+ 'use strict';
+
+ const CONSENT_TEXTS = {
+ en: ['accept', 'accept all', 'agree', 'continue', 'got it', 'reject all', 'decline', 'necessary only', 'required only', 'manage', 'customize'],
+ vi: ['chấp nhận', 'chấp nhận tất cả', 'đồng ý', 'tiếp tục', 'từ chối tất cả', 'từ chối', 'chỉ cần thiết', 'tùy chỉnh', 'quản lý', 'cho phép', 'đồng ý và tiếp tục', 'tôi đồng ý', 'xác nhận', 'tôi chấp nhận', 'đồng ý tất cả', 'chấp nhận và tiếp tục', 'cho phép tất cả'],
+ zh: ['接受', '接受全部', '同意', '继续', '拒绝全部', '拒绝', '仅必要', '管理', '自定义'],
+ ru: ['принять', 'принять все', 'согласен', 'продолжить', 'отклонить все', 'отклонить', 'только необходимые', 'настроить', 'управлять'],
+ ja: ['承認', '同意', '続ける', 'すべて拒否', '拒否', '必要のみ', 'カスタマイズ', '管理'],
+ de: ['akzeptieren', 'einverstanden', 'fortfahren', 'alle ablehnen', 'ablehnen', 'nur notwendige', 'anpassen', 'verwalten'],
+ fr: ['accepter', 'accepter tout', 'accepte', 'continuer', 'tout refuser', 'refuser', 'uniquement nécessaire', 'personnaliser', 'gérer'],
+ es: ['aceptar', 'acepto todo', 'acepto', 'continuar', 'rechazar todo', 'rechazar', 'solo necesario', 'personalizar', 'gestionar'],
+ it: ['accetta', 'accetto tutto', 'accetto', 'continua', 'rifiuta tutto', 'rifiuta', 'solo necessari', 'personalizza', 'gestisci'],
+ pl: ['akceptuj', 'akceptuj wszystko', 'zgadzam się', 'kontynuuj', 'odrzuć wszystko', 'odrzuć', 'tylko niezbędne', 'dostosuj', 'zarządzaj'],
+ nl: ['accepteren', 'accepteren', 'doorgaan', 'alles weigeren', 'weigeren', 'alleen noodzakelijk', 'aanpassen', 'beheren'],
+ ko: ['동의', '모두 동의', '계속하기', '모두 거부', '거부', '필수만', '설정', '관리'],
+ th: ['ยอมรับ', 'ยอมรับทั้งหมด', 'ตกลง', 'ปฏิเสธทั้งหมด', 'ปฏิเสธ', 'จำเป็นเท่านั้น', 'ตั้งค่า', 'จัดการ'],
+ id: ['setuju', 'setuju semua', 'lanjutkan', 'tolak semua', 'tolak', 'wajib saja', 'pengaturan', 'kelola'],
+ ms: ['terima', 'terima semua', 'teruskan', 'tolak semua', 'tolak', 'perlu sahaja', 'tetapan', 'urus'],
+ pt: ['aceitar', 'aceitar tudo', 'continuar', 'rejeitar tudo', 'rejeitar', 'necessário', 'configurar', 'gerir'],
+ sv: ['godkänn', 'godkänn alla', 'fortsätt', 'neka alla', 'neka', 'nödvändiga', 'inställningar', 'hantera'],
+ da: ['accepter', 'accepter alle', 'fortsæt', 'afvis alle', 'afvis', 'nødvendige', 'indstillinger', 'administrer'],
+ fi: ['hyväksy', 'hyväksy kaikki', 'jatka', 'hylkää kaikki', 'hylkää', 'välttämätön', 'asetukset', 'hallitse'],
+ 'zh-CN': ['接受', '接受全部', '同意', '继续', '我同意', '确定', '确认', '知道了', '好的', '拒绝全部', '拒绝', '仅必要', '设置', '自定义', '管理', '保存设置', '允许', '允许全部', '接受并继续', '同意并继续', '保存并继续'],
+ 'zh-TW': ['接受', '接受全部', '同意', '繼續', '我同意', '確定', '確認', '知道了', '好的', '拒絕全部', '拒絕', '僅必要', '設置', '自定義', '管理', '保存設置', '允許', '允許全部', '接受並繼續', '同意並繼續', '保存並繼續'],
+ ko: ['동의', '모두 동의', '수락', '계속하기', '확인', '거부', '거부하기', '필수만', '설정', '관리', '저장', '허용', '모두 허용'],
+ th: ['ยอมรับ', 'ยอมรับทั้งหมด', 'ตกลง', 'ดำเนินการต่อ', 'ปฏิเสธ', 'ปฏิเสธทั้งหมด', 'จำเป็นเท่านั้น', 'ตั้งค่า', 'จัดการ', 'บันทึก', 'อนุญาต', 'อนุญาตทั้งหมด'],
+ id: ['terima', 'terima semua', 'setuju', 'lanjutkan', 'tolak', 'tolak semua', 'wajib saja', 'pengaturan', 'kelola', 'simpan', 'izinkan', 'izinkan semua'],
+ ms: ['terima', 'terima semua', 'setuju', 'teruskan', 'tolak', 'tolak semua', 'perlu sahaja', 'tetapan', 'urus', 'simpan', 'benarkan', 'benarkan semua'],
+ };
+
+ function matchesConsentText(element) {
+ const text = element.textContent.toLowerCase();
+ const lang = document.documentElement.lang || 'en';
+ const texts = CONSENT_TEXTS[lang.split('-')[0]] || CONSENT_TEXTS['en'];
+ return texts.some(t => text.includes(t));
+ }
+
+ // Utility functions
+ function _sl(selector, container) {
+ return (container || document).querySelector(selector);
+ }
+
+ function _id(id) {
+ return document.getElementById(id);
+ }
+
+ function _ev(selector, container, full) {
+ return document.evaluate((typeof full == 'undefined' ? '//' : '') + selector, container || document, null, XPathResult.ANY_TYPE, null).iterateNext();
+ }
+
+ function _if(condition, ...selectors) {
+ return _sl(condition) ? _chain(...selectors) : false;
+ }
+
+ function _if_else(condition, if_selectors, else_selectors) {
+ if (_sl(condition)) return _chain(...if_selectors);
+
+ return _chain(...else_selectors);
+ }
+
+ function _chain(...selectors) {
+ let elements,
+ l = selectors.length;
+ let flagUnique = false,
+ flagOptional = false,
+ flagAllMatches = false;
+
+ for (let i = currentChainElement; i < l; i++) {
+ if (/^FLAG\:/.test(selectors[i])) {
+ selectors[i]
+ .split(':')[1]
+ .split(',')
+ .forEach(function (flag) {
+ if (flag == 'UNIQUE') flagUnique = true;
+ else if (flag == 'OPTIONAL') flagOptional = true;
+ else if (flag == 'REQUIRED') flagOptional = false;
+ else if (flag == 'ALL-MATCHES') flagAllMatches = true;
+ else if (flag == 'SINGLE-MATCH') flagAllMatches = false;
+ });
+
+ continue;
+ }
+
+ if (flagUnique) selectors[i] += selectors[i].startsWith('//') ? '[not(contains(@class, "' + classname + '"))]' : ':not(.' + classname + ')';
+
+ if (i == l - 1) return selectors[i];
+
+ elements = _sl(selectors[i], false, flagAllMatches);
+
+ if (!flagAllMatches) elements = elements ? [elements] : [];
+
+ if (!elements.length) {
+ if (flagOptional) {
+ currentChainElement++;
+ continue;
+ }
+
+ return false;
+ }
+
+ currentChainElement++;
+
+ elements.forEach(function (element) {
+ if (flagUnique) element.classList.add(classname);
+
+ if (element.nodeName == 'OPTION') element.selected = true;
+ else element.click();
+ });
+ }
+
+ return false;
+ }
+
+ function getItem(hostname) {
+ switch (hostname) {
+ case 'youtube.com':
+ case 'www.youtube.com':
+ return { strict: true, key: 'CONSENT', value: 'PENDING+999' };
+
+ case 'google.com':
+ case 'www.google.com':
+ return { strict: true, key: 'CONSENT', value: 'YES+' };
+
+ case 'twitter.com':
+ case 'www.twitter.com':
+ return { strict: false, key: 'twtr_cookie_consent', value: '1' };
+
+ case 'pepephone.com':
+ case 'lyricsbox.com':
+ return { strict: true, key: 'cookieconsent', value: '1111' };
+
+ case 'kontaktbazar.at':
+ case 'hoernews.de':
+ return { strict: false, key: 'cookieconsent_status', value: 'dismiss' };
+
+ case 'vodafoneziggo.nl':
+ return { strict: false, key: 'cookies-accepted', value: 'true' };
+ case 'frankfurt.de':
+ return { strict: false, key: 'cookieAccepted', value: 'needed---piwik' };
+ case 'hackerrank.com':
+ return { strict: false, key: 'show_cookie_banner', value: 'false' };
+
+ case 'facebook.com':
+ case 'www.facebook.com':
+ return { strict: true, key: 'datr', value: 'accepted' };
+
+ case 'instagram.com':
+ case 'www.instagram.com':
+ return { strict: true, key: 'ig_did', value: 'accepted' };
+
+ case 'linkedin.com':
+ case 'www.linkedin.com':
+ return { strict: false, key: 'lidc', value: 'accepted' };
+
+ case 'reddit.com':
+ case 'www.reddit.com':
+ return { strict: false, key: 'eu_cookie', value: '{"opted":true}' };
+
+ case 'tiktok.com':
+ case 'www.tiktok.com':
+ return { strict: true, key: 'tt_webid', value: 'accepted' };
+
+ case 'netflix.com':
+ case 'www.netflix.com':
+ return { strict: false, key: 'netflix-cookie-consent', value: 'accepted' };
+
+ case 'spotify.com':
+ case 'www.spotify.com':
+ return { strict: false, key: 'sp_dc', value: 'accepted' };
+
+ case 'amazon.com':
+ case 'www.amazon.com':
+ return { strict: false, key: 'amazon-cookie-consent', value: 'accepted' };
+
+ case 'pinterest.com':
+ case 'www.pinterest.com':
+ return { strict: false, key: '_pinterest_sess', value: 'accepted' };
+
+ case 'twitch.tv':
+ case 'www.twitch.tv':
+ return { strict: false, key: 'twitch_cookie_consent', value: 'accepted' };
+
+ case 'github.com':
+ case 'www.github.com':
+ return { strict: false, key: '_gh_sess', value: 'accepted' };
+
+ case 'medium.com':
+ case 'www.medium.com':
+ return { strict: false, key: 'medium_cookie_consent', value: 'accepted' };
+
+ case 'quora.com':
+ case 'www.quora.com':
+ return { strict: false, key: 'm-b', value: 'accepted' };
+
+ case 'stackoverflow.com':
+ case 'www.stackoverflow.com':
+ return { strict: false, key: 'acct', value: 'accepted' };
+
+ case 'microsoft.com':
+ case 'www.microsoft.com':
+ return { strict: false, key: 'MUID', value: 'accepted' };
+
+ case 'apple.com':
+ case 'www.apple.com':
+ return { strict: false, key: 'geo', value: 'accepted' };
+
+ case 'dropbox.com':
+ case 'www.dropbox.com':
+ return { strict: false, key: 'dbx-consent', value: 'accepted' };
+
+ case 'booking.com':
+ case 'www.booking.com':
+ return { strict: false, key: 'bkng_consent', value: 'accepted' };
+
+ case 'vnexpress.net':
+ case 'www.vnexpress.net':
+ return { strict: false, key: 'vnexpress_cookie_consent', value: 'accepted' };
+
+ case 'thanhnien.vn':
+ case 'www.thanhnien.vn':
+ return { strict: false, key: 'thanhnien_cookie', value: 'accepted' };
+
+ case 'tuoitre.vn':
+ case 'www.tuoitre.vn':
+ return { strict: false, key: 'tuoitre_cookie', value: 'accepted' };
+
+ case 'tiki.vn':
+ case 'www.tiki.vn':
+ return { strict: false, key: 'tiki_cookie', value: 'accepted' };
+
+ case 'shopee.vn':
+ case 'www.shopee.vn':
+ return { strict: false, key: 'shopee_cookie', value: 'accepted' };
+
+ case 'lazada.vn':
+ case 'www.lazada.vn':
+ return { strict: false, key: 'lzd_cookie', value: 'accepted' };
+
+ case 'sendo.vn':
+ case 'www.sendo.vn':
+ return { strict: false, key: 'sendo_cookie', value: 'accepted' };
+
+ case 'thegioididong.com':
+ case 'www.thegioididong.com':
+ return { strict: false, key: 'tgdd_cookie', value: 'accepted' };
+
+ case 'fptshop.com.vn':
+ case 'www.fptshop.com.vn':
+ return { strict: false, key: 'fpt_cookie', value: 'accepted' };
+
+ case 'cellphones.com.vn':
+ case 'www.cellphones.com.vn':
+ return { strict: false, key: 'cps_cookie', value: 'accepted' };
+
+ case 'aliexpress.com':
+ case 'www.aliexpress.com':
+ return { strict: false, key: 'aep_usuc_f', value: 'accepted' };
+
+ case 'ebay.com':
+ case 'www.ebay.com':
+ return { strict: false, key: 'ebay_cookie_consent', value: 'accepted' };
+
+ case 'coursera.org':
+ case 'www.coursera.org':
+ return { strict: false, key: 'coursera_cookie', value: 'accepted' };
+
+ case 'udemy.com':
+ case 'www.udemy.com':
+ return { strict: false, key: 'ud_cookie', value: 'accepted' };
+
+ case 'bachhoaxanh.com':
+ case 'www.bachhoaxanh.com':
+ return { strict: false, key: 'bhx_cookie', value: 'accepted' };
+
+ case 'dienmayxanh.com':
+ case 'www.dienmayxanh.com':
+ return { strict: false, key: 'dmx_cookie', value: 'accepted' };
+
+ case 'nguyenkim.com':
+ case 'www.nguyenkim.com':
+ return { strict: false, key: 'nk_cookie', value: 'accepted' };
+
+ case 'dantri.com.vn':
+ case 'www.dantri.com.vn':
+ return { strict: false, key: 'dantri_cookie', value: 'accepted' };
+
+ case 'vietnamnet.vn':
+ case 'www.vietnamnet.vn':
+ return { strict: false, key: 'vietnamnet_cookie', value: 'accepted' };
+
+ case '24h.com.vn':
+ case 'www.24h.com.vn':
+ return { strict: false, key: '24h_cookie', value: 'accepted' };
+
+ case 'vietcombank.com.vn':
+ case 'www.vietcombank.com.vn':
+ return { strict: false, key: 'vcb_cookie', value: 'accepted' };
+
+ case 'techcombank.com.vn':
+ case 'www.techcombank.com.vn':
+ return { strict: false, key: 'tcb_cookie', value: 'accepted' };
+
+ case 'mbbank.com.vn':
+ case 'www.mbbank.com.vn':
+ return { strict: false, key: 'mb_cookie', value: 'accepted' };
+
+ case 'amazon.co.jp':
+ case 'www.amazon.co.jp':
+ return { strict: false, key: 'amazon_jp_cookie', value: 'accepted' };
+
+ case 'rakuten.co.jp':
+ case 'www.rakuten.co.jp':
+ return { strict: false, key: 'rakuten_jp_cookie', value: 'accepted' };
+
+ case 'taobao.com':
+ case 'www.taobao.com':
+ return { strict: false, key: 'taobao_cookie', value: 'accepted' };
+
+ case 'line.me':
+ case 'www.line.me':
+ return { strict: false, key: 'line_cookie', value: 'accepted' };
+
+ case 'weibo.com':
+ case 'www.weibo.com':
+ return { strict: false, key: 'weibo_cookie', value: 'accepted' };
+
+ case 'kakao.com':
+ case 'www.kakao.com':
+ return { strict: false, key: 'kakao_cookie', value: 'accepted' };
+
+ case 'yahoo.co.jp':
+ case 'www.yahoo.co.jp':
+ return { strict: false, key: 'yahoo_jp_cookie', value: 'accepted' };
+
+ case 'naver.com':
+ case 'www.naver.com':
+ return { strict: false, key: 'naver_cookie', value: 'accepted' };
+
+ case 'baidu.com':
+ case 'www.baidu.com':
+ return { strict: false, key: 'baidu_cookie', value: 'accepted' };
+
+ case 'zalando.com':
+ case 'www.zalando.com':
+ return { strict: false, key: 'zalando_cookie', value: 'accepted' };
+
+ case 'asos.com':
+ case 'www.asos.com':
+ return { strict: false, key: 'asos_cookie', value: 'accepted' };
+
+ case 'zara.com':
+ case 'www.zara.com':
+ return { strict: false, key: 'zara_cookie', value: 'accepted' };
+
+ case 'tmall.com':
+ case 'www.tmall.com':
+ return { strict: false, key: 'tmall_cookie', value: 'accepted' };
+
+ case 'jd.com':
+ case 'www.jd.com':
+ return { strict: false, key: 'jd_cookie', value: 'accepted' };
+
+ case 'sina.com.cn':
+ case 'www.sina.com.cn':
+ return { strict: false, key: 'sina_cookie', value: 'accepted' };
+
+ case 'qq.com':
+ case 'www.qq.com':
+ return { strict: false, key: 'qq_cookie', value: 'accepted' };
+
+ case '163.com':
+ case 'www.163.com':
+ return { strict: false, key: 'netease_cookie', value: 'accepted' };
+
+ case 'sohu.com':
+ case 'www.sohu.com':
+ return { strict: false, key: 'sohu_cookie', value: 'accepted' };
+
+ case 'bilibili.com':
+ case 'www.bilibili.com':
+ return { strict: false, key: 'bilibili_cookie', value: 'accepted' };
+ }
+
+ const parts = hostname.split('.');
+ if (parts.length > 2) {
+ parts.shift();
+ return getItem(parts.join('.'));
+ }
+ return false;
+ }
+
+ function _parent(element) {
+ if (element && element.parentNode) return element.parentNode;
+ return false;
+ }
+
+ function _iframe(iframe_selector, selector) {
+ var e = _sl(iframe_selector);
+ return e ? _sl(selector, e.contentDocument || e.contentWindow.contentDocument) : e;
+ }
+
+ // Cookie consent handling logic
+ let searchPairs = {
+ '.vn-cookie-banner': ['.vn-cookie-banner__reject', '.vn-cookie-banner__customize'],
+ '.vn-cookie-notice': ['.vn-cookie-notice__reject', '.vn-cookie-notice__settings'],
+ '.vn-cookie-consent': ['.vn-cookie-consent__reject', '.vn-cookie-consent__customize'],
+ '.vn-cookie-popup': ['.vn-cookie-popup__reject', '.vn-cookie-popup__settings'],
+
+ '.shopee-cookie-banner': ['.shopee-cookie-banner__reject', '.shopee-cookie-banner__settings'],
+ '.lazada-cookie-notice': ['.lazada-cookie-notice__reject', '.lazada-cookie-notice__settings'],
+ '.tiki-cookie-popup': ['.tiki-cookie-popup__reject', '.tiki-cookie-popup__settings'],
+ '.sendo-cookie-consent': ['.sendo-cookie-consent__reject', '.sendo-cookie-consent__settings'],
+
+ '.vnexpress-cookie': ['.vnexpress-cookie__reject', '.vnexpress-cookie__settings'],
+ '.tuoitre-cookie': ['.tuoitre-cookie__reject', '.tuoitre-cookie__settings'],
+ '.thanhnien-cookie': ['.thanhnien-cookie__reject', '.thanhnien-cookie__settings'],
+ '.dantri-cookie': ['.dantri-cookie__reject', '.dantri-cookie__settings'],
+
+ '.tgdd-cookie-notice': ['.tgdd-cookie-notice__reject', '.tgdd-cookie-notice__settings'],
+ '.fpt-cookie-popup': ['.fpt-cookie-popup__reject', '.fpt-cookie-popup__settings'],
+ '.cps-cookie-consent': ['.cps-cookie-consent__reject', '.cps-cookie-consent__settings'],
+
+ '.vcb-cookie-notice': ['.vcb-cookie-notice__reject', '.vcb-cookie-notice__settings'],
+ '.tcb-cookie-popup': ['.tcb-cookie-popup__reject', '.tcb-cookie-popup__settings'],
+ '.mb-cookie-consent': ['.mb-cookie-consent__reject', '.mb-cookie-consent__settings'],
+
+ 'div[class*="consent"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
+ 'div[class*="notice"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
+ 'div[class*="popup"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
+ 'div[class*="banner"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
+ };
+
+ let searchGroups = [
+ '.qc-cmp2-summary-buttons button[mode="secondary"],\
+ .qc-cmp2-buttons-desktop > button:first-child,\
+ #didomi-popup .didomi-button-highlight:not([class*="paywall"]):not([class*="disagree"]),\
+ #rgpd_video .rgpd-mask a[data-rgpd-consent],\
+ .cli-barmodal-open #wt-cli-privacy-save-btn,\
+ .js--modal[style*="block"] .cookie-permission--accept-button,\
+ .gdpr-modal-rider .btn-cookieaccept,\
+ .js-cookiewall #sel-test-accept-cookies-button,\
+ #mpo[style*="block"] .submit.modal-privacy__btn[onclick*="privacyframe.accept"],\
+ .lightbox--cookie-consent .btn-cta,\
+ .lightbox.cookie-consent .cookie-consent-button-decline,\
+ .js-modal-gdpr.is-active .btn[data-level="2"],\
+ #CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection,\
+ #cookieNotificationModal.in .btn.accept-cookie,\
+ .has-ccwindow .cc-compliance .cc-dismiss,\
+ .ds2-cookie-disclaimer--slidedown .ds2-cookie-disclaimer-js--submit,\
+ #mdlCookieCompliance.in .cookieClose,\
+ #cookieModal.in .js-acceptDefaultCookie,\
+ .c-cookiebutton .c-cookiebutton__close,\
+ #normativa_cookies.in .btn,\
+ #cookiewall.in .btn-primary,\
+ .outerCookieBar .EuCookieBar__cookieButton,\
+ #TOS-POPUP .rhododendron-popup__button--agree,\
+ #cookie-wall #accept-cookies,\
+ #popup-wrapper .button[href*="/cookies.consent.php"],\
+ .reveal.cookies[style*="block"] button[click*="aceptaCookies"],\
+ .mnd-cookie-modal[style*="block"] .btn.is--primary,\
+ .cookieHandler.cookieHandler--modalOpen #acceptAllCookies,\
+ .gdpr-modal--active .btn--primary,\
+ #dpi-banner:not(.hidden) #btn-agree-cookie,\
+ .gh-banner.gh-banner-active #gh-cookiebanner-close,\
+ #mrktpref.notification-bar .btn-success,\
+ #PopinGDPRCookie[style*="block"] .jsbd-popin-ok,\
+ #modal-rodo.in .btn-primary,\
+ .cookie-compliance-modal.in .btn-primary,\
+ .cookieconsent.show .btn[data-dm*="accept"],\
+ .cookie-wall-modal.in .btn.ja,\
+ #modal-consent.in .modal-consent-accept,\
+ .rodo #cookies.in .btn-primary,\
+ .js-cookie-alert.in .js-cookie-alert-accept,\
+ #modal_gdpr_intro_popup.in #gdpr-modal-btn-ok-agree,\
+ #consentButtonContainer > button[onclick*="sendAndRedirect"],\
+ #eu-consent[style*="block"] .btn.yes,\
+ .modal--gdpr.is-open .js-gdpr-consent,\
+ #cookiePopupModal.in .cookiepopup-agreed,\
+ .polityka-cookie-rodo[style*="block"] .button-zgoda,\
+ .ui-dialog.consent-modal[style*="block"] .js-btn-agree,\
+ #up-cookie.active .button[onclick*="setCookiePreference"],\
+ .RodoModal.in .close,\
+ .consent-popup form[action*="cookie-consent"] .consent-popup__button,\
+ #consent form[action*="cookie-consent"] .one-btn,\
+ #cookiewall-wrapper .button[href*="accept"],\
+ #cookieChoiceButtonAccept,\
+ .mod-cookie-consent[style*="block"] .btn-all-cookies,\
+ .c-layer--consent .layer-button--accept,\
+ .button.button-ok[onclick*="acceptAVG"],\
+ #meredithGdprConsentFormButton,\
+ #advanced-cookie-modal.in .cookie-accept,\
+ .show-modal .cookie-settings-manager-container .initial-dialog .js-accept-button,\
+ .cookie-settings-manager-container .initial-dialog[style*="block"] .js-accept-button,\
+ .gdprLightbox[data-module="gdprLightbox"] ._type_gdpr_agree,\
+ .cookie.showa #Row1_Column1_Cell1_CookieSettings_AdvancedSaveAccept,\
+ #core-cookie-container[style*="block"] .btn--agree,\
+ .cookie-consent-modal._show .action-primary,\
+ #dsgvoModal.show #dsvgo-banner__button,\
+ .basicLightbox--visible #accept-all-gdpr,\
+ #gdpr-modal.in .gdpr-modal__btn--accept,\
+ .cookiehint .btn.cookieagree,\
+ #cookiealert .modal.in .btn[href*="accept"],\
+ #lml-data-consent-accept,\
+ #CBCookieMsg.in .btn[onclick*="approveCookies"],\
+ #cookiewall-container .button[name="submit"],\
+ #cookie_disclaimer.in .cookie_disclaimer_button,\
+ .m-cookie.iziModal[style*="block"] .m-cookie__save2.button,\
+ kamino-cookie-policy .mat-raised-button,\
+ #surbma-gpga-modal[style*="block"] button,\
+ #GDPR.overlayBox .menuButton,\
+ #cookiebar .cookie-selection-button.accept,\
+ .modal.in .btn.close-modal-cookie,\
+ #consent-module[style*="block"] #consent-module-text-button,\
+ .modal #consentButton,\
+ #consent-modal[style*="block"] .lm_modal__modal__content__body__buttons__ok,\
+ .cookiesOverlay3Box #cookiesConsentOK,\
+ .bemCookieOverlay--activePopup .bemCookieOverlay__btn--save,\
+ #root main ~ div [data-gi-selector="reject-all-cookies"] ~ div a,\
+ .cookies-management .cookies-deny,\
+ .offcanvas.is-open .js-offcanvas-cookie-submit,\
+ .force--consent.show--consent #cs_save__btn,\
+ .force--consent.show--consent #s-sv-bn,\
+ #cookieNoticeModal.vrm-reveal[style*="block"] .vrm-reveal__icon--close',
+ '.cookie-banner .cookie-banner__buttons .cookie-banner__button--reject,\
+ .cookie-consent-banner .cookie-consent-banner__reject,\
+ .cookie-notification .cookie-notification__buttons .cookie-notification__reject,\
+ .cookie-policy-banner .cookie-policy-banner__buttons .cookie-policy-banner__reject,\
+ .cookie-warning .cookie-warning__buttons .cookie-warning__reject,\
+ .cookie-notice .cookie-notice__buttons .cookie-notice__reject,\
+ .cookie-alert .cookie-alert__buttons .cookie-alert__reject,\
+ .cookie-popup .cookie-popup__buttons .cookie-popup__reject,\
+ .cookie-modal .cookie-modal__buttons .cookie-modal__reject,\
+ .cookie-dialog .cookie-dialog__buttons .cookie-dialog__reject,\
+ .gdpr-banner .gdpr-banner__buttons .gdpr-banner__reject,\
+ .gdpr-modal .gdpr-modal__buttons .gdpr-modal__reject,\
+ .gdpr-notice .gdpr-notice__buttons .gdpr-notice__reject,\
+ .gdpr-popup .gdpr-popup__buttons .gdpr-popup__reject,\
+ .gdpr-dialog .gdpr-dialog__buttons .gdpr-dialog__reject,\
+ .privacy-banner .privacy-banner__buttons .privacy-banner__reject,\
+ .privacy-modal .privacy-modal__buttons .privacy-modal__reject,\
+ .privacy-notice .privacy-notice__buttons .privacy-notice__reject,\
+ .privacy-popup .privacy-popup__buttons .privacy-popup__reject,\
+ .privacy-dialog .privacy-dialog__buttons .privacy-dialog__reject',
+
+ '.consent-banner .consent-banner__buttons .consent-banner__reject,\
+ .consent-modal .consent-modal__buttons .consent-modal__reject,\
+ .consent-notice .consent-notice__buttons .consent-notice__reject,\
+ .consent-popup .consent-popup__buttons .consent-popup__reject,\
+ .consent-dialog .consent-dialog__buttons .consent-dialog__reject,\
+ .tracking-banner .tracking-banner__buttons .tracking-banner__reject,\
+ .tracking-modal .tracking-modal__buttons .tracking-modal__reject,\
+ .tracking-notice .tracking-notice__buttons .tracking-notice__reject,\
+ .tracking-popup .tracking-popup__buttons .tracking-popup__reject,\
+ .tracking-dialog .tracking-dialog__buttons .tracking-dialog__reject',
+
+ '.cookie-settings-modal .cookie-settings__reject,\
+ .cookie-settings-modal .cookie-settings__customize,\
+ .cookie-preferences-modal .cookie-preferences__reject,\
+ .cookie-preferences-modal .cookie-preferences__customize,\
+ .cookie-manager-modal .cookie-manager__reject,\
+ .cookie-manager-modal .cookie-manager__customize,\
+ .cookie-control-modal .cookie-control__reject,\
+ .cookie-control-modal .cookie-control__customize,\
+ .cookie-options-modal .cookie-options__reject,\
+ .cookie-options-modal .cookie-options__customize',
+
+ '.data-privacy-modal .data-privacy__reject,\
+ .data-privacy-modal .data-privacy__customize,\
+ .data-protection-modal .data-protection__reject,\
+ .data-protection-modal .data-protection__customize,\
+ .data-consent-modal .data-consent__reject,\
+ .data-consent-modal .data-consent__customize,\
+ .data-settings-modal .data-settings__reject,\
+ .data-settings-modal .data-settings__customize,\
+ .data-preferences-modal .data-preferences__reject,\
+ .data-preferences-modal .data-preferences__customize',
+
+ '.privacy-manager-modal .privacy-manager__reject,\
+ .privacy-manager-modal .privacy-manager__customize,\
+ .privacy-settings-modal .privacy-settings__reject,\
+ .privacy-settings-modal .privacy-settings__customize,\
+ .privacy-options-modal .privacy-options__reject,\
+ .privacy-options-modal .privacy-options__customize,\
+ .privacy-control-modal .privacy-control__reject,\
+ .privacy-control-modal .privacy-control__customize,\
+ .privacy-preferences-modal .privacy-preferences__reject,\
+ .privacy-preferences-modal .privacy-preferences__customize',
+
+ '.consent-manager-modal .consent-manager__reject,\
+ .consent-manager-modal .consent-manager__customize,\
+ .consent-settings-modal .consent-settings__reject,\
+ .consent-settings-modal .consent-settings__customize,\
+ .consent-options-modal .consent-options__reject,\
+ .consent-options-modal .consent-options__customize,\
+ .consent-control-modal .consent-control__reject,\
+ .consent-control-modal .consent-control__customize,\
+ .consent-preferences-modal .consent-preferences__reject,\
+ .consent-preferences-modal .consent-preferences__customize',
+
+ '.tracking-manager-modal .tracking-manager__reject,\
+ .tracking-manager-modal .tracking-manager__customize,\
+ .tracking-settings-modal .tracking-settings__reject,\
+ .tracking-settings-modal .tracking-settings__customize,\
+ .tracking-options-modal .tracking-options__reject,\
+ .tracking-options-modal .tracking-options__customize,\
+ .tracking-control-modal .tracking-control__reject,\
+ .tracking-control-modal .tracking-control__customize,\
+ .tracking-preferences-modal .tracking-preferences__reject,\
+ .tracking-preferences-modal .tracking-preferences__customize',
+
+ '.gdpr-manager-modal .gdpr-manager__reject,\
+ .gdpr-manager-modal .gdpr-manager__customize,\
+ .gdpr-settings-modal .gdpr-settings__reject,\
+ .gdpr-settings-modal .gdpr-settings__customize,\
+ .gdpr-options-modal .gdpr-options__reject,\
+ .gdpr-options-modal .gdpr-options__customize,\
+ .gdpr-control-modal .gdpr-control__reject,\
+ .gdpr-control-modal .gdpr-control__customize,\
+ .gdpr-preferences-modal .gdpr-preferences__reject,\
+ .gdpr-preferences-modal .gdpr-preferences__customize',
+
+ 'div[class*="cookie-banner"] button[class*="reject"],\
+ div[class*="cookie-banner"] button[class*="decline"],\
+ div[class*="cookie-banner"] button[class*="settings"],\
+ div[id*="cookie-banner"] button[class*="reject"],\
+ div[id*="cookie-banner"] button[class*="decline"],\
+ div[id*="cookie-banner"] button[class*="settings"]',
+
+ 'div[class*="cookie-consent"] button[class*="reject"],\
+ div[class*="cookie-consent"] button[class*="decline"],\
+ div[class*="cookie-consent"] button[class*="settings"],\
+ div[id*="cookie-consent"] button[class*="reject"],\
+ div[id*="cookie-consent"] button[class*="decline"],\
+ div[id*="cookie-consent"] button[class*="settings"]',
+
+ 'div[class*="cookie-notice"] button[class*="reject"],\
+ div[class*="cookie-notice"] button[class*="decline"],\
+ div[class*="cookie-notice"] button[class*="settings"],\
+ div[id*="cookie-notice"] button[class*="reject"],\
+ div[id*="cookie-notice"] button[class*="decline"],\
+ div[id*="cookie-notice"] button[class*="settings"]',
+
+ '[data-*="cookie"] button[data-*="reject"],\
+ [data-*="cookie"] button[data-*="decline"],\
+ [data-*="cookie"] button[data-*="settings"],\
+ [data-*="gdpr"] button[data-*="reject"],\
+ [data-*="gdpr"] button[data-*="decline"],\
+ [data-*="gdpr"] button[data-*="settings"]',
+
+ 'div[class*="cookie-layer"] button[class*="reject"],\
+ div[class*="cookie-layer"] button[class*="decline"],\
+ div[class*="cookie-layer"] button[class*="settings"],\
+ div[id*="cookie-layer"] button[class*="reject"],\
+ div[id*="cookie-layer"] button[class*="decline"],\
+ div[id*="cookie-layer"] button[class*="settings"]',
+
+ 'div[class*="cookie-section"] button[class*="reject"],\
+ div[class*="cookie-section"] button[class*="decline"],\
+ div[class*="cookie-section"] button[class*="settings"],\
+ div[id*="cookie-section"] button[class*="reject"],\
+ div[id*="cookie-section"] button[class*="decline"],\
+ div[id*="cookie-section"] button[class*="settings"]',
+
+ 'div[class*="cookie-container"] button[class*="reject"],\
+ div[class*="cookie-container"] button[class*="decline"],\
+ div[class*="cookie-container"] button[class*="settings"],\
+ div[id*="cookie-container"] button[class*="reject"],\
+ div[id*="cookie-container"] button[class*="decline"],\
+ div[id*="cookie-container"] button[class*="settings"]',
+
+ '[data-purpose*="cookie"] button[data-purpose*="reject"],\
+ [data-purpose*="cookie"] button[data-purpose*="decline"],\
+ [data-purpose*="cookie"] button[data-purpose*="settings"],\
+ [data-ref*="cookie"] button[data-ref*="reject"],\
+ [data-ref*="cookie"] button[data-ref*="decline"],\
+ [data-ref*="cookie"] button[data-ref*="settings"]',
+
+ '[id*="cookie-manager"] button[id*="reject"],\
+ [id*="cookie-manager"] button[id*="decline"],\
+ [id*="cookie-manager"] button[id*="settings"],\
+ [id*="cookie-control"] button[id*="reject"],\
+ [id*="cookie-control"] button[id*="decline"],\
+ [id*="cookie-control"] button[id*="settings"]',
+
+ 'div[class*="vn-cookie"] button[class*="reject"],\
+ div[class*="vn-cookie"] button[class*="decline"],\
+ div[class*="vn-cookie"] button[class*="settings"],\
+ div[id*="vn-cookie"] button[class*="reject"],\
+ div[id*="vn-cookie"] button[class*="decline"],\
+ div[id*="vn-cookie"] button[class*="settings"]',
+
+ 'div[class*="ecommerce"] button[class*="cookie-reject"],\
+ div[class*="ecommerce"] button[class*="cookie-decline"],\
+ div[class*="ecommerce"] button[class*="cookie-settings"],\
+ div[id*="ecommerce"] button[class*="cookie-reject"],\
+ div[id*="ecommerce"] button[class*="cookie-decline"],\
+ div[id*="ecommerce"] button[class*="cookie-settings"]',
+
+ 'div[class*="news"] button[class*="cookie-reject"],\
+ div[class*="news"] button[class*="cookie-decline"],\
+ div[class*="news"] button[class*="cookie-settings"],\
+ div[id*="news"] button[class*="cookie-reject"],\
+ div[id*="news"] button[class*="cookie-decline"],\
+ div[id*="news"] button[class*="cookie-settings"]',
+
+ 'div[class*="retail"] button[class*="cookie-reject"],\
+ div[class*="retail"] button[class*="cookie-decline"],\
+ div[class*="retail"] button[class*="cookie-settings"],\
+ div[id*="retail"] button[class*="cookie-reject"],\
+ div[id*="retail"] button[class*="cookie-decline"],\
+ div[id*="retail"] button[class*="cookie-settings"]',
+
+ 'div[class*="gdpr"] button[class*="reject"],\
+ div[class*="gdpr"] button[class*="decline"],\
+ div[class*="gdpr"] button[class*="settings"],\
+ div[id*="gdpr"] button[class*="reject"],\
+ div[id*="gdpr"] button[class*="decline"],\
+ div[id*="gdpr"] button[class*="settings"]',
+
+ 'div[class*="privacy"] button[class*="reject"],\
+ div[class*="privacy"] button[class*="decline"],\
+ div[class*="privacy"] button[class*="settings"],\
+ div[id*="privacy"] button[class*="reject"],\
+ div[id*="privacy"] button[class*="decline"],\
+ div[id*="privacy"] button[class*="settings"]',
+
+ 'div[class*="bank"] button[class*="cookie-reject"],\
+ div[class*="bank"] button[class*="cookie-decline"],\
+ div[class*="bank"] button[class*="cookie-settings"],\
+ div[id*="bank"] button[class*="cookie-reject"],\
+ div[id*="bank"] button[class*="cookie-decline"],\
+ div[id*="bank"] button[class*="cookie-settings"]',
+
+ 'div[class*="consent"] button[class*="reject"],\
+ div[class*="consent"] button[class*="decline"],\
+ div[class*="consent"] button[class*="settings"],\
+ div[id*="consent"] button[class*="reject"],\
+ div[id*="consent"] button[class*="decline"],\
+ div[id*="consent"] button[class*="settings"]',
+
+ 'div[class*="notice"] button[class*="reject"],\
+ div[class*="notice"] button[class*="decline"],\
+ div[class*="notice"] button[class*="settings"],\
+ div[id*="notice"] button[class*="reject"],\
+ div[id*="notice"] button[class*="decline"],\
+ div[id*="notice"] button[class*="settings"]',
+
+ 'div[class*="popup"] button[class*="reject"],\
+ div[class*="popup"] button[class*="decline"],\
+ div[class*="popup"] button[class*="settings"],\
+ div[id*="popup"] button[class*="reject"],\
+ div[id*="popup"] button[class*="decline"],\
+ div[id*="popup"] button[class*="settings"]',
+
+ 'div[class*="eu-cookie-banner"] button[class*="reject"],\
+ div[class*="eu-cookie-banner"] button[class*="settings"]',
+
+ 'div[class*="gdpr-notice"] button[class*="reject"],\
+ div[class*="gdpr-notice"] button[class*="settings"]',
+
+ 'div[class*="privacy-consent"] button[class*="reject"],\
+ div[class*="privacy-consent"] button[class*="settings"]',
+
+ 'div[class*="asia"] button[class*="cookie-reject"],\
+ div[class*="asia"] button[class*="cookie-decline"],\
+ div[class*="asia"] button[class*="cookie-settings"]',
+
+ 'div[class*="europe"] button[class*="cookie-reject"],\
+ div[class*="europe"] button[class*="cookie-decline"],\
+ div[class*="europe"] button[class*="cookie-settings"]',
+
+ 'div[class*="global"] button[class*="cookie-reject"],\
+ div[class*="global"] button[class*="cookie-decline"],\
+ div[class*="global"] button[class*="cookie-settings"]',
+
+ 'div[class*="america"] button[class*="cookie-reject"],\
+ div[class*="america"] button[class*="cookie-decline"],\
+ div[class*="america"] button[class*="cookie-settings"]',
+
+ 'div[class*="oceania"] button[class*="cookie-reject"],\
+ div[class*="oceania"] button[class*="cookie-decline"],\
+ div[class*="oceania"] button[class*="cookie-settings"]',
+ ];
+
+ let currentChainElement = 0;
+ const classname = Math.random()
+ .toString(36)
+ .replace(/[^a-z]+/g, '');
+
+ // Search loop function
+ let searchGroupsLength = searchGroups.length,
+ searchPairsKeys = Object.keys(searchPairs),
+ searchPairsJoinedKeys = searchPairsKeys.join(','),
+ timeoutDuration = 300;
+
+ function querySelectorAllShadowRoot(selector, root = document) {
+ const elements = [];
+ const findElements = node => {
+ if (node.shadowRoot) {
+ node.shadowRoot.querySelectorAll(selector).forEach(el => elements.push(el));
+ node.shadowRoot.querySelectorAll('*').forEach(findElements);
+ }
+ };
+ root.querySelectorAll('*').forEach(findElements);
+ return elements;
+ }
+
+ function searchLoop(counter) {
+ if (document.cookie.indexOf('cookie_consent') !== -1) {
+ return;
+ }
+
+ const dynamicTimeout = Math.min(timeoutDuration * (counter + 1), 2000);
+
+ setTimeout(function () {
+ document.querySelectorAll(searchPairsJoinedKeys).forEach(function (box) {
+ searchPairsKeys.forEach(function (selector) {
+ if (box.matches(selector)) {
+ const shadowElements = querySelectorAllShadowRoot(searchPairs[selector].join(','), box);
+ shadowElements.forEach(button => {
+ if (button.click && !button.classList.contains(classname)) {
+ button.classList.add(classname);
+
+ if (typeof chrome == 'object' && chrome.runtime) chrome.runtime.sendMessage({ command: 'cookie_warning_dismissed', url: document.location.href });
+
+ button.click();
+
+ if (selector != '.message-container' && button.getAttribute('href') != '#cookieman-settings')
+ setTimeout(function () {
+ if (button) button.click();
+ }, 500);
+
+ timeoutDuration += 500;
+ }
+ });
+ }
+ });
+ });
+
+ document.querySelectorAll(searchGroups[counter % searchGroupsLength]).forEach(function (element) {
+ if (element.click && !element.classList.contains(classname)) {
+ element.classList.add(classname);
+
+ if (typeof chrome == 'object' && chrome.runtime) chrome.runtime.sendMessage({ command: 'cookie_warning_dismissed', url: document.location.href });
+
+ element.click();
+
+ if (element.getAttribute('aria-pressed') != 'true')
+ setTimeout(function () {
+ if (element) element.click();
+ }, 500);
+
+ timeoutDuration += 500;
+ }
+ });
+
+ if (counter < 100 * searchGroupsLength) {
+ searchLoop(counter + 1);
+ }
+ }, dynamicTimeout);
+ }
+
+ // Embeds handling
+ function handleEmbeds() {
+ var l = document.location,
+ is_audioboom = false,
+ is_dailymotion = false,
+ is_dailybuzz = false,
+ is_playerclipslaliga = false;
+
+ switch (l.hostname) {
+ case 'embeds.audioboom.com':
+ is_audioboom = true;
+ break;
+
+ case 'dailymotion.com':
+ case 'www.dailymotion.com':
+ is_dailymotion = l.pathname.indexOf('/embed') === 0;
+ break;
+
+ case 'geo.dailymotion.com':
+ is_dailymotion = l.pathname.indexOf('/player') === 0;
+ break;
+
+ case 'dailybuzz.nl':
+ is_dailybuzz = l.pathname.indexOf('/buzz/embed') === 0;
+ break;
+
+ case 'playerclipslaliga.tv':
+ is_playerclipslaliga = true;
+ break;
+ }
+
+ function searchEmbeds() {
+ setTimeout(function () {
+ if (is_audioboom) {
+ document.querySelectorAll('div[id^="cookie-modal"] .modal[style*="block"] .btn.mrs:not(.' + classname + ')').forEach(function (button) {
+ button.className += ' ' + classname;
+ button.click();
+ });
+ } else if (is_dailymotion) {
+ document.querySelectorAll('.np_DialogConsent-accept:not(.' + classname + '), .consent_screen-accept:not(.' + classname + ')').forEach(function (button) {
+ button.className += ' ' + classname;
+ button.click();
+ });
+ } else if (is_dailybuzz) {
+ document.querySelectorAll('#ask-consent #accept:not(.' + classname + ')').forEach(function (button) {
+ button.className += ' ' + classname;
+ button.click();
+ });
+ } else if (is_playerclipslaliga) {
+ document.querySelectorAll('#cookies button[onclick*="saveCookiesSelection"]:not(.' + classname + ')').forEach(function (button) {
+ button.className += ' ' + classname;
+ button.click();
+ });
+ } else {
+ return;
+ }
+
+ searchEmbeds();
+ }, 1000);
+ }
+
+ searchEmbeds();
+ }
+
+ // Initialize
+ var start = setInterval(function () {
+ var html = document.querySelector('html');
+
+ if (!html || /idc0_350/.test(html.className)) return;
+
+ clearInterval(start);
+
+ html.className += ' idc0_350';
+ searchLoop(0);
+ handleEmbeds();
+ }, 500);
+
+ var hostname = document.location.hostname.replace(/^w{2,3}\d*\./i, ''),
+ items = getItem(hostname);
+
+ if (items) {
+ (items instanceof Array ? items : [items]).forEach(function (item) {
+ let value = localStorage.getItem(item.key);
+ if (value == null || (item.strict && value != item.value)) {
+ localStorage.setItem(item.key, item.value);
+ counter++;
+ }
+ });
+
+ if (counter > 0) document.location.reload();
+ }
+})();
diff --git a/home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js b/home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js
new file mode 100644
index 0000000..50f3eff
--- /dev/null
+++ b/home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js
@@ -0,0 +1,704 @@
+// ==UserScript==
+// @name Return YouTube Dislike
+// @namespace https://www.returnyoutubedislike.com/
+// @homepage https://www.returnyoutubedislike.com/
+// @version 3.1.5
+// @encoding utf-8
+// @description Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/
+// @icon https://github.com/Anarios/return-youtube-dislike/raw/main/Icons/Return%20Youtube%20Dislike%20-%20Transparent.png
+// @author Anarios & JRWR
+// @match *://*.youtube.com/*
+// @exclude *://music.youtube.com/*
+// @exclude *://*.music.youtube.com/*
+// @compatible chrome
+// @compatible firefox
+// @compatible opera
+// @compatible safari
+// @compatible edge
+// @grant GM.xmlHttpRequest
+// @connect youtube.com
+// @grant GM_addStyle
+// @run-at document-end
+// @downloadURL https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.user.js
+// @updateURL https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.meta.js
+// ==/UserScript==
+
+const extConfig = {
+ // BEGIN USER OPTIONS
+ // You may change the following variables to allowed values listed in the corresponding brackets (* means default). Keep the style and keywords intact.
+ showUpdatePopup: false, // [true, false*] Show a popup tab after extension update (See what's new)
+ disableVoteSubmission: false, // [true, false*] Disable like/dislike submission (Stops counting your likes and dislikes)
+ disableLogging: true, // [true*, false] Disable Logging API Response in JavaScript Console.
+ coloredThumbs: false, // [true, false*] Colorize thumbs (Use custom colors for thumb icons)
+ coloredBar: false, // [true, false*] Colorize ratio bar (Use custom colors for ratio bar)
+ colorTheme: "classic", // [classic*, accessible, neon] Color theme (red/green, blue/yellow, pink/cyan)
+ numberDisplayFormat: "compactShort", // [compactShort*, compactLong, standard] Number format (For non-English locale users, you may be able to improve appearance with a different option. Please file a feature request if your locale is not covered)
+ numberDisplayRoundDown: true, // [true*, false] Round down numbers (Show rounded down numbers)
+ tooltipPercentageMode: "none", // [none*, dash_like, dash_dislike, both, only_like, only_dislike] Mode of showing percentage in like/dislike bar tooltip.
+ numberDisplayReformatLikes: false, // [true, false*] Re-format like numbers (Make likes and dislikes format consistent)
+ rateBarEnabled: false, // [true, false*] Enables ratio bar under like/dislike buttons
+ // END USER OPTIONS
+};
+
+const LIKED_STATE = "LIKED_STATE";
+const DISLIKED_STATE = "DISLIKED_STATE";
+const NEUTRAL_STATE = "NEUTRAL_STATE";
+let previousState = 3; //1=LIKED, 2=DISLIKED, 3=NEUTRAL
+let likesvalue = 0;
+let dislikesvalue = 0;
+let preNavigateLikeButton = null;
+
+let isMobile = location.hostname == "m.youtube.com";
+let isShorts = () => location.pathname.startsWith("/shorts");
+let mobileDislikes = 0;
+function cLog(text, subtext = "") {
+ if (!extConfig.disableLogging) {
+ subtext = subtext.trim() === "" ? "" : `(${subtext})`;
+ console.log(`[Return YouTube Dislikes] ${text} ${subtext}`);
+ }
+}
+
+function isInViewport(element) {
+ const rect = element.getBoundingClientRect();
+ const height = innerHeight || document.documentElement.clientHeight;
+ const width = innerWidth || document.documentElement.clientWidth;
+ return (
+ // When short (channel) is ignored, the element (like/dislike AND short itself) is
+ // hidden with a 0 DOMRect. In this case, consider it outside of Viewport
+ !(rect.top == 0 && rect.left == 0 && rect.bottom == 0 && rect.right == 0) &&
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= height &&
+ rect.right <= width
+ );
+}
+
+function getButtons() {
+ if (isShorts()) {
+ let elements = document.querySelectorAll(
+ isMobile ? "ytm-like-button-renderer" : "#like-button > ytd-like-button-renderer",
+ );
+ for (let element of elements) {
+ if (isInViewport(element)) {
+ return element;
+ }
+ }
+ }
+ if (isMobile) {
+ return (
+ document.querySelector(".slim-video-action-bar-actions .segmented-buttons") ??
+ document.querySelector(".slim-video-action-bar-actions")
+ );
+ }
+ if (document.getElementById("menu-container")?.offsetParent === null) {
+ return (
+ document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div") ??
+ document.querySelector("ytd-menu-renderer.ytd-video-primary-info-renderer > div")
+ );
+ } else {
+ return document.getElementById("menu-container")?.querySelector("#top-level-buttons-computed");
+ }
+}
+
+function getDislikeButton() {
+ if (getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER") {
+ if (getButtons().children[0].children[1] === undefined) {
+ return document.querySelector("#segmented-dislike-button");
+ } else {
+ return getButtons().children[0].children[1];
+ }
+ } else {
+ if (getButtons().querySelector("segmented-like-dislike-button-view-model")) {
+ const dislikeViewModel = getButtons().querySelector("dislike-button-view-model");
+ if (!dislikeViewModel) cLog("Dislike button wasn't added to DOM yet...");
+ return dislikeViewModel;
+ } else {
+ return getButtons().children[1];
+ }
+ }
+}
+
+function getLikeButton() {
+ return getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER"
+ ? document.querySelector("#segmented-like-button") !== null
+ ? document.querySelector("#segmented-like-button")
+ : getButtons().children[0].children[0]
+ : getButtons().querySelector("like-button-view-model") ?? getButtons().children[0];
+}
+
+function getLikeTextContainer() {
+ return (
+ getLikeButton().querySelector("#text") ??
+ getLikeButton().getElementsByTagName("yt-formatted-string")[0] ??
+ getLikeButton().querySelector("span[role='text']")
+ );
+}
+
+function getDislikeTextContainer() {
+ const dislikeButton = getDislikeButton();
+ let result =
+ dislikeButton?.querySelector("#text") ??
+ dislikeButton?.getElementsByTagName("yt-formatted-string")[0] ??
+ dislikeButton?.querySelector("span[role='text']");
+ if (result === null) {
+ let textSpan = document.createElement("span");
+ textSpan.id = "text";
+ textSpan.style.marginLeft = "6px";
+ dislikeButton?.querySelector("button").appendChild(textSpan);
+ if (dislikeButton) dislikeButton.querySelector("button").style.width = "auto";
+ result = textSpan;
+ }
+ return result;
+}
+
+function createObserver(options, callback) {
+ const observerWrapper = new Object();
+ observerWrapper.options = options;
+ observerWrapper.observer = new MutationObserver(callback);
+ observerWrapper.observe = function (element) {
+ this.observer.observe(element, this.options);
+ };
+ observerWrapper.disconnect = function () {
+ this.observer.disconnect();
+ };
+ return observerWrapper;
+}
+
+let shortsObserver = null;
+
+if (isShorts() && !shortsObserver) {
+ cLog("Initializing shorts mutation observer");
+ shortsObserver = createObserver(
+ {
+ attributes: true,
+ },
+ (mutationList) => {
+ mutationList.forEach((mutation) => {
+ if (
+ mutation.type === "attributes" &&
+ mutation.target.nodeName === "TP-YT-PAPER-BUTTON" &&
+ mutation.target.id === "button"
+ ) {
+ cLog("Short thumb button status changed");
+ if (mutation.target.getAttribute("aria-pressed") === "true") {
+ mutation.target.style.color =
+ mutation.target.parentElement.parentElement.id === "like-button"
+ ? getColorFromTheme(true)
+ : getColorFromTheme(false);
+ } else {
+ mutation.target.style.color = "unset";
+ }
+ return;
+ }
+ cLog("Unexpected mutation observer event: " + mutation.target + mutation.type);
+ });
+ },
+ );
+}
+
+function isVideoLiked() {
+ if (isMobile) {
+ return getLikeButton().querySelector("button").getAttribute("aria-label") == "true";
+ }
+ return getLikeButton().classList.contains("style-default-active");
+}
+
+function isVideoDisliked() {
+ if (isMobile) {
+ return getDislikeButton()?.querySelector("button").getAttribute("aria-label") == "true";
+ }
+ return getDislikeButton()?.classList.contains("style-default-active");
+}
+
+function isVideoNotLiked() {
+ if (isMobile) {
+ return !isVideoLiked();
+ }
+ return getLikeButton().classList.contains("style-text");
+}
+
+function isVideoNotDisliked() {
+ if (isMobile) {
+ return !isVideoDisliked();
+ }
+ return getDislikeButton()?.classList.contains("style-text");
+}
+
+function checkForUserAvatarButton() {
+ if (isMobile) {
+ return;
+ }
+ if (document.querySelector("#avatar-btn")) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+function getState() {
+ if (isVideoLiked()) {
+ return LIKED_STATE;
+ }
+ if (isVideoDisliked()) {
+ return DISLIKED_STATE;
+ }
+ return NEUTRAL_STATE;
+}
+
+function setLikes(likesCount) {
+ if (isMobile) {
+ getButtons().children[0].querySelector(".button-renderer-text").innerText = likesCount;
+ return;
+ }
+ getLikeTextContainer().innerText = likesCount;
+}
+
+function setDislikes(dislikesCount) {
+ if (isMobile) {
+ mobileDislikes = dislikesCount;
+ return;
+ }
+
+ const _container = getDislikeTextContainer();
+ _container?.removeAttribute("is-empty");
+ if (_container?.innerText !== dislikesCount) {
+ _container.innerText = dislikesCount;
+ }
+}
+
+function getLikeCountFromButton() {
+ try {
+ if (isShorts()) {
+ //Youtube Shorts don't work with this query. It's not necessary; we can skip it and still see the results.
+ //It should be possible to fix this function, but it's not critical to showing the dislike count.
+ return false;
+ }
+ let likeButton =
+ getLikeButton().querySelector("yt-formatted-string#text") ?? getLikeButton().querySelector("button");
+
+ let likesStr = likeButton.getAttribute("aria-label").replace(/\D/g, "");
+ return likesStr.length > 0 ? parseInt(likesStr) : false;
+ } catch {
+ return false;
+ }
+}
+
+(typeof GM_addStyle != "undefined"
+ ? GM_addStyle
+ : (styles) => {
+ let styleNode = document.createElement("style");
+ styleNode.type = "text/css";
+ styleNode.innerText = styles;
+ document.head.appendChild(styleNode);
+ })(`
+ #return-youtube-dislike-bar-container {
+ background: var(--yt-spec-icon-disabled);
+ border-radius: 2px;
+ }
+
+ #return-youtube-dislike-bar {
+ background: var(--yt-spec-text-primary);
+ border-radius: 2px;
+ transition: all 0.15s ease-in-out;
+ }
+
+ .ryd-tooltip {
+ position: absolute;
+ display: block;
+ height: 2px;
+ bottom: -10px;
+ }
+
+ .ryd-tooltip-bar-container {
+ width: 100%;
+ height: 2px;
+ position: absolute;
+ padding-top: 6px;
+ padding-bottom: 12px;
+ top: -6px;
+ }
+
+ ytd-menu-renderer.ytd-watch-metadata {
+ overflow-y: visible !important;
+ }
+
+ #top-level-buttons-computed {
+ position: relative !important;
+ }
+ `);
+
+function createRateBar(likes, dislikes) {
+ if (isMobile || !extConfig.rateBarEnabled) {
+ return;
+ }
+ let rateBar = document.getElementById("return-youtube-dislike-bar-container");
+
+ const widthPx = getLikeButton().clientWidth + (getDislikeButton()?.clientWidth ?? 52);
+
+ const widthPercent = likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
+
+ var likePercentage = parseFloat(widthPercent.toFixed(1));
+ const dislikePercentage = (100 - likePercentage).toLocaleString();
+ likePercentage = likePercentage.toLocaleString();
+
+ var tooltipInnerHTML;
+ switch (extConfig.tooltipPercentageMode) {
+ case "dash_like":
+ tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()} - ${likePercentage}%`;
+ break;
+ case "dash_dislike":
+ tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()} - ${dislikePercentage}%`;
+ break;
+ case "both":
+ tooltipInnerHTML = `${likePercentage}% / ${dislikePercentage}%`;
+ break;
+ case "only_like":
+ tooltipInnerHTML = `${likePercentage}%`;
+ break;
+ case "only_dislike":
+ tooltipInnerHTML = `${dislikePercentage}%`;
+ break;
+ default:
+ tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()}`;
+ }
+
+ if (!rateBar && !isMobile) {
+ let colorLikeStyle = "";
+ let colorDislikeStyle = "";
+ if (extConfig.coloredBar) {
+ colorLikeStyle = "; background-color: " + getColorFromTheme(true);
+ colorDislikeStyle = "; background-color: " + getColorFromTheme(false);
+ }
+
+ getButtons().insertAdjacentHTML(
+ "beforeend",
+ `
+
+`,
+ );
+ let descriptionAndActionsElement = document.getElementById("top-row");
+ descriptionAndActionsElement.style.borderBottom = "1px solid var(--yt-spec-10-percent-layer)";
+ descriptionAndActionsElement.style.paddingBottom = "10px";
+ } else {
+ document.querySelector(".ryd-tooltip").style.width = widthPx + "px";
+ document.getElementById("return-youtube-dislike-bar").style.width = widthPercent + "%";
+
+ if (extConfig.coloredBar) {
+ document.getElementById("return-youtube-dislike-bar-container").style.backgroundColor = getColorFromTheme(false);
+ document.getElementById("return-youtube-dislike-bar").style.backgroundColor = getColorFromTheme(true);
+ }
+ }
+}
+
+function setState() {
+ cLog("Fetching votes...");
+ let statsSet = false;
+
+ fetch(`https://returnyoutubedislikeapi.com/votes?videoId=${getVideoId()}`).then((response) => {
+ response.json().then((json) => {
+ if (json && !("traceId" in response) && !statsSet) {
+ const { dislikes, likes } = json;
+ cLog(`Received count: ${dislikes}`);
+ likesvalue = likes;
+ dislikesvalue = dislikes;
+ setDislikes(numberFormat(dislikes));
+ if (extConfig.numberDisplayReformatLikes === true) {
+ const nativeLikes = getLikeCountFromButton();
+ if (nativeLikes !== false) {
+ setLikes(numberFormat(nativeLikes));
+ }
+ }
+ createRateBar(likes, dislikes);
+ if (extConfig.coloredThumbs === true) {
+ const dislikeButton = getDislikeButton();
+ if (isShorts()) {
+ // for shorts, leave deactived buttons in default color
+ const shortLikeButton = getLikeButton().querySelector("tp-yt-paper-button#button");
+ const shortDislikeButton = dislikeButton?.querySelector("tp-yt-paper-button#button");
+ if (shortLikeButton.getAttribute("aria-pressed") === "true") {
+ shortLikeButton.style.color = getColorFromTheme(true);
+ }
+ if (shortDislikeButton && shortDislikeButton.getAttribute("aria-pressed") === "true") {
+ shortDislikeButton.style.color = getColorFromTheme(false);
+ }
+ shortsObserver.observe(shortLikeButton);
+ shortsObserver.observe(shortDislikeButton);
+ } else {
+ getLikeButton().style.color = getColorFromTheme(true);
+ if (dislikeButton) dislikeButton.style.color = getColorFromTheme(false);
+ }
+ }
+ }
+ });
+ });
+}
+
+function updateDOMDislikes() {
+ setDislikes(numberFormat(dislikesvalue));
+ createRateBar(likesvalue, dislikesvalue);
+}
+
+function likeClicked() {
+ if (checkForUserAvatarButton() == true) {
+ if (previousState == 1) {
+ likesvalue--;
+ updateDOMDislikes();
+ previousState = 3;
+ } else if (previousState == 2) {
+ likesvalue++;
+ dislikesvalue--;
+ updateDOMDislikes();
+ previousState = 1;
+ } else if (previousState == 3) {
+ likesvalue++;
+ updateDOMDislikes();
+ previousState = 1;
+ }
+ if (extConfig.numberDisplayReformatLikes === true) {
+ const nativeLikes = getLikeCountFromButton();
+ if (nativeLikes !== false) {
+ setLikes(numberFormat(nativeLikes));
+ }
+ }
+ }
+}
+
+function dislikeClicked() {
+ if (checkForUserAvatarButton() == true) {
+ if (previousState == 3) {
+ dislikesvalue++;
+ updateDOMDislikes();
+ previousState = 2;
+ } else if (previousState == 2) {
+ dislikesvalue--;
+ updateDOMDislikes();
+ previousState = 3;
+ } else if (previousState == 1) {
+ likesvalue--;
+ dislikesvalue++;
+ updateDOMDislikes();
+ previousState = 2;
+ if (extConfig.numberDisplayReformatLikes === true) {
+ const nativeLikes = getLikeCountFromButton();
+ if (nativeLikes !== false) {
+ setLikes(numberFormat(nativeLikes));
+ }
+ }
+ }
+ }
+}
+
+function setInitialState() {
+ setState();
+}
+
+function getVideoId() {
+ const urlObject = new URL(window.location.href);
+ const pathname = urlObject.pathname;
+ if (pathname.startsWith("/clip")) {
+ return (document.querySelector("meta[itemprop='videoId']") || document.querySelector("meta[itemprop='identifier']")).content;
+ } else {
+ if (pathname.startsWith("/shorts")) {
+ return pathname.slice(8);
+ }
+ return urlObject.searchParams.get("v");
+ }
+}
+
+function isVideoLoaded() {
+ if (isMobile) {
+ return document.getElementById("player").getAttribute("loading") == "false";
+ }
+ const videoId = getVideoId();
+
+ return (
+ // desktop: spring 2024 UI
+ document.querySelector(`ytd-watch-grid[video-id='${videoId}']`) !== null ||
+ // desktop: older UI
+ document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null ||
+ // mobile: no video-id attribute
+ document.querySelector('#player[loading="false"]:not([hidden])') !== null
+ );
+}
+
+function roundDown(num) {
+ if (num < 1000) return num;
+ const int = Math.floor(Math.log10(num) - 2);
+ const decimal = int + (int % 3 ? 1 : 0);
+ const value = Math.floor(num / 10 ** decimal);
+ return value * 10 ** decimal;
+}
+
+function numberFormat(numberState) {
+ let numberDisplay;
+ if (extConfig.numberDisplayRoundDown === false) {
+ numberDisplay = numberState;
+ } else {
+ numberDisplay = roundDown(numberState);
+ }
+ return getNumberFormatter(extConfig.numberDisplayFormat).format(numberDisplay);
+}
+
+function getNumberFormatter(optionSelect) {
+ let userLocales;
+ if (document.documentElement.lang) {
+ userLocales = document.documentElement.lang;
+ } else if (navigator.language) {
+ userLocales = navigator.language;
+ } else {
+ try {
+ userLocales = new URL(
+ Array.from(document.querySelectorAll("head > link[rel='search']"))
+ ?.find((n) => n?.getAttribute("href")?.includes("?locale="))
+ ?.getAttribute("href"),
+ )?.searchParams?.get("locale");
+ } catch {
+ cLog("Cannot find browser locale. Use en as default for number formatting.");
+ userLocales = "en";
+ }
+ }
+
+ let formatterNotation;
+ let formatterCompactDisplay;
+ switch (optionSelect) {
+ case "compactLong":
+ formatterNotation = "compact";
+ formatterCompactDisplay = "long";
+ break;
+ case "standard":
+ formatterNotation = "standard";
+ formatterCompactDisplay = "short";
+ break;
+ case "compactShort":
+ default:
+ formatterNotation = "compact";
+ formatterCompactDisplay = "short";
+ }
+
+ const formatter = Intl.NumberFormat(userLocales, {
+ notation: formatterNotation,
+ compactDisplay: formatterCompactDisplay,
+ });
+ return formatter;
+}
+
+function getColorFromTheme(voteIsLike) {
+ let colorString;
+ switch (extConfig.colorTheme) {
+ case "accessible":
+ if (voteIsLike === true) {
+ colorString = "dodgerblue";
+ } else {
+ colorString = "gold";
+ }
+ break;
+ case "neon":
+ if (voteIsLike === true) {
+ colorString = "aqua";
+ } else {
+ colorString = "magenta";
+ }
+ break;
+ case "classic":
+ default:
+ if (voteIsLike === true) {
+ colorString = "lime";
+ } else {
+ colorString = "red";
+ }
+ }
+ return colorString;
+}
+
+let smartimationObserver = null;
+
+function setEventListeners(evt) {
+ let jsInitChecktimer;
+
+ function checkForJS_Finish() {
+ //console.log();
+ if (isShorts() || (getButtons()?.offsetParent && isVideoLoaded())) {
+ const buttons = getButtons();
+ const dislikeButton = getDislikeButton();
+
+ if (preNavigateLikeButton !== getLikeButton() && dislikeButton) {
+ cLog("Registering button listeners...");
+ try {
+ getLikeButton().addEventListener("click", likeClicked);
+ dislikeButton?.addEventListener("click", dislikeClicked);
+ getLikeButton().addEventListener("touchstart", likeClicked);
+ dislikeButton?.addEventListener("touchstart", dislikeClicked);
+ dislikeButton?.addEventListener("focusin", updateDOMDislikes);
+ dislikeButton?.addEventListener("focusout", updateDOMDislikes);
+ preNavigateLikeButton = getLikeButton();
+
+ if (!smartimationObserver) {
+ smartimationObserver = createObserver(
+ {
+ attributes: true,
+ subtree: true,
+ childList: true,
+ },
+ updateDOMDislikes,
+ );
+ smartimationObserver.container = null;
+ }
+
+ const smartimationContainer = buttons.querySelector("yt-smartimation");
+ if (smartimationContainer && smartimationObserver.container != smartimationContainer) {
+ cLog("Initializing smartimation mutation observer");
+ smartimationObserver.disconnect();
+ smartimationObserver.observe(smartimationContainer);
+ smartimationObserver.container = smartimationContainer;
+ }
+ } catch {
+ return;
+ } //Don't spam errors into the console
+ }
+ if (dislikeButton) {
+ setInitialState();
+ clearInterval(jsInitChecktimer);
+ }
+ }
+ }
+
+ cLog("Setting up...");
+ jsInitChecktimer = setInterval(checkForJS_Finish, 111);
+}
+
+(function () {
+ "use strict";
+ window.addEventListener("yt-navigate-finish", setEventListeners, true);
+ setEventListeners();
+})();
+if (isMobile) {
+ let originalPush = history.pushState;
+ history.pushState = function (...args) {
+ window.returnDislikeButtonlistenersSet = false;
+ setEventListeners(args[2]);
+ return originalPush.apply(history, args);
+ };
+ setInterval(() => {
+ const dislikeButton = getDislikeButton();
+ if (dislikeButton?.querySelector(".button-renderer-text") === null) {
+ getDislikeTextContainer().innerText = mobileDislikes;
+ } else {
+ if (dislikeButton) dislikeButton.querySelector(".button-renderer-text").innerText = mobileDislikes;
+ }
+ }, 1000);
+}
diff --git a/home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js b/home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js
new file mode 100644
index 0000000..765097d
--- /dev/null
+++ b/home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js
@@ -0,0 +1,1146 @@
+// ==UserScript==
+// @name SponsorBlock Lite
+// @name:en SponsorBlock Lite - Auto-skip sponsor segments on YouTube and Bilibili
+// @name:zh-CN SponsorBlock Lite - 自动跳过 YouTube/Bilibili 赞助内容
+// @name:zh-TW SponsorBlock Lite - 自動跳過 YouTube/Bilibili 贊助內容
+// @name:ja SponsorBlock Lite - YouTube/Bilibili スポンサー自動スキップ
+// @name:ko SponsorBlock Lite - YouTube/Bilibili 스폰서 자동 건너뛰기
+// @name:de SponsorBlock Lite - YouTube/Bilibili Sponsoren überspringen
+// @name:fr SponsorBlock Lite - Ignorer les sponsors YouTube/Bilibili
+// @name:es SponsorBlock Lite - Saltar patrocinadores YouTube/Bilibili
+// @name:it SponsorBlock Lite - Salta sponsor YouTube/Bilibili
+// @namespace https://github.com/hxueh
+// @version 1.1.1
+// @description Auto-skip sponsor segments on YouTube and Bilibili using SponsorBlock API
+// @description:en Auto-skip sponsor segments on YouTube and Bilibili using SponsorBlock API
+// @description:zh-CN 基于 SponsorBlock API 自动跳过 YouTube 和 Bilibili 视频中的赞助片段
+// @description:zh-TW 基於 SponsorBlock API 自動跳過 YouTube 和 Bilibili 影片中的贊助片段
+// @description:ja SponsorBlock API を使用して YouTube と Bilibili 動画のスポンサーセグメントを自動的にスキップします
+// @description:ko SponsorBlock API를 사용하여 YouTube 및 Bilibili 동영상의 스폰서 구간을 자동으로 건너뜁니다
+// @description:de Überspringen Sie Sponsorensegmente in YouTube- und Bilibili-Videos automatisch mit der SponsorBlock-API
+// @description:fr Ignorez automatiquement les segments sponsorisés dans les vidéos YouTube et Bilibili via l'API SponsorBlock
+// @description:es Salte automáticamente los segmentos de patrocinadores en videos de YouTube y Bilibili usando la API de SponsorBlock
+// @description:it Salta automaticamente i segmenti degli sponsor nei video di YouTube e Bilibili utilizzando l'API SponsorBlock
+// @author hxueh
+// @match https://www.youtube.com/*
+// @match https://music.youtube.com/*
+// @match https://m.youtube.com/*
+// @match https://*.bilibili.com/video/*
+// @icon https://sponsor.ajay.app/LogoSponsorBlock256px.png
+// @grant GM_xmlhttpRequest
+// @grant GM_addStyle
+// @connect sponsor.ajay.app
+// @connect bsbsb.top
+// @run-at document-idle
+// @license LGPL-3.0-or-later
+// @downloadURL https://update.greasyfork.org/scripts/560869/SponsorBlock%20Lite.user.js
+// @updateURL https://update.greasyfork.org/scripts/560869/SponsorBlock%20Lite.meta.js
+// ==/UserScript==
+
+(function () {
+ "use strict";
+
+ // ==================== CONSTANTS ====================
+
+ // Platform detection (must be first for other constants to use)
+ const IS_BILIBILI = window.location.hostname.includes("bilibili.com");
+
+ const API_BASE_YOUTUBE = "https://sponsor.ajay.app";
+ const API_BASE_BILIBILI = "https://bsbsb.top";
+ const API_BASE = IS_BILIBILI ? API_BASE_BILIBILI : API_BASE_YOUTUBE;
+ const CATEGORIES = [
+ "sponsor",
+ "selfpromo",
+ "exclusive_access",
+ "interaction",
+ "outro",
+ "music_offtopic",
+ ];
+ const ACTION_TYPES = ["skip", "full"];
+ const SKIP_BUFFER = 0.003;
+
+ // Colors for all categories (used in preview bar and category pill)
+ const CATEGORY_COLORS = {
+ sponsor: "#00d400",
+ selfpromo: "#ffff00",
+ exclusive_access: "#008a5c",
+ interaction: "#cc00ff",
+ outro: "#0202ed",
+ music_offtopic: "#ff9900",
+ };
+
+ const CATEGORY_LABELS = {
+ exclusive_access: "Exclusive Access",
+ music_offtopic: "Music: Non-Music",
+ };
+
+ // ==================== STATE ====================
+
+ let currentVideoID = null;
+ let segments = [];
+ let skippableSegments = [];
+ let skipScheduleTimer = null;
+ let video = null;
+ let lastSkippedUUID = null;
+ let currentSegmentIndex = 0;
+ let videoChangeDebounce = null;
+ let previewBarContainer = null;
+ let videoDuration = 0;
+ let lastUrl = location.href;
+ let urlPollInterval = null;
+ let videoObserver = null;
+ let rafSkipId = null; // For requestAnimationFrame-based skipping
+ let lastVideoSrc = null; // Track video element replacement
+
+ // Platform detection
+ const IS_MUSIC_YOUTUBE = window.location.hostname === "music.youtube.com";
+ const IS_MOBILE_YOUTUBE = window.location.hostname === "m.youtube.com";
+
+ // Vinegar detection - now a function that's called when needed
+ let IS_VINEGAR = false;
+
+ function updateVinegarDetection() {
+ const hasVideo = document.querySelector("video") !== null;
+ const hasYouTubePlayer = document.querySelector("#movie_player, ytm-player, #player") !== null;
+ const hasYouTubeProgressBar = document.querySelector(".ytp-progress-bar, .progress-bar-line") !== null;
+ // Vinegar: video exists but no YouTube player components
+ const detected = hasVideo && !hasYouTubePlayer && !hasYouTubeProgressBar;
+
+ if (detected && !IS_VINEGAR) {
+ IS_VINEGAR = true;
+ log("Vinegar/native video mode detected");
+ }
+
+ return IS_VINEGAR;
+ }
+
+ // ==================== CSS INJECTION ====================
+
+ function injectStyles() {
+ const css = `
+ /* Desktop YouTube styles */
+ #sb-lite-previewbar {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ pointer-events: none;
+ z-index: 42;
+ list-style: none;
+ transform: scaleY(0.6);
+ transition: transform 0.1s cubic-bezier(0, 0, 0.2, 1);
+ }
+
+ /* Expand on hover (desktop) */
+ .ytp-progress-bar:hover #sb-lite-previewbar {
+ transform: scaleY(1);
+ }
+
+ /* Fullscreen mode (desktop) */
+ .ytp-big-mode #sb-lite-previewbar {
+ transform: scaleY(0.625);
+ }
+
+ .ytp-big-mode .ytp-progress-bar:hover #sb-lite-previewbar {
+ transform: scaleY(1);
+ }
+
+ /* Mobile YouTube styles */
+ .advancement-bar-line #sb-lite-previewbar,
+ .advancement-bar #sb-lite-previewbar,
+ .progress-bar-line #sb-lite-previewbar {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ pointer-events: none;
+ z-index: 42;
+ list-style: none;
+ transform: none;
+ }
+
+ .sb-lite-segment {
+ position: absolute;
+ height: 100%;
+ min-width: 1px;
+ display: inline-block;
+ opacity: 0.7;
+ }
+
+ .sb-lite-segment:hover {
+ opacity: 1;
+ }
+
+ #sb-lite-category-pill {
+ display: none;
+ align-items: center;
+ padding: 4px 12px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 500;
+ margin-left: 8px;
+ color: white;
+ font-family: Roboto, Arial, sans-serif;
+ white-space: nowrap;
+ cursor: default;
+ user-select: none;
+ }
+
+ /* Mobile category pill adjustments */
+ .ytm-slim-owner-container #sb-lite-category-pill,
+ ytm-slim-owner-renderer #sb-lite-category-pill {
+ font-size: 10px;
+ padding: 2px 8px;
+ margin-left: 4px;
+ }
+
+ /* Bilibili styles */
+ .bpx-player-progress-wrap #sb-lite-previewbar,
+ .bpx-player-progress #sb-lite-previewbar,
+ .bilibili-player-video-progress #sb-lite-previewbar,
+ .squirtle-progress-wrap #sb-lite-previewbar {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ pointer-events: none;
+ z-index: 42;
+ list-style: none;
+ transform: none;
+ }
+
+ /* Bilibili category pill adjustments */
+ .video-title #sb-lite-category-pill,
+ .video-info-title #sb-lite-category-pill {
+ font-size: 12px;
+ padding: 2px 8px;
+ margin-left: 8px;
+ }
+ `;
+
+ if (typeof GM_addStyle !== "undefined") {
+ GM_addStyle(css);
+ } else {
+ const style = document.createElement("style");
+ style.textContent = css;
+ document.head.appendChild(style);
+ }
+ }
+
+ // ==================== UTILITY FUNCTIONS ====================
+
+ async function sha256(message) {
+ const msgBuffer = new TextEncoder().encode(message);
+ const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
+ }
+
+ async function getHashPrefix(videoID) {
+ const hash = await sha256(videoID);
+ return hash.slice(0, 4);
+ }
+
+ function getBilibiliVideoID() {
+ const url = window.location.href;
+ const patterns = [
+ /\/video\/([^/?#]+)/,
+ /\/BV([^/?#]+)/,
+ /bvid=([^&]+)/,
+ ];
+ for (const pattern of patterns) {
+ const match = url.match(pattern);
+ if (match) {
+ let videoId = match[1];
+ if (!videoId.startsWith("BV")) {
+ videoId = "BV" + videoId;
+ }
+ return videoId;
+ }
+ }
+ return null;
+ }
+
+ function getVideoID() {
+ if (IS_BILIBILI) {
+ return getBilibiliVideoID();
+ }
+
+ const url = new URL(window.location.href);
+
+ const vParam = url.searchParams.get("v");
+ if (vParam && /^[a-zA-Z0-9_-]{11}$/.test(vParam)) {
+ return vParam;
+ }
+
+ const shortsMatch = url.pathname.match(/\/shorts\/([a-zA-Z0-9_-]{11})/);
+ if (shortsMatch) return shortsMatch[1];
+
+ const embedMatch = url.pathname.match(/\/embed\/([a-zA-Z0-9_-]{11})/);
+ if (embedMatch) return embedMatch[1];
+
+ const liveMatch = url.pathname.match(/\/live\/([a-zA-Z0-9_-]{11})/);
+ if (liveMatch) return liveMatch[1];
+
+ // Mobile watch URL pattern
+ const watchMatch = url.pathname.match(/\/watch\/([a-zA-Z0-9_-]{11})/);
+ if (watchMatch) return watchMatch[1];
+
+ return null;
+ }
+
+ function getVideoDuration() {
+ return video?.duration || 0;
+ }
+
+ function log(message, ...args) {
+ console.log(
+ `[SB Lite${IS_BILIBILI ? " Bilibili" : IS_VINEGAR ? " Vinegar" : IS_MOBILE_YOUTUBE ? " Mobile" : ""}]`,
+ message,
+ ...args,
+ );
+ }
+
+ function logError(message, ...args) {
+ console.error(
+ `[SB Lite${IS_BILIBILI ? " Bilibili" : IS_VINEGAR ? " Vinegar" : IS_MOBILE_YOUTUBE ? " Mobile" : ""}]`,
+ message,
+ ...args,
+ );
+ }
+
+ // ==================== API FUNCTIONS ====================
+
+ function fetchSegments(videoID) {
+ return new Promise(async (resolve) => {
+ try {
+ const hashPrefix = await getHashPrefix(videoID);
+ const params = new URLSearchParams({
+ categories: JSON.stringify(CATEGORIES),
+ actionTypes: JSON.stringify(ACTION_TYPES),
+ });
+
+ GM_xmlhttpRequest({
+ method: "GET",
+ url: `${API_BASE}/api/skipSegments/${hashPrefix}?${params}`,
+ headers: { Accept: "application/json" },
+ onload(response) {
+ if (response.status === 200) {
+ try {
+ const data = JSON.parse(response.responseText);
+ const videoData = data.find((v) => v.videoID === videoID);
+ const segs = videoData?.segments || [];
+ segs.sort((a, b) => a.segment[0] - b.segment[0]);
+ resolve(segs);
+ } catch {
+ resolve([]);
+ }
+ } else {
+ resolve([]);
+ }
+ },
+ onerror() {
+ resolve([]);
+ },
+ });
+ } catch {
+ resolve([]);
+ }
+ });
+ }
+
+ // ==================== SKIP LOGIC ====================
+
+ function computeSkippableSegments() {
+ skippableSegments = segments.filter((s) => {
+ if (s.actionType === "full") return false;
+ if (s.category === "music_offtopic" && !IS_MUSIC_YOUTUBE) return false;
+ return true;
+ });
+ currentSegmentIndex = 0;
+ }
+
+ function skipToTime(targetTime, retryCount = 0) {
+ if (!video || targetTime === undefined) return false;
+
+ const maxRetries = 3;
+ const previousTime = video.currentTime;
+
+ try {
+ video.currentTime = targetTime;
+
+ // On iOS/Vinegar, verify the skip worked after a short delay
+ if (IS_VINEGAR && retryCount < maxRetries) {
+ setTimeout(() => {
+ // Check if we're still in a segment that should be skipped
+ // (meaning the skip might have failed)
+ const currentTime = video.currentTime;
+ const timeDiff = Math.abs(currentTime - targetTime);
+
+ // If we're more than 0.5s away from target and still before target,
+ // the skip likely failed
+ if (timeDiff > 0.5 && currentTime < targetTime - 0.5) {
+ log(`Skip verification failed (attempt ${retryCount + 1}), retrying...`);
+ skipToTime(targetTime, retryCount + 1);
+ }
+ }, 100);
+ }
+
+ return true;
+ } catch (e) {
+ logError("Skip failed:", e);
+ return false;
+ }
+ }
+
+ function findNextSegment(currentTime) {
+ if (
+ currentSegmentIndex > 0 &&
+ skippableSegments[currentSegmentIndex - 1] &&
+ currentTime < skippableSegments[currentSegmentIndex - 1].segment[0]
+ ) {
+ currentSegmentIndex = 0;
+ }
+
+ while (currentSegmentIndex < skippableSegments.length) {
+ const seg = skippableSegments[currentSegmentIndex];
+ if (currentTime < seg.segment[1] - SKIP_BUFFER) {
+ return { segment: seg, index: currentSegmentIndex };
+ }
+ currentSegmentIndex++;
+ }
+ return null;
+ }
+
+ // RAF-based skip loop for Vinegar (more responsive than timeupdate)
+ function startRAFSkipLoop() {
+ if (rafSkipId) {
+ cancelAnimationFrame(rafSkipId);
+ }
+
+ function checkAndSkip() {
+ if (!video || !skippableSegments.length) {
+ rafSkipId = null;
+ return;
+ }
+
+ // Check for video element replacement
+ if (IS_VINEGAR) {
+ const currentVideo = document.querySelector("video");
+ if (currentVideo && currentVideo !== video) {
+ log("Video element replaced, re-attaching...");
+ video = currentVideo;
+ setupVideoListeners();
+ }
+ }
+
+ if (!video.paused) {
+ const currentTime = video.currentTime;
+
+ for (const seg of skippableSegments) {
+ const [startTime, endTime] = seg.segment;
+ if (
+ currentTime >= startTime - SKIP_BUFFER &&
+ currentTime < endTime - SKIP_BUFFER &&
+ lastSkippedUUID !== seg.UUID
+ ) {
+ lastSkippedUUID = seg.UUID;
+ log(`Skipping ${seg.category} segment at ${currentTime.toFixed(2)}s -> ${endTime.toFixed(2)}s`);
+ skipToTime(endTime);
+ break;
+ }
+ }
+ }
+
+ rafSkipId = requestAnimationFrame(checkAndSkip);
+ }
+
+ rafSkipId = requestAnimationFrame(checkAndSkip);
+ }
+
+ function stopRAFSkipLoop() {
+ if (rafSkipId) {
+ cancelAnimationFrame(rafSkipId);
+ rafSkipId = null;
+ }
+ }
+
+ function scheduleSkips() {
+ // For Vinegar/iOS, use RAF-based skipping for better responsiveness
+ if (IS_VINEGAR || IS_MOBILE_YOUTUBE) {
+ if (!video?.paused && skippableSegments.length > 0) {
+ startRAFSkipLoop();
+ }
+ return;
+ }
+
+ // Desktop: use timer-based approach
+ if (skipScheduleTimer) {
+ clearTimeout(skipScheduleTimer);
+ skipScheduleTimer = null;
+ }
+
+ if (!video || video.paused || !skippableSegments.length) return;
+
+ const currentTime = video.currentTime;
+ const result = findNextSegment(currentTime);
+
+ if (!result) return;
+
+ const { segment: nextSegment } = result;
+ const [startTime, endTime] = nextSegment.segment;
+
+ if (currentTime >= startTime - SKIP_BUFFER) {
+ if (lastSkippedUUID !== nextSegment.UUID) {
+ lastSkippedUUID = nextSegment.UUID;
+ log(`Skipping ${nextSegment.category} segment`);
+ skipToTime(endTime);
+ currentSegmentIndex++;
+ }
+ setTimeout(scheduleSkips, 50);
+ return;
+ }
+
+ const timeUntilStart = (startTime - currentTime) / video.playbackRate;
+ const delayMs = Math.max(0, timeUntilStart * 1000 - 50);
+
+ skipScheduleTimer = setTimeout(() => {
+ if (!video || video.paused) return;
+
+ const nowTime = video.currentTime;
+ if (
+ nowTime >= startTime - SKIP_BUFFER &&
+ nowTime < endTime - SKIP_BUFFER
+ ) {
+ if (lastSkippedUUID !== nextSegment.UUID) {
+ lastSkippedUUID = nextSegment.UUID;
+ log(`Skipping ${nextSegment.category} segment`);
+ skipToTime(endTime);
+ currentSegmentIndex++;
+ }
+ }
+ scheduleSkips();
+ }, delayMs);
+ }
+
+ // ==================== PREVIEW BAR ====================
+
+ function createPreviewBar() {
+ const container = document.createElement("ul");
+ container.id = "sb-lite-previewbar";
+ return container;
+ }
+
+ function createSegmentBar(segment, duration) {
+ const bar = document.createElement("li");
+ bar.className = "sb-lite-segment";
+
+ const startTime = segment.segment[0];
+ const endTime = Math.min(segment.segment[1], duration);
+
+ const startPercent = (startTime / duration) * 100;
+ const endPercent = (endTime / duration) * 100;
+
+ bar.style.left = `${startPercent}%`;
+ bar.style.right = `${100 - endPercent}%`;
+ bar.style.backgroundColor = CATEGORY_COLORS[segment.category] || "#888";
+
+ // Add title tooltip
+ bar.title = segment.category.replace(/_/g, " ");
+
+ return bar;
+ }
+
+ function getProgressBar() {
+ // Bilibili
+ if (IS_BILIBILI) {
+ return (
+ document.querySelector(".bpx-player-progress-wrap") ||
+ document.querySelector(".bilibili-player-video-progress") ||
+ document.querySelector(".squirtle-progress-wrap") ||
+ document.querySelector(".bpx-player-progress")
+ );
+ }
+
+ // Desktop YouTube
+ let progressBar = document.querySelector(".ytp-progress-bar");
+
+ // YouTube Music
+ if (!progressBar && IS_MUSIC_YOUTUBE) {
+ progressBar = document.querySelector("#progress-bar");
+ }
+
+ // Mobile YouTube - try multiple selectors
+ if (!progressBar && IS_MOBILE_YOUTUBE) {
+ progressBar =
+ document.querySelector(".progress-bar-line") ||
+ document.querySelector(".advancement-bar-line") ||
+ document.querySelector(".advancement-bar") ||
+ document.querySelector("ytm-player .progress-bar") ||
+ document.querySelector(".player-controls-content .progress-bar-line") ||
+ document.querySelector("[class*='progress-bar']");
+ }
+
+ return progressBar;
+ }
+
+ function clearPreviewBar() {
+ if (previewBarContainer) {
+ previewBarContainer.innerHTML = "";
+ }
+ }
+
+ function removePreviewBar() {
+ if (previewBarContainer) {
+ previewBarContainer.remove();
+ previewBarContainer = null;
+ }
+ }
+
+ function updatePreviewBar() {
+ const duration = getVideoDuration();
+ if (!duration || duration <= 0) return;
+
+ videoDuration = duration;
+
+ // Get or create container
+ if (!previewBarContainer) {
+ previewBarContainer = createPreviewBar();
+ }
+
+ // Attach to progress bar if not already attached
+ const progressBar = getProgressBar();
+ if (progressBar && !progressBar.contains(previewBarContainer)) {
+ // Ensure progress bar has relative positioning for absolute children
+ const computedStyle = window.getComputedStyle(progressBar);
+ if (computedStyle.position === "static") {
+ progressBar.style.position = "relative";
+ }
+ progressBar.appendChild(previewBarContainer);
+ }
+
+ if (!progressBar) {
+ // For Vinegar, this is expected since native controls can't be modified
+ if (IS_VINEGAR) {
+ log("Preview bar not available (Vinegar/native controls)");
+ } else {
+ log("Progress bar not found, will retry...");
+ }
+ return;
+ }
+
+ // Clear existing bars
+ clearPreviewBar();
+
+ // Filter segments for preview bar (exclude ActionType.Full)
+ const previewSegments = segments.filter((s) => s.actionType !== "full");
+
+ // Sort by duration (longer first) to render properly
+ const sortedSegments = [...previewSegments].sort(
+ (a, b) => b.segment[1] - b.segment[0] - (a.segment[1] - a.segment[0]),
+ );
+
+ // Create segment bars
+ for (const segment of sortedSegments) {
+ // Skip music_offtopic on non-music YouTube
+ if (segment.category === "music_offtopic" && !IS_MUSIC_YOUTUBE) {
+ continue;
+ }
+
+ const bar = createSegmentBar(segment, duration);
+ previewBarContainer.appendChild(bar);
+ }
+ }
+
+ // ==================== CATEGORY PILL ====================
+
+ function createCategoryPill() {
+ const pill = document.createElement("span");
+ pill.id = "sb-lite-category-pill";
+ return pill;
+ }
+
+ function attachCategoryPill() {
+ let pill = document.getElementById("sb-lite-category-pill");
+ if (!pill) {
+ pill = createCategoryPill();
+ }
+
+ let titleContainer = null;
+
+ if (IS_BILIBILI) {
+ // Bilibili title selectors
+ titleContainer =
+ document.querySelector(".video-title") ||
+ document.querySelector(".title-text") ||
+ document.querySelector("h1.video-title") ||
+ document.querySelector(".video-info-title");
+ } else if (IS_MUSIC_YOUTUBE) {
+ titleContainer = document.querySelector("ytmusic-player-bar .title");
+ } else if (IS_MOBILE_YOUTUBE) {
+ // Mobile YouTube title selectors
+ titleContainer =
+ document.querySelector(
+ ".slim-video-metadata-header .slim-owner-icon-and-title",
+ ) ||
+ document.querySelector("ytm-slim-owner-renderer") ||
+ document.querySelector(".slim-video-information-title") ||
+ document.querySelector(".slim-video-metadata-title") ||
+ document.querySelector("[class*='video-title']") ||
+ document.querySelector("h2.slim-video-information-title");
+ } else {
+ // Desktop YouTube
+ titleContainer =
+ document.querySelector("#above-the-fold #title h1") ||
+ document.querySelector("ytd-watch-metadata #title h1") ||
+ document.querySelector("#info-contents h1") ||
+ document.querySelector("h1.ytd-video-primary-info-renderer");
+ }
+
+ if (titleContainer && !titleContainer.contains(pill)) {
+ titleContainer.style.display = "flex";
+ titleContainer.style.alignItems = "center";
+ titleContainer.style.flexWrap = "wrap";
+ titleContainer.appendChild(pill);
+ }
+
+ return pill;
+ }
+
+ function showCategoryPill(segment) {
+ const pill = attachCategoryPill();
+ if (!pill) return;
+
+ const label = CATEGORY_LABELS[segment.category] || segment.category;
+ const color = CATEGORY_COLORS[segment.category] || "#008a5c";
+
+ pill.textContent = label;
+ pill.style.backgroundColor = color;
+ pill.style.display = "inline-flex";
+ }
+
+ function hideCategoryPill() {
+ const pill = document.getElementById("sb-lite-category-pill");
+ if (pill) {
+ pill.style.display = "none";
+ }
+ }
+
+ function updateCategoryPill() {
+ const fullVideoSegment = segments.find((s) => s.actionType === "full");
+ if (fullVideoSegment) {
+ showCategoryPill(fullVideoSegment);
+ } else {
+ hideCategoryPill();
+ }
+ }
+
+ // ==================== VIDEO LISTENERS ====================
+
+ function setupVideoListeners() {
+ if (!video) return;
+
+ // Re-check Vinegar detection now that we have a video
+ updateVinegarDetection();
+
+ const videoId = video.getAttribute("data-sb-lite-initialized");
+ const currentSrc = video.currentSrc || video.src;
+
+ // Check if this is a new video or if the source changed
+ if (videoId === currentVideoID && lastVideoSrc === currentSrc) return;
+
+ video.setAttribute("data-sb-lite-initialized", currentVideoID);
+ lastVideoSrc = currentSrc;
+
+ log("Setting up video listeners" + (IS_VINEGAR ? " (Vinegar mode)" : ""));
+
+ // Remove any existing listeners by cloning (for Vinegar video replacement scenario)
+ // We'll use named functions and track them instead
+
+ const onPlay = () => {
+ log("Video play event");
+ scheduleSkips();
+ };
+
+ const onPlaying = () => {
+ log("Video playing event");
+ scheduleSkips();
+ };
+
+ const onSeeked = () => {
+ log("Video seeked event");
+ lastSkippedUUID = null;
+ currentSegmentIndex = 0;
+ if (!video.paused) {
+ scheduleSkips();
+ }
+ };
+
+ const onRateChange = () => {
+ scheduleSkips();
+ };
+
+ const onPause = () => {
+ log("Video pause event");
+ if (skipScheduleTimer) {
+ clearTimeout(skipScheduleTimer);
+ skipScheduleTimer = null;
+ }
+ stopRAFSkipLoop();
+ };
+
+ const onDurationChange = () => {
+ if (segments.length > 0) {
+ updatePreviewBar();
+ }
+ };
+
+ const onLoadedMetadata = () => {
+ log("Video loadedmetadata event");
+ if (segments.length > 0) {
+ updatePreviewBar();
+ }
+ };
+
+ video.addEventListener("play", onPlay);
+ video.addEventListener("playing", onPlaying);
+ video.addEventListener("seeked", onSeeked);
+ video.addEventListener("ratechange", onRateChange);
+ video.addEventListener("pause", onPause);
+ video.addEventListener("durationchange", onDurationChange);
+ video.addEventListener("loadedmetadata", onLoadedMetadata);
+
+ // For Vinegar/iOS: also listen to timeupdate as backup
+ // (RAF loop is primary, but timeupdate helps when app is backgrounded)
+ if (IS_VINEGAR || IS_MOBILE_YOUTUBE) {
+ const onTimeUpdate = () => {
+ if (!video.paused && skippableSegments.length > 0) {
+ const currentTime = video.currentTime;
+ for (const seg of skippableSegments) {
+ const [startTime, endTime] = seg.segment;
+ if (
+ currentTime >= startTime &&
+ currentTime < endTime - SKIP_BUFFER &&
+ lastSkippedUUID !== seg.UUID
+ ) {
+ lastSkippedUUID = seg.UUID;
+ log(`Skipping ${seg.category} segment (timeupdate backup)`);
+ skipToTime(endTime);
+ break;
+ }
+ }
+ }
+ };
+ video.addEventListener("timeupdate", onTimeUpdate);
+ }
+
+ // For Vinegar: Monitor for video element replacement
+ if (IS_VINEGAR) {
+ // Also start skip loop immediately if video is already playing
+ if (!video.paused && skippableSegments.length > 0) {
+ startRAFSkipLoop();
+ }
+ }
+ }
+
+ function findVideoElement() {
+ // Bilibili selectors
+ if (IS_BILIBILI) {
+ video =
+ document.querySelector(".bpx-player-video-area video") ||
+ document.querySelector(".bilibili-player video") ||
+ document.querySelector("video");
+ return video;
+ }
+
+ // For Vinegar (or when YouTube player is replaced), just find any video element
+ const anyVideo = document.querySelector("video");
+ if (anyVideo) {
+ // Check if this looks like a Vinegar setup (no YouTube player elements)
+ const hasYouTubePlayer = document.querySelector("#movie_player, ytm-player") !== null;
+ if (!hasYouTubePlayer) {
+ if (!IS_VINEGAR) {
+ IS_VINEGAR = true;
+ log("Vinegar/native video detected");
+ }
+ video = anyVideo;
+ return video;
+ }
+ }
+
+ // Desktop selectors
+ video =
+ document.querySelector("video.html5-main-video") ||
+ document.querySelector("video.video-stream") ||
+ document.querySelector("#movie_player video");
+
+ // Mobile selectors
+ if (!video && IS_MOBILE_YOUTUBE) {
+ video =
+ document.querySelector("ytm-player video") ||
+ document.querySelector(".player-container video") ||
+ document.querySelector(".html5-video-container video") ||
+ document.querySelector(".video-stream") ||
+ document.querySelector("video[playsinline]") ||
+ document.querySelector("video");
+ }
+
+ // Fallback
+ if (!video) {
+ video = document.querySelector("video");
+ }
+
+ return video;
+ }
+
+ // ==================== MUTATION OBSERVER FOR VIDEO ====================
+
+ function setupVideoObserver() {
+ if (videoObserver) {
+ videoObserver.disconnect();
+ }
+
+ videoObserver = new MutationObserver((mutations) => {
+ // Check if video element was added or replaced
+ const currentVideo = document.querySelector("video");
+
+ if (currentVideo && currentVideo !== video) {
+ log("Video element change detected via observer");
+ video = currentVideo;
+
+ // Re-check Vinegar status
+ updateVinegarDetection();
+
+ if (currentVideoID) {
+ setupVideoListeners();
+ if (segments.length > 0 && !video.paused) {
+ scheduleSkips();
+ }
+ }
+ } else if (!currentVideo && video) {
+ log("Video element removed");
+ video = null;
+ stopRAFSkipLoop();
+ }
+ });
+
+ videoObserver.observe(document.body, {
+ childList: true,
+ subtree: true,
+ });
+ }
+
+ // ==================== NAVIGATION & INITIALIZATION ====================
+
+ function resetState() {
+ currentVideoID = null;
+ segments = [];
+ skippableSegments = [];
+ lastSkippedUUID = null;
+ currentSegmentIndex = 0;
+ videoDuration = 0;
+ lastVideoSrc = null;
+
+ if (skipScheduleTimer) {
+ clearTimeout(skipScheduleTimer);
+ skipScheduleTimer = null;
+ }
+
+ stopRAFSkipLoop();
+
+ hideCategoryPill();
+ removePreviewBar();
+ }
+
+ async function loadSegmentsAndSetup() {
+ if (!currentVideoID) return;
+
+ try {
+ segments = await fetchSegments(currentVideoID);
+
+ if (segments.length > 0) {
+ log(`Found ${segments.length} segments for video ${currentVideoID}`);
+ }
+
+ computeSkippableSegments();
+ updateCategoryPill();
+ updatePreviewBar();
+ setupVideoListeners();
+
+ if (video && !video.paused) {
+ scheduleSkips();
+ }
+
+ // Retry preview bar attachment after a delay (for slow-loading UI)
+ if ((IS_MOBILE_YOUTUBE || IS_VINEGAR) && segments.length > 0) {
+ setTimeout(updatePreviewBar, 1000);
+ setTimeout(updatePreviewBar, 2000);
+ setTimeout(updateCategoryPill, 1000);
+ }
+ } catch (error) {
+ logError("Failed to load segments:", error);
+ }
+ }
+
+ function handleVideoChangeImpl() {
+ const newVideoID = getVideoID();
+
+ if (!newVideoID || newVideoID === currentVideoID) {
+ return;
+ }
+
+ log(`Video changed to: ${newVideoID}`);
+ resetState();
+ currentVideoID = newVideoID;
+
+ let attempts = 0;
+ const maxAttempts = 50;
+
+ const checkVideo = setInterval(() => {
+ attempts++;
+
+ // Re-check Vinegar detection on each attempt
+ updateVinegarDetection();
+
+ if (findVideoElement()) {
+ clearInterval(checkVideo);
+ log("Video element found after", attempts, "attempts");
+ loadSegmentsAndSetup();
+ } else if (attempts >= maxAttempts) {
+ clearInterval(checkVideo);
+ logError("Failed to find video element after max attempts");
+ }
+ }, 100);
+ }
+
+ function handleVideoChange() {
+ if (videoChangeDebounce) {
+ clearTimeout(videoChangeDebounce);
+ }
+ videoChangeDebounce = setTimeout(handleVideoChangeImpl, 50);
+ }
+
+ function setupNavigationListener() {
+ // Standard YouTube navigation events (may not fire on mobile)
+ document.addEventListener("yt-navigate-finish", () => {
+ log("yt-navigate-finish event");
+ handleVideoChange();
+ });
+
+ document.addEventListener("yt-navigate-start", () => {
+ hideCategoryPill();
+ removePreviewBar();
+ stopRAFSkipLoop();
+ });
+
+ // Mobile-specific events
+ if (IS_MOBILE_YOUTUBE) {
+ document.addEventListener("state-navigateend", () => {
+ log("state-navigateend event");
+ handleVideoChange();
+ });
+
+ document.addEventListener("yt-page-data-updated", () => {
+ log("yt-page-data-updated event");
+ handleVideoChange();
+ });
+ }
+
+ // History API interception
+ const originalPushState = history.pushState;
+ history.pushState = function (...args) {
+ originalPushState.apply(this, args);
+ log("pushState detected");
+ handleVideoChange();
+ };
+
+ const originalReplaceState = history.replaceState;
+ history.replaceState = function (...args) {
+ originalReplaceState.apply(this, args);
+ log("replaceState detected");
+ handleVideoChange();
+ };
+
+ window.addEventListener("popstate", () => {
+ log("popstate event");
+ handleVideoChange();
+ });
+
+ // URL polling fallback (essential for mobile and Vinegar)
+ urlPollInterval = setInterval(() => {
+ if (location.href !== lastUrl) {
+ log("URL change detected via polling:", location.href);
+ lastUrl = location.href;
+ handleVideoChange();
+ }
+
+ // For Vinegar: periodically check if video element was replaced
+ if (IS_VINEGAR && currentVideoID) {
+ const currentVideo = document.querySelector("video");
+ if (currentVideo && currentVideo !== video) {
+ log("Video element replacement detected via polling");
+ video = currentVideo;
+ setupVideoListeners();
+ if (skippableSegments.length > 0 && !video.paused) {
+ scheduleSkips();
+ }
+ }
+ }
+ }, 500);
+ }
+
+ function init() {
+ log("Initializing SponsorBlock Lite");
+
+ // Initial Vinegar detection (may update later when video loads)
+ updateVinegarDetection();
+
+ log(
+ "Platform:",
+ IS_BILIBILI ? "Bilibili" : IS_VINEGAR ? "Vinegar" : IS_MOBILE_YOUTUBE ? "Mobile" : IS_MUSIC_YOUTUBE ? "Music" : "Desktop",
+ );
+
+ injectStyles();
+ setupNavigationListener();
+ setupVideoObserver();
+ handleVideoChange();
+
+ // Multiple retry attempts for initial load
+ setTimeout(handleVideoChange, 500);
+ setTimeout(handleVideoChange, 1000);
+ setTimeout(handleVideoChange, 2000);
+
+ // Additional retries for mobile/Vinegar
+ if (IS_MOBILE_YOUTUBE || IS_VINEGAR) {
+ setTimeout(handleVideoChange, 3000);
+ setTimeout(handleVideoChange, 5000);
+ }
+
+ // For Vinegar: also retry after longer delays since the player loads differently
+ setTimeout(() => {
+ updateVinegarDetection();
+ if (IS_VINEGAR) {
+ log("Late Vinegar detection check");
+ handleVideoChange();
+ }
+ }, 4000);
+ }
+
+ // ==================== START ====================
+
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", init);
+ } else {
+ init();
+ }
+})();
diff --git a/home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js b/home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js
new file mode 100644
index 0000000..90b2357
--- /dev/null
+++ b/home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js
@@ -0,0 +1,18 @@
+// ==UserScript==
+// @name Startpage - Hide Ads
+// @match https://www.startpage.com/*
+// @run-at document-start
+// ==/UserScript==
+
+new MutationObserver(function(mutations) {
+ mutations.forEach((mutation) => {
+ if (mutation.type === 'childList') {
+ mutation.addedNodes.forEach((node) => {
+ if (node.nodeType === 1 && node.nodeName === 'DIV' && node.id === 'gcsa-top') {
+ node.remove();
+ this.disconnect();
+ }
+ });
+ }
+ });
+}).observe(document, { childList: true, subtree: true });
diff --git a/home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js b/home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js
new file mode 100644
index 0000000..a425a03
--- /dev/null
+++ b/home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js
@@ -0,0 +1,191 @@
+// ==UserScript==
+// @name TrackingTokenStripper
+// @version 1.4
+// @description Remove most of the annoying tracking token from URL parameters
+// @license MIT
+// @homepage https://blog.miniasp.com/
+// @homepageURL https://blog.miniasp.com/
+// @website https://www.facebook.com/will.fans
+// @source https://github.com/doggy8088/TrackingTokenStripper/raw/refs/heads/master/TrackingTokenStripper.user.js
+// @namespace https://github.com/doggy8088/TrackingTokenStripper
+// @author Will Huang
+// @match *://*/*
+// @run-at document-start
+// ==/UserScript==
+
+(function () {
+ 'use strict';
+
+ const oldReplaceState = history.replaceState;
+ history.replaceState = function replaceState() {
+ let ret = oldReplaceState.apply(this, arguments);
+ window.dispatchEvent(new Event('replacestate'));
+ window.dispatchEvent(new Event('locationchange'));
+ return ret;
+ };
+
+ window.addEventListener('popstate', () => {
+ window.dispatchEvent(new Event('locationchange'));
+ });
+
+ window.addEventListener('locationchange', function () {
+ executeActions();
+ });
+
+ executeActions();
+
+ let id = setInterval(executeActions, 500);
+
+ setTimeout(() => { clearInterval(id); }, 2000);
+
+ function executeActions() {
+
+ var s = TrackingTokenStripper(location.href)
+ // facebook
+ .remove('fbclid')
+ .removeByDomain('www.facebook.com', 'privacy_mutation_token')
+ .removeByDomain('www.facebook.com', 'acontext')
+ .removeByDomain('www.facebook.com', '__xts__[0]')
+ .removeByDomain('www.facebook.com', 'notif_t')
+ .removeByDomain('www.facebook.com', 'notif_id')
+ .removeByDomain('www.facebook.com', 'notif_ids[0]')
+ .removeByDomain('www.facebook.com', 'notif_ids[1]')
+ .removeByDomain('www.facebook.com', 'notif_ids[2]')
+ .removeByDomain('www.facebook.com', 'notif_ids[3]')
+ .removeByDomain('www.facebook.com', 'ref', 'notif')
+ .removeByDomain('www.facebook.com', 'ref=watch_permalink')
+
+ // Dropbox
+ .removeByDomain('www.dropbox.com', '_ad')
+ .removeByDomain('www.dropbox.com', '_camp')
+ .removeByDomain('www.dropbox.com', '_tk')
+
+ // YouTube
+ // https://youtu.be/4f-Y9G5ENPc?si=SHSu2hEdSbXGy4_Q
+ // https://www.youtube.com/embed/4f-Y9G5ENPc?si=GQFJV_nKMXxpiQb6
+ .removeByDomain('youtu.be', 'si')
+ .removeByDomain('www.youtube.com', 'si')
+
+ // Google Analytics
+ // https://support.google.com/analytics/answer/1033863?hl=en
+ .remove('utm_id')
+ .remove('utm_source')
+ .remove('utm_medium')
+ .remove('utm_campaign')
+ .remove('utm_term')
+ .remove('utm_content')
+ .remove('_ga')
+
+ // GA - others
+ .remove('utm_campaignid')
+ .remove('utm_cid')
+ .remove('utm_reader')
+ .remove('utm_referrer')
+ .remove('utm_name')
+ .remove('utm_social')
+ .remove('utm_social-type')
+ .remove('gclid')
+ .remove('igshid')
+ .remove('_hsenc')
+ .remove('_hsmi')
+ .remove('mc_cid')
+ .remove('mc_eid')
+ .remove('mkt_tok')
+ .remove('yclid')
+ .remove('_openstat')
+
+ // devblogs.microsoft.com
+ .removeByDomain('devblogs.microsoft.com', 'utm_issue')
+ .removeByDomain('devblogs.microsoft.com', 'utm_position')
+ .removeByDomain('devblogs.microsoft.com', 'utm_topic')
+ .removeByDomain('devblogs.microsoft.com', 'utm_section')
+ .removeByDomain('devblogs.microsoft.com', 'utm_cta')
+ .removeByDomain('devblogs.microsoft.com', 'utm_description')
+ .removeByDomain('devblogs.microsoft.com', 'ocid')
+
+ // Microsoft
+ .remove('wt.mc_id')
+ .removeByDomain('learn.microsoft.com', 'ocid')
+ .removeByDomain('learn.microsoft.com', 'redirectedfrom')
+
+ .removeByDomain('azure.microsoft.com', 'OCID')
+ .removeByDomain('azure.microsoft.com', 'ef_id')
+
+ .removeByDomain('www.msn.com', 'ocid')
+ .removeByDomain('www.msn.com', 'cvid')
+
+ // bilibili
+ .removeByDomain('www.bilibili.com', 'share_source')
+ .removeByDomain('www.bilibili.com', 'share_medium')
+
+ // Others
+ .remove('__tn__')
+ .remove('gclsrc')
+ .remove('itm_source')
+ .remove('itm_medium')
+ .remove('itm_campaign')
+ .remove('mc') // sendgrid.com
+ .remove('mcd') // sendgrid.com
+ .remove('cvosrc') // sendgrid.com
+ .remove('cr_cc') // https://blogs.microsoft.com/
+
+ .remove('sc_channel')
+ .remove('sc_campaign')
+ .remove('sc_geo')
+ .remove('trk')
+ .remove('sc_publisher')
+ .remove('trkCampaign')
+ .remove('sc_outcome')
+ .remove('sc_country')
+
+ .remove('__hstc')
+ .remove('__hssc')
+ .remove('__hsfp')
+ .remove('_gl')
+
+ // Yahoo News
+ .remove('guce_referrer')
+ .remove('guce_referrer_sig')
+
+ .toString();
+
+ if (s && location.href !== s) {
+ // console.log('Changing URL', s);
+ // location.href = s;
+ oldReplaceState.apply(history, [{}, '', s]);
+ }
+
+ function TrackingTokenStripper(url) {
+ const parsedUrl = new URL(url);
+ return {
+ remove(name, value) {
+ if (parsedUrl.searchParams.has(name)) {
+ if (value && value === parsedUrl.searchParams.get(name)) {
+ parsedUrl.searchParams.delete(name);
+ }
+ if (!value) {
+ parsedUrl.searchParams.delete(name);
+ }
+ }
+ return TrackingTokenStripper(parsedUrl.toString());
+ },
+ removeByDomain(domain, name) {
+ if (parsedUrl.hostname.toLocaleLowerCase() === domain.toLocaleLowerCase()) {
+ if (name.indexOf('=') >= 0) {
+ var [key, value] = name.split("=");
+ return this.remove(key, value);
+ } else {
+ return this.remove(name);
+ }
+ } else {
+ return this;
+ }
+ },
+ toString() {
+ return parsedUrl.toString();
+ }
+ }
+ }
+ }
+
+})();
diff --git a/home/programs/qutebrowser/keybindings.nix b/home/programs/qutebrowser/keybindings.nix
new file mode 100644
index 0000000..5be534a
--- /dev/null
+++ b/home/programs/qutebrowser/keybindings.nix
@@ -0,0 +1,15 @@
+{config, ...}: {
+ programs.qutebrowser.keyBindings = {
+ normal."" = "tab-close";
+ normal."" = "open file://${config.xdg.dataHome}/qutebrowser/bookmarks.html";
+
+ # Ctrl+c is used to leave the current mode and return to normal mode.
+ insert."" = "mode-leave";
+ hint."" = "mode-leave";
+ caret."" = "mode-leave";
+ command."" = "mode-leave";
+ prompt."" = "mode-leave";
+ yesno."" = "mode-leave";
+ register."" = "mode-leave";
+ };
+}
diff --git a/home/programs/qutebrowser/quickmarks.nix b/home/programs/qutebrowser/quickmarks.nix
deleted file mode 100644
index 79ab7e1..0000000
--- a/home/programs/qutebrowser/quickmarks.nix
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- gh = "https://github.com";
- yt = "https://youtube.com";
- pp = "https://account.proton.me";
-}
diff --git a/home/programs/qutebrowser/search.nix b/home/programs/qutebrowser/search.nix
new file mode 100644
index 0000000..27f48e1
--- /dev/null
+++ b/home/programs/qutebrowser/search.nix
@@ -0,0 +1,30 @@
+{...}: {
+ programs.qutebrowser.searchEngines = rec {
+ startpage = "https://www.startpage.com/sp/search?q={}";
+
+ mynixos = "https://mynixos.com/search?q={}";
+ duckduckgo = "https://duckduckgo.com/?q={}";
+ google = "https://google.com/search?hl=en&q={}";
+ yandex = "https://yandex.com/search/?text={}";
+ bing = "https://bing.com/search?q={}";
+ youtube = "https://youtube.com/results?search_query={}";
+ google-images = "https://google.com/search?hl=en&tbm=isch&q={}";
+
+ # AI
+ chatgpt = "https://chatgpt.com/?q={}";
+ claude = "https://claude.ai/new?q={}";
+ gemini = "https://gemini.google.com/app?q={}";
+
+ # Maps
+ amap = "https://maps.apple.com/?q={}";
+ gmap = "https://www.google.com/maps/search/{}";
+
+ # shortcuts
+ g = google;
+ n = mynixos;
+ gpt = chatgpt;
+ gem = gemini;
+ cla = claude;
+ DEFAULT = startpage;
+ };
+}
diff --git a/home/programs/qutebrowser/settings.nix b/home/programs/qutebrowser/settings.nix
new file mode 100644
index 0000000..f02c386
--- /dev/null
+++ b/home/programs/qutebrowser/settings.nix
@@ -0,0 +1,41 @@
+{config, ...}: {
+ programs.qutebrowser = {
+ settings = {
+ url = rec {
+ default_page = "file://${config.xdg.dataHome}/qutebrowser/bookmarks.html";
+ start_pages = [default_page];
+ };
+ new_instance_open_target = "window";
+ "tabs.last_close" = "close";
+ "statusbar.widgets" = ["keypress" "url" "progress"];
+
+ # Adblock
+ "content.blocking.enabled" = true;
+ "content.blocking.method" = "adblock";
+ "content.blocking.adblock.lists" = [
+ "https://easylist.to/easylist/easylist.txt"
+ "https://easylist.to/easylist/easyprivacy.txt"
+ "https://secure.fanboy.co.nz/fanboy-cookiemonster.txt"
+ ];
+
+ # Clipboard access (needed for Excalidraw, Cyberchef, etc.)
+ "content.javascript.clipboard" = "access";
+
+ # Downloads
+ "downloads.location.directory" = "~/Downloads";
+ "downloads.location.prompt" = false;
+
+ # Editor (Ctrl+e in text fields)
+ "editor.command" = ["ghostty" "-e" "nvim" "{}"];
+
+ # Privacy
+ "content.geolocation" = false;
+ "content.cookies.accept" = "no-3rdparty";
+ };
+
+ extraConfig = ''
+ c.statusbar.padding = {'top': 6, 'bottom': 6, 'left': 8, 'right': 8}
+ c.tabs.padding = {'top': 6, 'bottom': 6, 'left': 8, 'right': 8}
+ '';
+ };
+}
diff --git a/home/programs/qutebrowser/userscripts.nix b/home/programs/qutebrowser/userscripts.nix
new file mode 100644
index 0000000..7d391b5
--- /dev/null
+++ b/home/programs/qutebrowser/userscripts.nix
@@ -0,0 +1,27 @@
+{...}: {
+ xdg.dataFile = {
+ # Startpage - hide sponsored results
+ "qutebrowser/greasemonkey/startpage-no-ads.user.js".source =
+ ./greasemonkey/startpage-no-ads.user.js;
+
+ # Return YouTube Dislike
+ "qutebrowser/greasemonkey/return-youtube-dislike.user.js".source =
+ ./greasemonkey/return-youtube-dislike.user.js;
+
+ # SponsorBlock Lite - auto-skip sponsors on YouTube
+ "qutebrowser/greasemonkey/sponsorblock-lite.user.js".source =
+ ./greasemonkey/sponsorblock-lite.user.js;
+
+ # Don't Track Me Google - remove Google tracking redirects
+ "qutebrowser/greasemonkey/dont-track-me-google.user.js".source =
+ ./greasemonkey/dont-track-me-google.user.js;
+
+ # I don't care about cookies - auto-dismiss cookie banners
+ "qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js".source =
+ ./greasemonkey/i-dont-care-about-cookies.user.js;
+
+ # TrackingTokenStripper - remove tracking params from URLs (utm_*, fbclid, etc.)
+ "qutebrowser/greasemonkey/tracking-token-stripper.user.js".source =
+ ./greasemonkey/tracking-token-stripper.user.js;
+ };
+}
diff --git a/home/programs/spicetify/default.nix b/home/programs/spicetify/default.nix
index 254d9d8..00e6cbb 100644
--- a/home/programs/spicetify/default.nix
+++ b/home/programs/spicetify/default.nix
@@ -1,6 +1,7 @@
# Spicetify is a spotify client customizer
{
pkgs,
+ pkgs-stable,
config,
lib,
inputs,
@@ -16,6 +17,7 @@ in {
programs.spicetify = {
enable = true;
+ spotifyPackage = pkgs-stable.spotify;
theme = lib.mkForce spicePkgs.themes.dribbblish;
colorScheme = "custom";
diff --git a/home/programs/thunar/default.nix b/home/programs/thunar/default.nix
index 37c5092..61d32b8 100644
--- a/home/programs/thunar/default.nix
+++ b/home/programs/thunar/default.nix
@@ -1,6 +1,7 @@
# Thunar is a file explorer
{
pkgs,
+ pkgs-stable,
config,
lib,
...
@@ -8,20 +9,24 @@
user = config.var.username;
in {
# ctrl + m to toggle the menubar
- home.packages = with pkgs; [
- thunar
- xfconf
- tumbler
- thunar-archive-plugin
- thunar-volman
- thunar-media-tags-plugin
- p7zip
- xarchiver
- papirus-icon-theme
- material-icons
- material-design-icons
- material-symbols
- ];
+ home.packages =
+ (with pkgs-stable; [
+ xfce.thunar
+ xfce.xfconf
+ xfce.tumbler
+ xfce.thunar-archive-plugin
+ xfce.thunar-volman
+ xfce.thunar-media-tags-plugin
+ p7zip
+ xarchiver
+ ])
+ ++ (with pkgs; [
+ # Icon themes: keep on global pkgs to avoid conflicts with other modules
+ papirus-icon-theme
+ material-icons
+ material-design-icons
+ material-symbols
+ ]);
gtk = {
enable = true;
@@ -30,6 +35,8 @@ in {
package = pkgs.papirus-icon-theme;
};
+ gtk4.theme = null;
+
# bookmarks for the side pane
gtk3.bookmarks = [
"file:///home/${user}/Downloads Downloads"
diff --git a/home/programs/zathura/default.nix b/home/programs/zathura/default.nix
deleted file mode 100644
index 510e3de..0000000
--- a/home/programs/zathura/default.nix
+++ /dev/null
@@ -1,15 +0,0 @@
-# TODO: Misc section with VLC, Zathura etc
-# Zathura is a PDF viewer
-{
- programs.zathura = {
- enable = true;
-
- options = {
- guioptions = "v";
- adjust-open = "width";
- statusbar-basename = true;
- render-loading = false;
- scroll-step = 120;
- };
- };
-}
diff --git a/home/programs/zen/bookmarks.nix b/home/programs/zen/bookmarks.nix
deleted file mode 100644
index 6aa5f41..0000000
--- a/home/programs/zen/bookmarks.nix
+++ /dev/null
@@ -1,171 +0,0 @@
-{
- force = true;
- settings = [
- {
- name = "Bookmarks";
- toolbar = false;
- bookmarks = [
- {
- name = "Mail";
- url = "https://mail.proton.me";
- }
- {
- name = "Drive";
- url = "https://drive.proton.me";
- }
- {
- name = "Lumo";
- url = "https://lumo.proton.me";
- }
- {
- name = "Calendar";
- url = "https://calendar.proton.me";
- }
- {
- name = "Maps";
- url = "https://maps.apple.com";
- }
- {
- name = "Amazon";
- url = "https://amazon.fr";
- }
- {
- name = "Tools";
- bookmarks = [
- {
- name = "tldr";
- url = "https://tldr.inbrowser.app/";
- }
- {
- name = "Excalidraw";
- url = "https://excalidraw.com";
- }
- {
- name = "Cobalt (downloader)";
- url = "https://cobalt.meowing.de";
- }
- {
- name = "Mazanoke (image downgrading)";
- url = "https://mazanoke.hadi.icu";
- }
- {
- name = "Stirling PDF";
- url = "https://pdf.hadi.icu";
- }
- {
- name = "Vert (file converter)";
- url = "https://vert.sh";
- }
- {
- name = "Markdown to pdf";
- url = "https://md2file.com";
- }
- {
- name = "Image to Vector";
- url = "https://www.vectorcascade.com/";
- }
- {
- name = "PrivateBin";
- url = "https://privatebin.net";
- }
- ];
- }
- {
- name = "Social";
- bookmarks = [
- {
- name = "Bsky";
- url = "https://bsky.app";
- }
- {
- name = "Reddit";
- url = "https://reddit.com";
- }
- {
- name = "Youtube";
- url = "https://youtube.com";
- }
- {
- name = "Instagram";
- url = "https://instagram.com";
- }
- {
- name = "Github";
- url = "https://github.com";
- }
- {
- name = "Discord";
- url = "https://discord.com/channels/@me/";
- }
- ];
- }
- {
- name = "Other";
- bookmarks = [
- {
- name = "Startpage config";
- url = "https://www.startpage.com/do/mypage.pl?prfe=45d331deb05471d659dba933e7400df51d952bb103da6f6125c0e769a6be1d65610456a479f495ceeee7e97311cf227d7c1bb198de0ceeb193d8cddf9c455c19a409cc35c3e3f542ee27bd7cecd3";
- }
- {
- name = "Hyprland Wiki";
- url = "https://wiki.hypr.land";
- }
- {
- name = "Search NixOS";
- url = "https://mynixos.com";
- }
- {
- name = "Nixpkgs";
- url = "https://github.com/NixOS/nixpkgs";
- }
- {
- name = "Claude";
- url = "https://claude.ai";
- }
- {
- name = "Gemini";
- url = "https://gemini.google.com";
- }
- {
- name = "Medium";
- url = "https://medium.com";
- }
- ];
- }
- {
- name = "Infosec";
- bookmarks = [
- {
- name = "Nix 4 Cyber";
- url = "https://n4c.hadi.icu";
- }
- {
- name = "Cyberchef";
- url = "https://cyberchef.hadi.icu";
- }
- {
- name = "TryHackMe";
- url = "https://tryhackme.com";
- }
- {
- name = "Root-Me";
- url = "https://root-me.org";
- }
- {
- name = "Exploit-DB";
- url = "https://exploit-db.com";
- }
- {
- name = "Crack Station";
- url = "https://crackstation.net";
- }
- {
- name = "Osint Tracker";
- url = "https://app.osintracker.com";
- }
- ];
- }
- ];
- }
- ];
-}
diff --git a/home/programs/zen/default.nix b/home/programs/zen/default.nix
deleted file mode 100644
index 3df15bd..0000000
--- a/home/programs/zen/default.nix
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- inputs,
- lib,
- pkgs,
- ...
-}: {
- imports = [inputs.zen-browser.homeModules.beta];
-
- stylix.targets.zen-browser.profileNames = ["default"];
-
- home.sessionVariables = {
- MOZ_LEGACY_PROFILES = 1;
- DEFAULT_BROWSER = "zen-beta";
- BROWSER = "zen-beta";
- };
-
- programs.zen-browser = {
- enable = true;
- nativeMessagingHosts = [pkgs.firefoxpwa];
- policies = import ./policies.nix {inherit lib;};
- languagePacks = ["en-US" "fr"];
- profiles = {
- default = {
- id = 0;
- name = "default";
- isDefault = true;
- containersForce = true;
- pinsForce = true;
- spacesForce = true;
-
- settings = import ./settings.nix;
- bookmarks = import ./bookmarks.nix;
- search = import ./search.nix {inherit pkgs;};
- spaces = import ./spaces.nix;
- keyboardShortcuts = import ./keyboard-shortcuts.nix;
-
- extraConfig = ''
- // BETTERFOX
- // ${builtins.readFile "${inputs.betterfox}/user.js"} // The way we do it here, importing the others separately is better
- ${builtins.readFile "${inputs.betterfox}/Fastfox.js"}
- ${builtins.readFile "${inputs.betterfox}/Securefox.js"}
- ${builtins.readFile "${inputs.betterfox}/Peskyfox.js"}
-
- /****************************************************************************
- * START: MY OVERRIDES *
- ****************************************************************************/
- // Visit https://github.com/yokoffing/Betterfox/wiki/Common-Overrides
- // Visit https://github.com/yokoffing/Betterfox/wiki/Optional-Hardening
- // Enter your personal overrides below this line:
-
- // Common Overrides
- user_pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior5,cookieBehaviorPBM5,cm,fp,stp,emailTP,emailTPPrivate,-lvl2,rp,rpTop,ocsp,qps,qpsPBM,fpp,fppPrivate,3pcd,btp"); // https://github.com/yokoffing/Betterfox/wiki/Common-Overrides#example
- user_pref("permissions.default.geo", 0); // https://github.com/yokoffing/Betterfox/wiki/Common-Overrides#location-requests
- user_pref("permissions.default.desktop-notification", 0); // https://github.com/yokoffing/Betterfox/wiki/Common-Overrides#site-notifications
- user_pref("browser.ml.linkPreview.enabled", true); // https://github.com/yokoffing/Betterfox/wiki/Common-Overrides#ai-features
-
- // Optional Hardening
- // Below 2 - https://github.com/yokoffing/Betterfox/wiki/Optional-Hardening#firefox-sync--view
- user_pref("identity.fxaccounts.enabled", false); // PREF: disable Firefox Sync
- user_pref("browser.firefox-view.feature-tour", "{\"screen\":\"\",\"complete\":true}"); // PREF: disable the Firefox View tour from popping up
- // Below 3 - https://github.com/yokoffing/Betterfox/wiki/Optional-Hardening#password-credit-card-and-address-management
- user_pref("signon.rememberSignons", false); // PREF: disable login manager
- user_pref("extensions.formautofill.addresses.enabled", false); // PREF: disable address and credit card manager
- user_pref("extensions.formautofill.creditCards.enabled", false); // PREF: disable address and credit card manager
- // TODO - Future? https://github.com/yokoffing/Betterfox/wiki/Optional-Hardening#secure-dns
- // Below 3 - https://github.com/yokoffing/Betterfox/wiki/Optional-Hardening#downloads
- user_pref("browser.download.useDownloadDir", true); // PREF: use default download directory
- user_pref("browser.download.always_ask_before_handling_new_types", false); // PREF: ask whether to open or save new file types
- user_pref("extensions.postDownloadThirdPartyPrompt", false); // PREF: display the installation prompt for all extensions
- // Below 1 - https://github.com/yokoffing/Betterfox/wiki/Optional-Hardening#public-key-pinning
- user_pref("security.cert_pinning.enforcement_level", 2); // PREF: enforce certificate pinning, [ERROR] MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE, 1 = allow user MiTM (such as your antivirus) (default), 2 = strict
-
- /****************************************************************************
- * SECTION: SMOOTHFOX *
- ****************************************************************************/
- // Visit https://github.com/yokoffing/Betterfox/blob/main/Smoothfox.js
- // Enter your scrolling overrides below this line:
- // Section taken from https://github.com/yokoffing/Betterfox/blob/eee6e58b2b0ee10a59efb6586a5db07ae181d8c7/Smoothfox.js#L28
- // Advice at https://github.com/yokoffing/Betterfox/wiki/Common-Overrides#scrolling
-
- /****************************************************************************************
- * OPTION: INSTANT SCROLLING (SIMPLE ADJUSTMENT) *
- ****************************************************************************************/
- // Recommended for 60hz+ displays
- user_pref("apz.overscroll.enabled", true); // DEFAULT NON-LINUX
- user_pref("general.smoothScroll", true); // DEFAULT
- user_pref("mousewheel.default.delta_multiplier_y", 275); // 250-400; adjust this number to your liking
- // Firefox Nightly only:
- // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1846935
- // user_pref("general.smoothScroll.msdPhysics.enabled", false); // [FF122+ Nightly]
- '';
- };
- };
- };
-}
diff --git a/home/programs/zen/keyboard-shortcuts.nix b/home/programs/zen/keyboard-shortcuts.nix
deleted file mode 100644
index 5ccbab7..0000000
--- a/home/programs/zen/keyboard-shortcuts.nix
+++ /dev/null
@@ -1,299 +0,0 @@
-[
- # Remaps
- {
- id = "focusURLBar";
- key = " ";
- modifiers.control = true;
- }
- {
- id = "key_newNavigator";
- key = "n";
- modifiers.accel = true;
- }
- {
- id = "viewBookmarksToolbarKb";
- key = "b";
- modifiers = {
- accel = true;
- shift = true;
- };
- }
- {
- id = "key_findAgain";
- disabled = true;
- }
- {
- id = "key_findPrevious";
- disabled = true;
- }
- {
- id = "key_privatebrowsing";
- key = "n";
- modifiers = {
- accel = true;
- shift = true;
- };
- }
- {
- id = "key_gotoHistory";
- key = "h";
- modifiers = {
- accel = true;
- shift = true;
- };
- }
- {
- id = "goBackKb";
- key = "h";
- modifiers.accel = true;
- }
- {
- id = "goForwardKb";
- key = "l";
- modifiers.accel = true;
- }
-
- # Disabled shortcuts
- {
- id = "printKb";
- disabled = true;
- }
- {
- id = "zen-close-all-unpinned-tabs";
- disabled = true;
- }
- {
- id = "zen-new-empty-split-view";
- disabled = true;
- }
- {
- id = "zen-split-view-unsplit";
- disabled = true;
- }
- {
- id = "zen-split-view-horizontal";
- disabled = true;
- }
- {
- id = "zen-split-view-vertical";
- disabled = true;
- }
- {
- id = "zen-split-view-grid";
- disabled = true;
- }
- {
- id = "zen-glance-expand";
- disabled = true;
- }
- {
- id = "zen-toggle-pin-tab";
- disabled = true;
- }
- {
- id = "zen-toggle-sidebar";
- disabled = true;
- }
- {
- id = "zen-new-unsynced-window";
- disabled = true;
- }
- {
- id = "key_closeWindow";
- disabled = true;
- }
- {
- id = "key_quitApplication";
- disabled = true;
- }
- {
- id = "key_search";
- disabled = true;
- }
- {
- id = "key_search2";
- disabled = true;
- }
- {
- id = "focusURLBar2";
- disabled = true;
- }
- {
- id = "key_savePage";
- disabled = true;
- }
- {
- id = "key_togglePictureInPicture";
- disabled = true;
- }
- {
- id = "showAllHistoryKb";
- disabled = true;
- }
- {
- id = "addBookmarkAsKb";
- disabled = true;
- }
- {
- id = "manBookmarkKb";
- disabled = true;
- }
- {
- id = "viewBookmarksSidebarKb";
- key = "b";
- modifiers = {
- accel = true;
- };
- }
- {
- id = "key_toggleMute";
- disabled = true;
- }
- {
- id = "key_switchTextDirection";
- disabled = true;
- }
- {
- id = "key_screenshot";
- disabled = true;
- }
- {
- id = "key_viewInfo";
- disabled = true;
- }
- {
- id = "key_toggleToolbox";
- disabled = true;
- }
- {
- id = "key_browserToolbox";
- disabled = true;
- }
- {
- id = "key_browserConsole";
- disabled = true;
- }
- {
- id = "key_responsiveDesignMode";
- disabled = true;
- }
- {
- id = "key_inspector";
- disabled = true;
- }
- {
- id = "key_webconsole";
- key = "i";
- modifiers = {
- accel = true;
- shift = true;
- };
- }
- {
- id = "key_jsdebugger";
- disabled = true;
- }
- {
- id = "key_netmonitor";
- disabled = true;
- }
- {
- id = "key_styleeditor";
- disabled = true;
- }
- {
- id = "key_performance";
- disabled = true;
- }
- {
- id = "key_storage";
- disabled = true;
- }
- {
- id = "key_dom";
- disabled = true;
- }
- {
- id = "key_accessibility";
- disabled = true;
- }
- {
- id = "key_openDownloads";
- disabled = true;
- }
- {
- id = "key_openAddons";
- disabled = true;
- }
- {
- id = "key_reload";
- key = "r";
- modifiers = {
- accel = true;
- };
- }
- {
- id = "key_reload2";
- disabled = true;
- }
- {
- id = "key_reload_skip_cache";
- key = "r";
- modifiers = {
- accel = true;
- shift = true;
- };
- }
- {
- id = "key_reload_skip_cache2";
- disabled = true;
- }
- {
- id = "key_enterFullScreen";
- disabled = true;
- }
- {
- id = "key_exitFullScreen";
- disabled = true;
- }
- {
- id = "key_aboutProcesses";
- disabled = true;
- }
- {
- id = "viewGenaiChatSidebarKb";
- disabled = true;
- }
- {
- id = "toggleSidebarKb";
- disabled = true;
- }
- {
- id = "key_showAllTabs";
- disabled = true;
- }
- {
- id = "key_sanitize";
- disabled = true;
- }
- {
- id = "key_wrCaptureCmd";
- disabled = true;
- }
- {
- id = "key_wrToggleCaptureSequenceCmd";
- disabled = true;
- }
- {
- id = "goHome";
- disabled = true;
- }
- {
- id = "goBackKb2";
- disabled = true;
- }
- {
- id = "goForwardKb2";
- disabled = true;
- }
-]
diff --git a/home/programs/zen/policies.nix b/home/programs/zen/policies.nix
deleted file mode 100644
index 0face3c..0000000
--- a/home/programs/zen/policies.nix
+++ /dev/null
@@ -1,44 +0,0 @@
-{...}: {
- ExtensionSettings = {
- "*" = {
- blocked_install_message = "The addon you are trying to install is not added in the Nix config";
- installation_mode = "blocked";
- };
- "adnauseam@rednoise.org" = {
- private_browsing = true;
- installation_mode = "force_installed";
- install_url = "https://addons.mozilla.org/firefox/downloads/latest/adnauseam/latest.xpi";
- };
- "78272b6fa58f4a1abaac99321d503a20@proton.me" = {
- private_browsing = true;
- default_area = "navbar";
- installation_mode = "force_installed";
- install_url = "https://addons.mozilla.org/firefox/downloads/latest/proton-pass/latest.xpi";
- };
- "{d7742d87-e61d-4b78-b8a1-b469842139fa}" = {
- private_browsing = true;
- installation_mode = "force_installed";
- install_url = "https://addons.mozilla.org/firefox/downloads/latest/vimium-ff/latest.xpi";
- };
- "jid1-MnnxcxisBPnSXQ@jetpack" = {
- private_browsing = true;
- installation_mode = "force_installed";
- install_url = "https://addons.mozilla.org/firefox/downloads/latest/privacy-badger17/latest.xpi";
- };
- # View Xpi Id's in Firefox Extension Store
- "queryamoid@kaply.com" = {
- private_browsing = true;
- installation_mode = "force_installed";
- install_url = "https://github.com/mkaply/queryamoid/releases/download/v0.2/query_amo_addon_id-0.2-fx.xpi";
- };
- };
- "3rdparty".Extensions = {
- "adnauseam@rednoise.org" = {
- enabled = true;
- firstInstall = false;
- hidingAds = true;
- clickingAds = true;
- blockingMalware = true;
- };
- };
-}
diff --git a/home/programs/zen/search.nix b/home/programs/zen/search.nix
deleted file mode 100644
index 3c43fb5..0000000
--- a/home/programs/zen/search.nix
+++ /dev/null
@@ -1,162 +0,0 @@
-{pkgs, ...}: {
- force = true;
- default = "Startpage";
- privateDefault = "Startpage";
- order = [
- "Startpage"
- "Gooogle"
- "Gooogle (Web)"
- "NixOS Packages"
- "NixOS Options"
- "NixOS Wiki"
- "Home Manager"
- "My NixOS"
- "Noogle"
- "ChatGPT"
- "Claude"
- "Gemini"
- "Yandex"
- "Google Maps"
- ];
- engines = let
- nix-icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
- google-icon = "https://www.gstatic.com/images/branding/searchlogo/ico/favicon.ico";
- in {
- "Gooogle" = {
- urls = [
- {
- template = "https://www.google.com/search?num=50&q={searchTerms}";
- }
- ];
- icon = google-icon;
- definedAliases = ["@gs" "@google"];
- };
- "Gooogle (Web)" = {
- urls = [
- {
- template = "https://www.google.com/search?num=50&udm=14&q={searchTerms}";
- }
- ];
- icon = google-icon;
- definedAliases = ["@gw" "@googleweb"];
- };
- "Startpage" = {
- urls = [
- {
- template = "https://www.startpage.com/sp/search?query={searchTerms}";
- }
- ];
- icon = "https://www.startpage.com/sp/cdn/favicons/favicon-gradient.ico";
- definedAliases = ["@sp"];
- updateInterval = 24 * 60 * 60 * 1000;
- };
- "NixOS Packages" = {
- urls = [
- {
- template = "https://search.nixos.org/packages";
- params = [
- {
- name = "type";
- value = "packages";
- }
- {
- name = "query";
- value = "{searchTerms}";
- }
- ];
- }
- ];
- icon = nix-icon;
- definedAliases = [
- "@np"
- "@nixpkgs"
- ];
- };
- "NixOS Options" = {
- urls = [
- {
- template = "https://search.nixos.org/options";
- params = [
- {
- name = "type";
- value = "packages";
- }
- {
- name = "query";
- value = "{searchTerms}";
- }
- ];
- }
- ];
- icon = nix-icon;
- definedAliases = [
- "@no"
- "@nixopts"
- ];
- };
- "NixOS Wiki" = {
- urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}];
- icon = nix-icon;
- updateInterval = 24 * 60 * 60 * 1000; # every day
- definedAliases = ["@nw"];
- };
- "Home Manager" = {
- urls = [{template = "https://home-manager-options.extranix.com/?query={searchTerms}";}];
- icon = nix-icon;
- definedAliases = [
- "@hm"
- "@home"
- "'homeman"
- ];
- };
- "My NixOS" = {
- urls = [{template = "https://mynixos.com/search?q={searchTerms}";}];
- icon = nix-icon;
- definedAliases = [
- "@n"
- "@nx"
- "@mynixos"
- ];
- };
- "ChatGPT" = {
- urls = [
- {template = "https://chat.openai.com/?q={searchTerms}";}
- ];
- icon = "https://chatgpt.com/cdn/assets/favicon-eex17e9e.ico";
- definedAliases = ["@cg" "@chatgpt"];
- };
- "Claude" = {
- urls = [
- {template = "https://claude.ai/new?q={searchTerms}";}
- ];
- icon = "https://claude.ai/favicon.ico";
- definedAliases = ["@claude" "@cl"];
- };
- "Gemini" = {
- urls = [
- {template = "https://gemini.google.com/app?q={searchTerms}";}
- ];
- icon = "https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06.svg";
- definedAliases = ["@gemini" "@gm"];
- };
- "Yandex" = {
- urls = [
- {template = "https://yandex.com/search/?text={searchTerms}";}
- ];
- icon = "https://yandex.com/favicon.ico";
- definedAliases = ["@yandex" "@ya"];
- };
- "Google Maps" = {
- urls = [
- {template = "https://www.google.com/maps/search/{searchTerms}";}
- ];
- icon = "https://www.google.com/images/branding/product/ico/maps15_bnuw3a_32dp.ico";
- definedAliases = ["@maps" "@gmaps"];
- };
- "bing".metaData.hidden = true;
- "ddg".metaData.hidden = true;
- "ebay".metaData.hidden = true;
- "google".metaData.hidden = true;
- "Perplexity".metaData.hidden = true;
- };
-}
diff --git a/home/programs/zen/settings.nix b/home/programs/zen/settings.nix
deleted file mode 100644
index 195f326..0000000
--- a/home/programs/zen/settings.nix
+++ /dev/null
@@ -1,66 +0,0 @@
-let
- lock-false = {
- Value = false;
- Status = "locked";
- };
- lock-true = {
- Value = true;
- Status = "locked";
- };
-in {
- # NO LONGER NEEDED WITH https://zen-browser.app/mods/e122b5d9-d385-4bf8-9971-e137809097d0/?page=3 YAY!
- "browser.newtabpage.activity-stream.feeds.system.topsites" = true;
- "browser.newtabpage.activity-stream.feeds.system.topstories" = true;
-
- "browser.aboutwelcome.enabled" = false;
- "browser.ctrlTab.sortByRecentlyUsed" = false;
- "browser.startup.page" = 1;
- "browser.startup.firstrunSkipsHomepage" = true;
- "browser.startup.homepage_override.mstone" = "ignore";
- "trailhead.firstrun.didSeeAboutWelcome" = true;
-
- # Do not tell what plugins we have enabled: https://mail.mozilla.org/pipermail/firefox-dev/2013-November/001186.html
- "plugins.enumerable_names" = "";
- "plugin.state.flash" = 0;
- "browser.search.update" = false;
- "extensions.getAddons.cache.enabled" = lock-false;
- "extensions.ui.sitepermission.hidden" = lock-true;
- "extensions.ui.locale.hidden" = lock-true;
-
- "layout.css.devPixelsPerPx" = -1;
- # "zen.theme.accent-color" = "#ffb787";
- "zen.theme.acrylic-elements" = false;
- "zen.theme.border-radius" = 8;
- "zen.theme.content-element-separation" = 0;
- "zen.theme.dark-mode-bias" = 0.3;
- # "zen.theme.disable-lightweight" = true; Depracated https://github.com/zen-browser/desktop/issues/9522#issuecomment-3089206722
- "zen.theme.essentials-favicon-bg" = true;
- "zen.theme.gradient" = true;
- "zen.theme.gradient.show-custom-colors" = false;
- "zen.theme.hide-tab-throbber" = true;
- "zen.theme.show-custom-colors" = true;
- "zen.theme.styled-status-panel" = false;
- "zen.theme.use-sysyem-colors" = false;
- "zen.theme.use-system-colors" = false;
-
- "zen.urlbar.behavior" = "normal";
- "zen.urlbar.replace-newtab" = true;
-
- "zen.view.compact.enable-at-startup" = false;
- "zen.view.compact.hide-tabbar" = true;
- "zen.view.compact.hide-toolbar" = true;
- "zen.view.experimental-no-window-controls" = true;
- "zen.view.sidebar-expanded" = false;
- "zen.view.use-single-toolbar" = true;
-
- "zen.glance.enabled" = false;
- "zen.tabs.show-newtab-vertical" = false;
- "zen.window-sync.enabled" = false;
-
- "privacy.userContext.enabled" = false;
- "privacy.userContext.ui.enabled" = false;
-
- "zen.watermark.enabled" = false;
- "zen.welcome-screen.seen" = lock-true;
- "zen.widget.linux.transparency" = false; # Disable transparent sidebar
-}
diff --git a/home/programs/zen/spaces.nix b/home/programs/zen/spaces.nix
deleted file mode 100644
index 8872839..0000000
--- a/home/programs/zen/spaces.nix
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- Home = {
- id = "1f8a6f7c-3b59-4d65-9c1f-0a3e9a6f1b01";
- icon = "🏠";
- position = 1000;
- };
-
- Infosec = {
- id = "2b9d4c41-6a8e-4c9b-9a44-6d1c7f2e8b02";
- icon = "🔒";
- position = 2000;
- };
-}
diff --git a/home/system/hyprland/bindings.nix b/home/system/hyprland/bindings.nix
index 5550156..ae21279 100644
--- a/home/system/hyprland/bindings.nix
+++ b/home/system/hyprland/bindings.nix
@@ -66,61 +66,18 @@ in {
}
{
key = "b";
- desc = "Zen Browser";
- cmd = "zen-beta";
+ desc = "Qutebrowser";
+ cmd = "${pkgs.qutebrowser}/bin/qutebrowser";
}
{
key = "i";
- desc = "Zen Browser (Private window)";
- cmd = "zen-beta --private-window";
+ desc = "Qutebrowser (Temp session)";
+ cmd = "${pkgs.qutebrowser}/bin/qutebrowser --temp-basedir";
}
]))
# Web links
- "$mod,B, exec, uwsm app -- zen-beta" # Browser (Zen)
- ("$shiftMod, B, exec, "
- + lib.getExe (mkMenu [
- {
- key = "h";
- desc = "Home";
- cmd = "zen-beta 'https://home.hadi.icu'";
- }
- {
- key = "m";
- desc = "Proton Mail";
- cmd = "zen-beta 'https://mail.proton.me/u/2/inbox'";
- }
- {
- key = "c";
- desc = "Proton Calendar";
- cmd = "zen-beta 'https://calendar.proton.me/u/2'";
- }
- {
- key = "l";
- desc = "Proton Lumo";
- cmd = "zen-beta 'https://lumo.proton.me/u/2'";
- }
- {
- key = "d";
- desc = "Proton Drive";
- cmd = "zen-beta 'https://drive.proton.me/u/2/'";
- }
- {
- key = "G";
- desc = "Google Gemini";
- cmd = "zen-beta 'https://gemini.google.com/'";
- }
- {
- key = "g";
- desc = "Github";
- cmd = "zen-beta 'https://github.com/'";
- }
- {
- key = "n";
- desc = "MyNixos";
- cmd = "zen-beta 'https://mynixos.com/'";
- }
- ]))
+ "$mod,B, exec, uwsm app -- ${pkgs.qutebrowser}/bin/qutebrowser" # Browser (Qutebrowser)
# Power
"$mod, X, global, caelestia:session" # Powermenu
diff --git a/home/system/hyprland/default.nix b/home/system/hyprland/default.nix
index 00d47fe..4051cdf 100644
--- a/home/system/hyprland/default.nix
+++ b/home/system/hyprland/default.nix
@@ -39,13 +39,9 @@ in {
wlr-randr
brightnessctl
gnome-themes-extra
- libva
dconf
wayland-utils
wayland-protocols
- glib
- direnv
- meson
];
wayland.windowManager.hyprland = {
@@ -74,25 +70,16 @@ in {
env = [
"XDG_CURRENT_DESKTOP,Hyprland"
- "MOZ_ENABLE_WAYLAND,1"
- "ANKI_WAYLAND,1"
- "DISABLE_QT5_COMPAT,0"
- "NIXOS_OZONE_WL,1"
"XDG_SESSION_TYPE,wayland"
"XDG_SESSION_DESKTOP,Hyprland"
+ "ANKI_WAYLAND,1"
+ "DISABLE_QT5_COMPAT,0"
"QT_AUTO_SCREEN_SCALE_FACTOR,1"
"QT_QPA_PLATFORM,wayland;xcb"
"QT_QPA_PLATFORMTHEME,gtk3"
"QT_WAYLAND_DISABLE_WINDOWDECORATION,1"
"ELECTRON_OZONE_PLATFORM_HINT,auto"
- "__GL_GSYNC_ALLOWED,0"
- "__GL_VRR_ALLOWED,0"
- "DISABLE_QT5_COMPAT,0"
"DIRENV_LOG_FORMAT,"
- "WLR_DRM_NO_ATOMIC,1"
- "WLR_BACKEND,vulkan"
- "WLR_RENDERER,vulkan"
- "WLR_NO_HARDWARE_CURSORS,1"
"SDL_VIDEODRIVER,wayland"
"CLUTTER_BACKEND,wayland"
];
@@ -130,7 +117,7 @@ in {
};
master = {
- new_status = true;
+ new_status = "slave";
allow_small_split = true;
mfact = 0.5;
};
@@ -139,9 +126,6 @@ in {
windowrule = [
"match:class .*, suppress_event maximize"
- "match:class zen-beta, suppress_event float"
-
- "match:class zen-beta, sync_fullscreen 0"
"match:class proton-authenticator, float on"
"match:class proton-authenticator, center on"
diff --git a/hosts/laptop/configuration.nix b/hosts/laptop/configuration.nix
index e417037..0d5702e 100644
--- a/hosts/laptop/configuration.nix
+++ b/hosts/laptop/configuration.nix
@@ -12,8 +12,6 @@
../../nixos/users.nix
../../nixos/utils.nix
../../nixos/hyprland.nix
- ../../nixos/docker.nix
- ../../nixos/clamav.nix
../../nixos/omen.nix # CHANGEME: For my laptop only, remove this (OMEN 16)
diff --git a/hosts/laptop/home.nix b/hosts/laptop/home.nix
index 1946cc5..aa61fb8 100644
--- a/hosts/laptop/home.nix
+++ b/hosts/laptop/home.nix
@@ -12,18 +12,17 @@
../../home/programs/ghostty
../../home/programs/nvf
../../home/programs/shell
- ../../home/programs/fetch
../../home/programs/git
../../home/programs/git/lazygit.nix
- ../../home/programs/git/signing.nix # Change the key or remove this file
+ ../../home/programs/git/signing.nix # CHANGEME: Change the key or remove this file
../../home/programs/spicetify
../../home/programs/thunar
../../home/programs/nixy
- ../../home/programs/zathura
../../home/programs/nightshift
+ ../../home/programs/qutebrowser
../../home/programs/nix-utils
- ../../home/programs/zen
+ ../../home/programs/group/basic-apps.nix
../../home/programs/group/cybersecurity.nix
../../home/programs/group/dev.nix
../../home/programs/group/misc.nix
@@ -40,31 +39,8 @@
];
home = {
- packages = with pkgs; [
- # Apps
- vlc # Video player
- blanket # White-noise app
- obsidian # Note taking app
- textpieces # Manipulate texts
- resources # Ressource monitor
- gnome-clocks # Clocks app
- gnome-text-editor # Basic graphic text editor
- mpv # Video player
- ticktick # Todo app
- session-desktop # Session app, private messages
- signal-desktop # Signal app, private messages
- stirling-pdf # PDF Editor
- calibre # Ebooks
- swappy # Screenshot tool
- pinta # Image editor
- element-desktop
- clamtk
- ];
-
inherit (config.var) username;
homeDirectory = "/home/" + config.var.username;
-
- # Import a profile picture, used by the caelestia dashboard
file.".face" = {source = ./profile_picture.png;};
sessionVariables = {
diff --git a/hosts/pph/configuration.nix b/hosts/pph/configuration.nix
deleted file mode 100644
index 99a8315..0000000
--- a/hosts/pph/configuration.nix
+++ /dev/null
@@ -1,25 +0,0 @@
-{config, ...}: {
- imports = [
- # Mostly system related configuration
- ../../nixos/audio.nix
- ../../nixos/bluetooth.nix
- ../../nixos/fonts.nix
- ../../nixos/home-manager.nix
- ../../nixos/nix.nix
- ../../nixos/systemd-boot.nix
- ../../nixos/sddm.nix
- ../../nixos/users.nix
- ../../nixos/utils.nix
- ../../nixos/hyprland.nix
- ../../nixos/docker.nix
-
- # You should let those lines as is
- ./hardware-configuration.nix
- ./variables.nix
- ];
-
- home-manager.users."${config.var.username}" = import ./home.nix;
-
- # Don't touch this
- system.stateVersion = "24.05";
-}
diff --git a/hosts/pph/hardware-configuration.nix b/hosts/pph/hardware-configuration.nix
deleted file mode 100644
index 900e023..0000000
--- a/hosts/pph/hardware-configuration.nix
+++ /dev/null
@@ -1,31 +0,0 @@
-# Do not modify this file! It was generated by ‘nixos-generate-config’
-# and may be overwritten by future invocations. Please make changes
-# to /etc/nixos/configuration.nix instead.
-{ config, lib, pkgs, modulesPath, ... }:
-
-{
- imports =
- [ (modulesPath + "/installer/scan/not-detected.nix")
- ];
-
- boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod" ];
- boot.initrd.kernelModules = [ ];
- boot.kernelModules = [ "kvm-intel" ];
- boot.extraModulePackages = [ ];
-
- fileSystems."/" =
- { device = "/dev/disk/by-uuid/5dbf85d3-d236-4af8-b489-d6066bfe1eb7";
- fsType = "ext4";
- };
-
- fileSystems."/boot" =
- { device = "/dev/disk/by-uuid/043E-1755";
- fsType = "vfat";
- options = [ "fmask=0077" "dmask=0077" ];
- };
-
- swapDevices = [ ];
-
- nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
- hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
-}
diff --git a/hosts/pph/home.nix b/hosts/pph/home.nix
deleted file mode 100644
index c858209..0000000
--- a/hosts/pph/home.nix
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- pkgs,
- config,
- ...
-}: {
- imports = [
- # Programs
- ../../home/programs/brave
- ../../home/programs/ghostty
- ../../home/programs/nvf
- ../../home/programs/shell
- ../../home/programs/fetch
- ../../home/programs/git
- ../../home/programs/git/lazygit.nix
- ../../home/programs/thunar
- ../../home/programs/nixy
- ../../home/programs/zathura
- ../../home/programs/nightshift
- ../../home/programs/proton
- ../../home/programs/nix-utils
- ../../home/programs/zen
- ../../home/programs/qutebrowser
-
- ../../home/programs/group/cybersecurity.nix
- ../../home/programs/group/dev.nix
- ../../home/programs/group/misc.nix
-
- # System (Desktop environment like stuff)
- ../../home/system/hyprland
- ../../home/system/caelestia-shell
- ../../home/system/hyprpaper
- ../../home/system/mime
- ../../home/system/udiskie
-
- ./variables.nix # Mostly user-specific configuration
- ./secrets
- ];
-
- home = {
- packages = with pkgs; [
- # Apps
- vlc # Video player
- obsidian # Note taking app
- textpieces # Manipulate texts
- resources # Ressource monitor
- gnome-clocks # Clocks app
- gnome-text-editor # Basic graphic text editor
- mpv # Video player
- swappy # Screenshot tool
- pinta # Image editor
- libreoffice
- ];
-
- inherit (config.var) username;
- homeDirectory = "/home/" + config.var.username;
-
- # Don't touch this
- stateVersion = "24.05";
- };
-
- programs.home-manager.enable = true;
-}
diff --git a/hosts/pph/secrets/default.nix b/hosts/pph/secrets/default.nix
deleted file mode 100644
index 607375c..0000000
--- a/hosts/pph/secrets/default.nix
+++ /dev/null
@@ -1,43 +0,0 @@
-# Those are my secrets, encrypted with sops
-# You shouldn't import this file, unless you edit it
-{
- pkgs,
- inputs,
- ...
-}: {
- imports = [inputs.sops-nix.homeManagerModules.sops];
-
- sops = {
- age.keyFile = "/home/hadrien/.config/sops/age/keys.txt";
- defaultSopsFile = ./secrets.yaml;
- secrets = {
- ssh-config = {path = "/home/hadrien/.ssh/config";};
- github-key = {path = "/home/hadrien/.ssh/github";};
- gitlab-key = {path = "/home/hadrien/.ssh/gitlab";};
- };
- };
-
- home.file.".config/nixos/.sops.yaml".text = ''
- keys:
- - &primary age12yvtj49pfh3fqzqflscm0ek4yzrjhr6cqhn7x89gdxnlykq0xudq5c7334
- - &work age1c8pawdsxptfslgrz2c56s39mrtnjzc5mm3hfzgr2wdwu2v6vfsdsupjsq6
- creation_rules:
- - path_regex: hosts/laptop/secrets/secrets.yaml$
- key_groups:
- - age:
- - *primary
- - path_regex: hosts/server/secrets/secrets.yaml$
- key_groups:
- - age:
- - *primary
- - path_regex: hosts/pph/secrets/secrets.yaml$
- key_groups:
- - age:
- - *work
- '';
-
- systemd.user.services.mbsync.Unit.After = ["sops-nix.service"];
- home.packages = with pkgs; [sops age];
-
- wayland.windowManager.hyprland.settings.exec-once = ["systemctl --user start sops-nix"];
-}
diff --git a/hosts/pph/secrets/secrets.yaml b/hosts/pph/secrets/secrets.yaml
deleted file mode 100644
index 70c2974..0000000
--- a/hosts/pph/secrets/secrets.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-ssh-config: ENC[AES256_GCM,data:jtot9nSlaS/zmVqGEDACG4HarHFnpw3QMLdYGOvHI1rzjFm+FuIw+MXtPBaDT2rWO59XKchp31X2rik6igNoY9iuQ/uncFWonkb8RTOV6zG/BC32cFf08nNmp75slr1y/YA8rc2kM4An81Zq27g0e9AKyRVRqmvI3HEQq/1mpWF8OJpSfdggCIylGQezB2Vy3Ik2hJyoJaf7BSaikN1/jPzaImpPi2OOrREydePuZjX8D0DqM2xm+LUSsUpXutsKWDaaeuMAqWfjH1svOvT4+oyMBoqrp2+ijP7vRjFeuYrxaU858YzDi0+bTdzn8umlAr6rjLZW+9JUKDog5Fja5j/WvIk1PClqfXCX1+hCX4GlAdV3FYTn,iv:vQuRDKuidQFl4u7bQlAEAf3s8kYBdNwmXO6JbcRV32k=,tag:yv7NHfncDwjy9OGrTZI57A==,type:str]
-github-key: ENC[AES256_GCM,data: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,iv:7SuHnThyDeOMpDMZ5/LCiyxsFvzkNwEV8xpL56FI/qw=,tag:4CLUrclfHQU+2M1OxLtw7w==,type:str]
-gitlab-key: ENC[AES256_GCM,data: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,iv:IKHMuKQt7rsbUfzosTloCS5YF8Xt9RhCaw5qM9wt0HE=,tag:cgMQRQzix3HnO0lEwh4Q2g==,type:str]
-sops:
- age:
- - recipient: age1c8pawdsxptfslgrz2c56s39mrtnjzc5mm3hfzgr2wdwu2v6vfsdsupjsq6
- enc: |
- -----BEGIN AGE ENCRYPTED FILE-----
- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvelBDQ2FYR3dvRHl6dUc4
- UmwyZXhKL3JyS09JSUxZUFEzdmlTQk4xZFJRCm9vQmlzUzlZelZCWlVTVzJEN3N1
- MXV1RGZSTHN2KzBRVDdvQURGTE1PZUUKLS0tIEp6UlZsZlFORUVSb0w0ZERsQ1pB
- Szd1TDFqQ016WWd1SFowN0ptcGlyRGcKRH424S/7enLTuACcJyFUdbIgsUl0U/5i
- 6WRrU0kHesh0gcxU1QMvLKiUZdYwo+pFoDWZiocNUKlEt49isncMrQ==
- -----END AGE ENCRYPTED FILE-----
- lastmodified: "2026-03-16T08:42:01Z"
- mac: ENC[AES256_GCM,data:RbYlNcntZ9k4t469eq5AO4CJQ2zSWetFYz3K14sN4vwAvYgErkvVZSQvzaTPuBpfNCFxTnfSH/d73EZvqTskfBElef6TgPK6EiDV5hMfz5sdnZmc97+le+Uvzs0c6Y38faKfs4ZrqtbMRIH1YuWpnLKfJmfCPIFayeEoockgbTs=,iv:P32AWbPLsV68Ee4G+AiBkDdKHm3vZngtJGz0D+lz58Y=,tag:AQYyAoxY+CpT6GawCQw+xw==,type:str]
- unencrypted_suffix: _unencrypted
- version: 3.11.0
diff --git a/hosts/pph/variables.nix b/hosts/pph/variables.nix
deleted file mode 100644
index f8a3561..0000000
--- a/hosts/pph/variables.nix
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- config,
- lib,
- ...
-}: {
- imports = [
- # Choose your theme here:
- ../../themes/zen.nix
- ];
-
- config.var = {
- hostname = "pph";
- username = "hadrien";
- configDirectory =
- "/home/"
- + config.var.username
- + "/.config/nixos"; # The path of the nixos configuration directory
-
- keyboardLayout = "fr";
-
- location = "Paris";
- timeZone = "Europe/Paris";
- defaultLocale = "en_US.UTF-8";
- extraLocale = "fr_FR.UTF-8";
-
- git = {
- username = "pph";
- email = "pph@pph.pph";
- };
-
- autoUpgrade = false;
- autoGarbageCollector = true;
- };
-
- # DON'T TOUCH THIS
- options = {
- var = lib.mkOption {
- type = lib.types.attrs;
- default = {};
- };
- };
-}
diff --git a/hosts/server/configuration.nix b/hosts/server/configuration.nix
index 429e6e5..4f2be5c 100644
--- a/hosts/server/configuration.nix
+++ b/hosts/server/configuration.nix
@@ -15,7 +15,6 @@
../../server-modules/glance
../../server-modules/adguardhome.nix
../../server-modules/arr.nix
- # ../../server-modules/eleakxir.nix
../../server-modules/blog.nix
../../server-modules/awesome-wallpapers.nix
../../server-modules/iknowyou.nix
diff --git a/hosts/server/home.nix b/hosts/server/home.nix
index 29638e7..208a9c7 100644
--- a/hosts/server/home.nix
+++ b/hosts/server/home.nix
@@ -10,36 +10,18 @@
# Programs
../../home/programs/nvf
../../home/programs/shell
- ../../home/programs/fetch
../../home/programs/git
../../home/programs/git/lazygit.nix
../../home/programs/nixy
../../home/programs/nix-utils
+
+ ../../home/programs/group/dev.nix
];
home = {
inherit (config.var) username;
homeDirectory = "/home/" + config.var.username;
- packages = with pkgs; [
- # Dev
- go
- nodejs
- python3
- jq
- just
- pnpm
- wireguard-tools
- duckdb
- claude-code
-
- # Utils
- zip
- unzip
- btop
- fastfetch
- ];
-
# Don't touch this
stateVersion = "24.05";
};
diff --git a/nixos/clamav.nix b/nixos/clamav.nix
deleted file mode 100644
index 8e3cd87..0000000
--- a/nixos/clamav.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-{pkgs, ...}: {
- environment.systemPackages = with pkgs; [
- clamav
- ];
-
- services.clamav = {
- daemon.enable = true;
- updater.enable = true;
- scanner.enable = true;
- fangfrisch.enable = true;
- };
-}
diff --git a/nixos/home-manager.nix b/nixos/home-manager.nix
index 7913cc0..aa69cfc 100644
--- a/nixos/home-manager.nix
+++ b/nixos/home-manager.nix
@@ -1,9 +1,15 @@
# Home-manager configuration for NixOS
-{inputs, ...}: {
+{inputs, pkgs, ...}: {
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
backupFileExtension = "hm-backup";
- extraSpecialArgs = {inherit inputs;};
+ extraSpecialArgs = {
+ inherit inputs;
+ pkgs-stable = import inputs.nixpkgs-stable {
+ system = pkgs.stdenv.hostPlatform.system;
+ config.allowUnfree = true;
+ };
+ };
};
}
diff --git a/nixos/nvidia.nix b/nixos/nvidia.nix
index c0beca1..f71f130 100644
--- a/nixos/nvidia.nix
+++ b/nixos/nvidia.nix
@@ -15,7 +15,6 @@ in {
boot.kernelParams = [
"nvidia-drm.modeset=1" # Enable mode setting for Wayland
"nvidia.NVreg_PreserveVideoMemoryAllocations=1" # Improves resume after sleep
- "nvidia.NVreg_RegistryDwords=PowerMizerEnable=0x1;PerfLevelSrc=0x2222;PowerMizerLevel=0x3;PowerMizerDefault=0x3;PowerMizerDefaultAC=0x3" # Performance/power optimizations
];
# Blacklist nouveau to avoid conflicts
@@ -24,14 +23,11 @@ in {
# Environment variables for better compatibility
environment.variables = {
LIBVA_DRIVER_NAME = "nvidia"; # Hardware video acceleration
- XDG_SESSION_TYPE = "wayland"; # Force Wayland
GBM_BACKEND = "nvidia-drm"; # Graphics backend for Wayland
__GLX_VENDOR_LIBRARY_NAME = "nvidia"; # Use Nvidia driver for GLX
- WLR_NO_HARDWARE_CURSORS = "1"; # Fix for cursors on Wayland
NIXOS_OZONE_WL = "1"; # Wayland support for Electron apps
__GL_GSYNC_ALLOWED = "1"; # Enable G-Sync if available
__GL_VRR_ALLOWED = "1"; # Enable VRR (Variable Refresh Rate)
- WLR_DRM_NO_ATOMIC = "1"; # Fix for some issues with Hyprland
NVD_BACKEND = "direct"; # Configuration for new driver
MOZ_ENABLE_WAYLAND = "1"; # Wayland support for Firefox
};
@@ -73,7 +69,6 @@ in {
# Enhanced graphics support
graphics = {
enable = true;
- package = nvidiaDriverChannel;
enable32Bit = true;
extraPackages = with pkgs; [
nvidia-vaapi-driver
diff --git a/nixos/utils.nix b/nixos/utils.nix
index 10763c2..8cdd63a 100644
--- a/nixos/utils.nix
+++ b/nixos/utils.nix
@@ -57,9 +57,6 @@ in {
XDG_DATA_HOME = "$HOME/.local/share";
PASSWORD_STORE_DIR = "$HOME/.local/share/password-store";
EDITOR = "nvim";
- TERMINAL = "ghostty";
- TERM = "ghostty";
- BROWSER = "zen-beta";
};
services.libinput.enable = true;