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='' - black='' - red='' - green='' - yellow='' - blue='' - magenta='' - cyan='' - white='' - grey='' - reset='' - - ## 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 + + + +
+

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", + ` +
+
+
+
+
+
+ + ${tooltipInnerHTML} + +
+`, + ); + 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;