nix-configs

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit c6245f319188fe2dc5351b9ac499d80ea97fff53
Author: breadcat <breadcat@users.noreply.github.com>
Date:   Mon, 14 Jul 2025 15:33:23 +0100

Initial commit

Diffstat:
A.gitignore | 2++
Acommon/audio.nix | 9+++++++++
Acommon/emulators.nix | 26++++++++++++++++++++++++++
Acommon/flakes.nix | 3+++
Acommon/fonts.nix | 7+++++++
Acommon/garbage.nix | 8++++++++
Acommon/locale.nix | 18++++++++++++++++++
Acommon/media-sort.nix | 24++++++++++++++++++++++++
Acommon/nfs.nix | 8++++++++
Acommon/packages.nix | 18++++++++++++++++++
Acommon/ssh-tunnel.nix | 19+++++++++++++++++++
Acommon/ssh.nix | 12++++++++++++
Acommon/syncthing.nix | 40++++++++++++++++++++++++++++++++++++++++
Acommon/user.nix | 15+++++++++++++++
Acommon/ydotool.nix | 27+++++++++++++++++++++++++++
Aentrypoint.nix | 24++++++++++++++++++++++++
Ahome/alacritty.nix | 42++++++++++++++++++++++++++++++++++++++++++
Ahome/cursor.nix | 15+++++++++++++++
Ahome/firefox.nix | 31+++++++++++++++++++++++++++++++
Ahome/fish.nix | 29+++++++++++++++++++++++++++++
Ahome/ghostty.nix | 37+++++++++++++++++++++++++++++++++++++
Ahome/git.nix | 9+++++++++
Ahome/htop.nix | 14++++++++++++++
Ahome/hyprland.nix | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahome/kodi.nix | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahome/lf.nix | 17+++++++++++++++++
Ahome/mpv.nix | 41+++++++++++++++++++++++++++++++++++++++++
Ahome/neovim.nix | 41+++++++++++++++++++++++++++++++++++++++++
Ahome/newsboat.nix | 25+++++++++++++++++++++++++
Ahome/rbw.nix | 13+++++++++++++
Ahome/ssh.nix | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahome/tofi.nix | 17+++++++++++++++++
Amachines/arcadia-hardware.nix | 37+++++++++++++++++++++++++++++++++++++
Amachines/arcadia.nix | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amachines/ilias-hardware.nix | 39+++++++++++++++++++++++++++++++++++++++
Amachines/ilias.nix | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amachines/minerva-hardware.nix | 32++++++++++++++++++++++++++++++++
Amachines/minerva.nix | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/blog-sort-archives.nix | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/blog-sort-languages.nix | 35+++++++++++++++++++++++++++++++++++
Ascripts/blog-sort-quotes.nix | 34++++++++++++++++++++++++++++++++++
Ascripts/ctimerename.nix | 27+++++++++++++++++++++++++++
Ascripts/duupmove.nix | 34++++++++++++++++++++++++++++++++++
Ascripts/htpc-launcher.nix | 11+++++++++++
Ascripts/overtid.nix | 36++++++++++++++++++++++++++++++++++++
Ascripts/phone-dump.nix | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/watchedlist.nix | 36++++++++++++++++++++++++++++++++++++
Ascripts/youtube-id-rss.nix | 20++++++++++++++++++++
48 files changed, 1643 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +research +\ No newline at end of file diff --git a/common/audio.nix b/common/audio.nix @@ -0,0 +1,9 @@ +{ + security.rtkit.enable = true; + services.pipewire = { + enable = true; + wireplumber.enable = true; + alsa.enable = true; + pulse.enable = true; + }; +} diff --git a/common/emulators.nix b/common/emulators.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + # Emulators + blastem + cemu + dolphin-emu + duckstation + flycast + gopher64 + mgba + pcsx2 + ppsspp + punes + rpcs3 + sameboy + snes9x + xemu + # Game engines + corsix-th + eduke32 + openra + openrct2 + openttd + ]; +} diff --git a/common/flakes.nix b/common/flakes.nix @@ -0,0 +1,3 @@ +{ + nix.settings.experimental-features = [ "nix-command" "flakes" ]; +} diff --git a/common/fonts.nix b/common/fonts.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: + +{ +fonts.packages = with pkgs; [ + nerd-fonts.jetbrains-mono +]; +} diff --git a/common/garbage.nix b/common/garbage.nix @@ -0,0 +1,7 @@ +{ + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; +} +\ No newline at end of file diff --git a/common/locale.nix b/common/locale.nix @@ -0,0 +1,17 @@ +{ + time.timeZone = "Europe/London"; + i18n.defaultLocale = "en_GB.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "en_GB.UTF-8"; + LC_IDENTIFICATION = "en_GB.UTF-8"; + LC_MEASUREMENT = "en_GB.UTF-8"; + LC_MONETARY = "en_GB.UTF-8"; + LC_NAME = "en_GB.UTF-8"; + LC_NUMERIC = "en_GB.UTF-8"; + LC_PAPER = "en_GB.UTF-8"; + LC_TELEPHONE = "en_GB.UTF-8"; + LC_TIME = "en_GB.UTF-8"; + }; + services.xserver.xkb.layout = "gb"; + console.keyMap = "uk"; +} +\ No newline at end of file diff --git a/common/media-sort.nix b/common/media-sort.nix @@ -0,0 +1,24 @@ +{ pkgs }: + +pkgs.buildGoModule { + pname = "media-sort"; + version = "2.6.2"; + + src = pkgs.fetchFromGitHub { + owner = "jpillora"; + repo = "media-sort"; + rev = "v2.6.2"; + sha256 = "078bqjlh9n0575apgv4aw6d92bm17riqc5yb64vxg2d9yf9mi4s4"; + # nix-prefetch-url --unpack https://github.com/jpillora/media-sort/archive/refs/tags/v2.6.2.tar.gz + }; + + vendorHash = "sha256-JHnKBr2sxwAXjdrmpkENz4Sm76MmPgNlSVtA8WoXwmA"; + # nix-prefetch-url https://github.com/jpillora/media-sort/archive/refs/tags/v2.6.2.tar.gz | xargs nix hash convert --to sri --hash-algo sha256 + + meta = with pkgs.lib; { + description = "Media sorter – organizes movies and TV into directories"; + homepage = "https://github.com/jpillora/media-sort"; + license = licenses.mit; + platforms = platforms.linux; + }; +} diff --git a/common/nfs.nix b/common/nfs.nix @@ -0,0 +1,7 @@ +{ + fileSystems."/mnt" = { + device = "192.168.1.3:/mnt"; + fsType = "nfs"; + options = [ "x-systemd.automount" "noauto" ]; + }; +} +\ No newline at end of file diff --git a/common/packages.nix b/common/packages.nix @@ -0,0 +1,18 @@ +{ pkgs, ... }: { + nixpkgs.config.allowUnfree = true; + environment.systemPackages = with pkgs; [ + fastfetch + ffmpeg + file + fish + git + htop + jdupes + neovim + rclone + rsync + syncthing + tmux + unzip + ]; +} diff --git a/common/ssh-tunnel.nix b/common/ssh-tunnel.nix @@ -0,0 +1,19 @@ +{ pkgs, username, domain, ... }: + +{ + systemd.services.reverse-ssh-tunnel = { + description = "Persistent Reverse SSH Tunnel"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = "${pkgs.openssh}/bin/ssh -NTg -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=accept-new -p 55012 -i /home/${username}/vault/docs/secure/ssh-key-2022-02-16.key -R 55013:localhost:22 ${username}@${domain}"; + Restart = "always"; + RestartSec = "10s"; + User = "${username}"; + }; + }; + + environment.systemPackages = with pkgs; [ openssh ]; +} diff --git a/common/ssh.nix b/common/ssh.nix @@ -0,0 +1,11 @@ +{ username, sshkey, ... }: + +{ + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + }; + + # SSH key + users.users.${username}.openssh.authorizedKeys.keys = [ "${sshkey}" ]; +} +\ No newline at end of file diff --git a/common/syncthing.nix b/common/syncthing.nix @@ -0,0 +1,40 @@ +{ username, ... }: +{ + + services.syncthing = { + enable = true; + user = "${username}"; + dataDir = "/home/${username}/"; + configDir = "/home/${username}/.config/syncthing"; + settings = { + options.urAccepted = 1; + devices = { + desktop.id = "6DL2MHG-4WS4B2Q-IAOHURV-XL3CXVZ-EBDXZMH-FZS7WFX-UJAVUJL-UQ2EOAQ"; + htpc.id = "E46LP6X-6LMHIBU-LPQTF2P-T5VIU52-OJWUAP5-ZX7VCQU-S7GGGK3-Y4IXVAJ"; + laptop.id = "L2DBXFX-T5B52M7-54AOF4S-HVGQGHM-XMEDPFI-NXX4PEI-V6YHD7P-JYGR2A3"; + nas.id = "FONKXV6-BQFMLNT-6OHTKXG-CP7DOZP-M5ZA6GW-5WAN4L6-X3LEANG-7EC5WQ6"; + phone.id = "7M34AP7-VLSE6A4-UX24I72-VDXCBSW-BGXHSUF-OF6UQQL-7QK4IFW-5F5M3QH"; + server.id = "TJV7YEI-GYLINDA-6YYHJW7-TLV6XUY-LJEJWSV-AEZ6NKE-BFLX4KB-BJ5DNAH"; + }; + folders = { + "/home/${username}/vault" = { + label = "vault"; + id = "vault"; + devices = [ "desktop" "htpc" "laptop" "nas" "phone" "server" ]; + }; + }; + }; + }; + + # https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes + boot.kernel.sysctl."net.core.rmem_max" = 7500000; + boot.kernel.sysctl."net.core.wmem_max" = 7500000; + + # Disable default ~/Sync folder + systemd.services.syncthing.environment.STNODEFAULTFOLDER = "true"; + + # Firewall ports + networking.firewall.allowedTCPPorts = [ 22000 ]; + networking.firewall.allowedUDPPorts = [ 22000 21027 ]; + +} diff --git a/common/user.nix b/common/user.nix @@ -0,0 +1,15 @@ +{ pkgs, username, fullname, ... }: +{ + users.users."${username}" = { + isNormalUser = true; + description = "${fullname}"; + shell = pkgs.fish; + extraGroups = [ "networkmanager" "wheel" "video" ]; + }; + + # Auto login + services.getty.autologinUser = "${username}"; + + # Enable fish shell + programs.fish.enable = true; +} diff --git a/common/ydotool.nix b/common/ydotool.nix @@ -0,0 +1,27 @@ +{ pkgs, username, ... }: + +{ + boot.kernelModules = [ "uinput" ]; + users.users.${username}.extraGroups = [ "uinput" ]; + # Define the uinput group + users.groups.uinput = {}; + + # Install ydotool system-wide + environment.systemPackages = with pkgs; [ + ydotool + ]; + + # Udev rule to allow group access to /dev/uinput + services.udev.extraRules = '' + KERNEL=="uinput", GROUP="uinput", MODE="0660" + ''; + + # Set capabilities on ydotool via a wrapper so it persists rebuilds + security.wrappers.ydotool = { + source = "${pkgs.ydotool}/bin/ydotool"; + capabilities = "cap_sys_admin,cap_dac_override,cap_sys_nice+ep"; + owner = "root"; + group = "uinput"; + permissions = "u+rx,g+rx"; + }; +} diff --git a/entrypoint.nix b/entrypoint.nix @@ -0,0 +1,24 @@ +{ + config, + pkgs, + lib, + ... +}: let + fullname = "Peter"; + username = lib.strings.toLower fullname; + domain = "minskio.co.uk"; + email = "${username}@${domain}"; + sshkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCXdHG4d/CoCbS1mp7cg+/3qS8nI4bvp7nvU5BZdkzseOt1NerZ4rgdQLBiFGiEi4LPMOQxBGXe7uuskn3TCc2C/DkZH/+AdYQ5MDXRbRqta/0oS8XVTzWcBtluaHc6qsuF6MkSU853ZWVgzlYimfSkjkwvrMT38WkkauC9U4VoqODVLQe5sivR/2INHctNfj0dYuyvPRUhAiuTrha0cKrS7xkOIf4a9gQgunU4+cmyb1HPt6KmNMzuZ/nhsqVWf6h/v0oBTg8p+aestfpg2fTAlY8Za8t/ZOqpF1TeWqUB+1AXEoQHNw2bezzKwCyX39cvjTeE5EWKl7oXalq91J39 ssh-key-2022-02-16"; + hostname = + if builtins.pathExists "/etc/hostname" + then lib.strings.removeSuffix "\n" (builtins.readFile "/etc/hostname") + else throw "Error: /etc/hostname not found. Please ensure the hostname is set before rebuild."; + machine = lib.strings.removeSuffix "\n" hostname; + osConfigPath = ./machines + "/${machine}.nix"; +in { + imports = [ + (import osConfigPath {inherit config pkgs lib fullname machine username domain email sshkey;}) + ]; + + networking.hostName = machine; +} diff --git a/home/alacritty.nix b/home/alacritty.nix @@ -0,0 +1,42 @@ +{ + programs.alacritty = { + enable = true; + settings = { + font = { + size = 11.0; + # draw_bold_text_with_bright_colors = true; + normal = { + family = "JetBrainsMono Nerd Font Mono"; + style = "Regular"; + }; + }; + colors = { + primary = { + background = "#1d1f21"; + foreground = "#c5c8c6"; + }; + normal = { + black = "#282a2e"; + red = "#a54242"; + green = "#8c9440"; + yellow = "#de935f"; + blue = "#5f819d"; + magenta = "#85678f"; + cyan = "#5e8d87"; + white = "#707880"; + }; + bright = { + black = "#373b41"; + red = "#cc6666"; + green = "#b5bd68"; + yellow = "#f0c674"; + blue = "#81a2be"; + magenta = "#b294bb"; + cyan = "#8abeb7"; + white = "#c5c8c6"; + }; + }; + }; + }; +} + diff --git a/home/cursor.nix b/home/cursor.nix @@ -0,0 +1,15 @@ +{ pkgs, lib, ... }: + +{ +home.pointerCursor = { + gtk.enable = true; + package = pkgs.posy-cursors; + name = "Posy_Cursor_Black"; + size = 24; +}; + +nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ + "posy-cursors" + ]; + } + diff --git a/home/firefox.nix b/home/firefox.nix @@ -0,0 +1,30 @@ +{ +programs.firefox = { + enable = true; + + profiles.default = { + id = 0; + name = "default"; + + # Example Firefox preferences + settings = { + "browser.aboutConfig.showWarning" = false; + "browser.gesture.swipe.left" = ""; + "browser.gesture.swipe.right" = ""; + "browser.startup.homepage" = "https://breadcat.github.io/startpage/"; + "browser.theme.content-theme" = "0"; # Dark theme + "browser.theme.toolbar-theme" = "0"; # Dark theme + "layout.css.prefers-color-scheme.content-override" = "0"; # Dark CSS themes + "network.cookie.cookieBehavior" = 1; # Block third-party cookies + "privacy.donottrackheader.enabled" = true; + }; + extensions = [ + # "ublock-origin@raymondhill.net" # Just an example (must match extension ID) + # "uBlock0@raymondhill.net" # uBlock Origin + ]; + }; +}; +home.sessionVariables = { + MOZ_ENABLE_WAYLAND = 1; +}; +} +\ No newline at end of file diff --git a/home/fish.nix b/home/fish.nix @@ -0,0 +1,29 @@ +{ + programs.fish = { + enable = true; + functions = { + __fish_command_not_found_handler = { body = "echo fish: Unknown command $argv[1]"; onEvent = "fish_command_not_found"; }; + vat = "math $argv + \"($argv * 0.2)\""; + mcd = "mkdir -p $argv[1] && cd $argv[1]"; + mergeinto = "rsync --progress --remove-source-files -av \"$argv[1]\" \"$argv[2]\" && find \"$argv[1]\" -empty -delete"; + }; + loginShellInit = '' + set fish_greeting # Disable greeting + set --erase fish_greeting # Disable greeting + set -gx SYNCDIR $HOME/vault + set -gx EDITOR nvim + set -gx VISUAL $EDITOR + ''; + shellAliases = { + extract = "aunpack"; + jdupes = "jdupes -A"; # exclude hidden files + empties = "find . -maxdepth 3 -mount -not -path \"*/\.*\" -empty -print"; + vaultedit = "find \"$SYNCDIR\" -maxdepth 5 -type f | fzf --preview \"cat {}\" --layout reverse | xargs -r -I{} \"$EDITOR\" {}"; + week = "date +%V"; + }; +# binds = { +# "ctrl-h".command = "backward-kill-path-component"; +# "ctrl-backspace".command = "kill-word"; +# }; + }; +} diff --git a/home/ghostty.nix b/home/ghostty.nix @@ -0,0 +1,37 @@ +{ + programs.ghostty = { + enable = true; + settings = { + theme = "base16-dark"; + font-size = 11; + }; + themes = + { + base16-dark = { + background = "1d1f21"; + cursor-color = "c5c8c6"; + foreground = "c5c8c6"; + palette = [ + "0=#282a2e" + "1=#a54242" + "2=#8c9440" + "3=#de935f" + "4=#5f819d" + "5=#85678f" + "6=#5e8d87" + "7=#707880" + "8=#373b41" + "9=#cc6666" + "10=#b5bd68" + "11=#f0c674" + "12=#8ae2be" + "13=#b294bb" + "14=#8abeb7" + "15=#c5c8c6" + ]; + selection-background = "353749"; + selection-foreground = "cdd6f4"; + }; + }; + }; +} diff --git a/home/git.nix b/home/git.nix @@ -0,0 +1,9 @@ +{ fullname, email, ... }: + +{ + programs.git = { + enable = true; + userName = "${fullname}"; + userEmail = "${email}"; + }; +} diff --git a/home/htop.nix b/home/htop.nix @@ -0,0 +1,14 @@ +{ + programs.htop = { + enable = true; + settings = { + shadow_other_users = 1; + tree_view = 1; + hide_userland_threads = 1; + columnMeters0 = ["AllCPUs" "Memory"]; + columnMeterModes0 = [1 1]; + columnMeters1 = ["DateTime" "Tasks" "LoadAverage" "Uptime" "System"]; + columnMeterModes1 = [2 2 2 2 2]; + }; + }; +} diff --git a/home/hyprland.nix b/home/hyprland.nix @@ -0,0 +1,199 @@ +{ ... }: + +{ + wayland.windowManager.hyprland = { + enable = true; + settings = { + + ecosystem = { + "no_update_news" = true; + }; + + monitor = ",preferred,auto,auto"; + env = [ + "XCURSOR_SIZE,24" + "HYPRCURSOR_SIZE,24" + ]; + + general = { + gaps_in = 5; + gaps_out = 20; + border_size = 2; + "col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg"; + "col.inactive_border" = "rgba(595959aa)"; + resize_on_border = false; + allow_tearing = false; + layout = "dwindle"; + }; + + cursor = { + inactive_timeout = 3; + }; + + decoration = { + rounding = 5; + active_opacity = 1.0; + inactive_opacity = 1.0; + shadow = { + enabled = true; + range = 4; + render_power = 3; + color = "rgba(1a1a1aee)"; + }; + blur = { + enabled = true; + size = 3; + passes = 1; + vibrancy = 0.1696; + }; + }; + + animations = { + enabled = true; + bezier = [ + "easeOutQuint,0.23,1,0.32,1" + "easeInOutCubic,0.65,0.05,0.36,1" + "linear,0,0,1,1" + "almostLinear,0.5,0.5,0.75,1.0" + "quick,0.15,0,0.1,1" + ]; + animation = [ + "global, 1, 10, default" + "border, 1, 5.39, easeOutQuint" + "windows, 1, 4.79, easeOutQuint" + "windowsIn, 1, 4.1, easeOutQuint, popin 87%" + "windowsOut, 1, 1.49, linear, popin 87%" + "fadeIn, 1, 1.73, almostLinear" + "fadeOut, 1, 1.46, almostLinear" + "fade, 1, 3.03, quick" + "layers, 1, 3.81, easeOutQuint" + "layersIn, 1, 4, easeOutQuint, fade" + "layersOut, 1, 1.5, linear, fade" + "fadeLayersIn, 1, 1.79, almostLinear" + "fadeLayersOut, 1, 1.39, almostLinear" + "workspaces, 1, 1.94, almostLinear, fade" + "workspacesIn, 1, 1.21, almostLinear, fade" + "workspacesOut, 1, 1.94, almostLinear, fade" + ]; + }; + + dwindle = { + pseudotile = true; + preserve_split = true; + workspace = [ + "w[tv1], gapsout:0, gapsin:0" + "f[1], gapsout:0, gapsin:0" + ]; + windowrulev2 = [ + "bordersize 0, floating:0, onworkspace:w[tv1]" + "rounding 0, floating:0, onworkspace:w[tv1]" + "bordersize 0, floating:0, onworkspace:f[1]" + "rounding 0, floating:0, onworkspace:f[1]" + ]; + }; + + master = { + new_status = "master"; + }; + + misc = { + force_default_wallpaper = 0; + disable_hyprland_logo = true; + }; + + input = { + kb_layout = "gb"; + kb_options = "caps:backspace"; + follow_mouse = 1; + sensitivity = 0; + touchpad = { + natural_scroll = false; + }; + }; + + gestures = { + workspace_swipe = false; + }; + + bind = [ + "SUPER, R, exec, tofi-drun | xargs hyprctl dispatch exec --" + "SUPER, W, exec, firefox" + "SUPER, T, exec, ghostty" + "SUPER_SHIFT, W, exec, firefox -private-window" + "ALT, Tab, cyclenext" + "ALT SHIFT, Tab, cyclenext, prev" + "SUPER, RETURN, exec, ghostty" + "SUPER_SHIFT, Q, killactive," + "SUPER, X, exit," + "SUPER, E, exec, ghostty -e lf" + "SUPER, Space, togglefloating," + "SUPER, F, fullscreen," + "SUPER, P, pseudo," + "SUPER, J, togglesplit," + "SUPER, left, movefocus, l" + "SUPER, right, movefocus, r" + "SUPER, up, movefocus, u" + "SUPER, down, movefocus, d" + "SUPER, 1, workspace, 1" + "SUPER, 2, workspace, 2" + "SUPER, 3, workspace, 3" + "SUPER, 4, workspace, 4" + "SUPER, 5, workspace, 5" + "SUPER, 6, workspace, 6" + "SUPER, 7, workspace, 7" + "SUPER, 8, workspace, 8" + "SUPER, 9, workspace, 9" + "SUPER, 0, workspace, 10" + "SUPER SHIFT, 1, movetoworkspace, 1" + "SUPER SHIFT, 2, movetoworkspace, 2" + "SUPER SHIFT, 3, movetoworkspace, 3" + "SUPER SHIFT, 4, movetoworkspace, 4" + "SUPER SHIFT, 5, movetoworkspace, 5" + "SUPER SHIFT, 6, movetoworkspace, 6" + "SUPER SHIFT, 7, movetoworkspace, 7" + "SUPER SHIFT, 8, movetoworkspace, 8" + "SUPER SHIFT, 9, movetoworkspace, 9" + "SUPER SHIFT, 0, movetoworkspace, 10" + "SUPER, mouse_down, workspace, e+1" + "SUPER, mouse_up, workspace, e-1" + ]; + + bindm = [ + "ALT, mouse:272, movewindow" + "ALT, mouse:273, resizewindow" + ]; + + bindel = [ + ",XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+" + ",XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" + ",XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" + ",XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle" + ",XF86MonBrightnessUp, exec, brightnessctl s 10%+" + ",XF86MonBrightnessDown, exec, brightnessctl s 10%-" + ]; + + bindl = [ + ", XF86AudioNext, exec, playerctl next" + ", XF86AudioPause, exec, playerctl play-pause" + ", XF86AudioPlay, exec, playerctl play-pause" + ", XF86AudioPrev, exec, playerctl previous" + ]; + + windowrulev2 = [ + "suppressevent maximize, class:.*" + "nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0" + ]; + }; + }; + + programs.fish = { + interactiveShellInit = '' + set -gx HYPRPATH (whereis Hyprland | awk '{print $NF}') + if test (tty) = "/dev/tty1"; exec $HYPRPATH; end + ''; + }; + + dconf = { + enable = true; + }; +} diff --git a/home/kodi.nix b/home/kodi.nix @@ -0,0 +1,60 @@ +{ username, ... }: + +{ + programs.kodi = { + enable = true; + settings = { + "addons.unknownsources" = "true"; + "addons.updatemode" = "1"; + "locale.country" = "UK (12h)"; + "locale.language" = "resource.language.en_gb"; + "locale.timezone" = "Europe/London"; + "locale.timezonecountry" = "Britain (UK)"; + "lookandfeel.skincolors" = "midnight"; + "screensaver.mode" = "screensaver.xbmc.builtin.dim"; + "screensaver.time" = "5"; + "services.webserver" = "true"; + "services.webserverauthentication" = "true"; + "services.webserverpassword" = "kodi"; + "services.webserverport" = "8080"; + "services.webserverusername" = "kodi"; + "videolibrary.tvshowsselectfirstunwatcheditem" = "2"; + }; + addonSettings = { + "service.watchedlist" = { + "dbpath" = "/home/${username}/vault/"; + "dbfilename" = "watchedlist.db"; + }; + "skin.estuary" = { + "homemenunopicturesbutton" = "true"; + "homemenunoradiobutton" = "true"; + "homemenunofavbutton" = "true"; + "homemenunomusicbutton" = "true"; + "homemenunomusicvideobutton" = "true"; + "homemenunovideosbutton" = "true"; + "homemenunotvbutton" = "true"; + }; + }; + sources = { + video = { + default = "movies"; + source = [ + { name = "television"; path = "/mnt/media/videos/television"; allowsharing = "true"; } + { name = "movies"; path = "/mnt/media/videos/movies"; allowsharing = "true"; } + { name = "${username}"; path = "/home/${username}"; allowsharing = "true"; } + ]; + }; + files = { + source = [ + { name = "a4kSubtitles-repo"; path = "https://a4k-openproject.github.io/a4kSubtitles/packages/"; allowsharing = "true"; } + ]; + }; + }; + }; + # Launch Kodi (and fix fullscreen issue) via Hyprland + wayland.windowManager.hyprland = { + settings = { + "exec-once" = "htpc-launcher"; + }; + }; +} diff --git a/home/lf.nix b/home/lf.nix @@ -0,0 +1,17 @@ +{ + programs.lf = { + enable = true; + settings = { + icons = true; + ignorecase = true; + }; + keybindings = { + "." = "set hidden!"; + "<delete>" = "delete"; + "<enter>" = "shell"; + "d" = "delete"; + "i" = "$swayimg -r *"; + "gv" = "cd ~/vault"; + }; + }; +} diff --git a/home/mpv.nix b/home/mpv.nix @@ -0,0 +1,41 @@ +{ pkgs, ... }: + +{ + programs.mpv = { + enable = true; + config = { + volume = 50; # initial volume + audio-display = "no"; + sub-auto = "fuzzy"; + ytdl-raw-options = "sub-format=en,write-srt="; + ytdl-format = "bestvideo[height<=?480][fps<=?30]+bestaudio/best"; + }; + scripts = with pkgs.mpvScripts; [ + sponsorblock-minimal + ]; + + profiles = { + "extension.gif" = { loop-file = "inf"; }; + "extension.webm" = { loop-file = "inf"; }; + "extension.jpg" = { pause = "yes"; }; + "extension.jpeg" = { pause = "yes"; }; + "extension.webp" = { pause = "yes"; }; + "extension.png" = { pause = "yes"; }; + "extension.avif" = { pause = "yes"; }; + }; + bindings = { + "-" = "add volume -5"; + "=" = "add volume 5"; + PGDWN = "playlist-prev"; + PGUP = "playlist-next"; + x = "cycle sub"; + X = "cycle sub-visibility"; + "Ctrl+n" = "af toggle acompressor"; + "Alt+-" = "add video-zoom -0.02"; + "Alt+=" = "add video-zoom 0.02"; + RIGHT = "osd-msg-bar seek +5 exact"; + LEFT = "osd-msg-bar seek -5 exact"; + "ctrl+del" = "run rm '$\{path\}'"; + }; + }; +} diff --git a/home/neovim.nix b/home/neovim.nix @@ -0,0 +1,41 @@ +{ + ... +}: { + programs.neovim = { + enable = true; + defaultEditor = true; + extraConfig = '' + set smartcase + set nocompatible + let mapleader ="," + set backspace=indent,eol,start + set clipboard+=unnamedplus + set ignorecase + set linebreak + set mouse=a + set nohlsearch + set number + set title + set titlestring=%f\ %m + set whichwrap+=<,>,h,l,[,] + set list listchars=nbsp:¬,tab:»·,trail:·,extends:> + set shiftwidth=2 + set softtabstop=2 + set tabstop=2 + syntax on + map <C-H> <C-W> + map <C-Del> X<Esc>ce<del> + map <F8> :setlocal spell! spelllang=en_gb<CR> + xnoremap <A-z> :s/^.<CR>gv " alt-z removes first character of line + nnoremap <A-z> 0x " alt-z in normal mode removes first char + :iab <expr> _date strftime("%F") + :iab <expr> _time strftime("%H:%M") + :iab <expr> _stamp strftime("%F\T%H:%M:00") + autocmd BufWritePre * %s/\s\+$//e + autocmd BufWritepre * %s/\n\+\%$//e + autocmd FileType nix setlocal tabstop=2 shiftwidth=2 expandtab + autocmd BufWritePre *.nix %s/\s\+$//e | retab + autocmd BufWritePost *.nix silent! execute '!alejandra -qq %' | edit + ''; + }; +} diff --git a/home/newsboat.nix b/home/newsboat.nix @@ -0,0 +1,25 @@ +{ domain, username, ... }: + +{ + programs.newsboat = { + enable = true; + extraConfig = '' + show-read-feeds no + auto-reload yes + reload-time 45 + browser $BROWSER + bind-key RIGHT open + bind-key LEFT quit + bind-key a toggle-article-read + bind-key m toggle-show-read-feeds + bind-key n next-unread + bind-key N prev-unread + macro m set browser "mpv %u" ; open-in-browser-and-mark-read ; set browser "$BROWSER %u" + urls-source "freshrss" + freshrss-url "https://rss.${domain}/api/greader.php" + freshrss-login "${username}" + freshrss-passwordeval "rbw get 'freshrss api'" + ''; + }; +} + diff --git a/home/rbw.nix b/home/rbw.nix @@ -0,0 +1,13 @@ +{ pkgs, domain, email, ... }: + +{ + programs.rbw = { + enable = true; + settings = { + base_url = "https://pass.${domain}"; + email = "${email}"; + pinentry = pkgs.pinentry-tty; + }; + }; +} + diff --git a/home/ssh.nix b/home/ssh.nix @@ -0,0 +1,52 @@ +{ domain, username, ... }: + +{ + programs.ssh = { + enable = true; + + matchBlocks = { + "minskio" = { + hostname = "${domain}"; + user = "${username}"; + port = 55012; + identityFile = "~/vault/docs/secure/ssh-key-2022-02-16.key"; + }; + "tunnel" = { + hostname = "${domain}"; + user = "${username}"; + port = 55012; + identityFile = "~/vault/docs/secure/ssh-key-2022-02-16.key"; + extraOptions = { + RemoteCommand = "ssh -p 55013 ${username}@localhost -i ~/vault/docs/secure/ssh-key-2022-02-16.key"; + RequestTTY = "force"; + }; + }; + "htpc" = { + hostname = "192.168.1.6"; + user = "${username}"; + port = 22; + identityFile = "~/vault/docs/secure/ssh-key-2022-02-16.key"; + }; + "nas" = { + hostname = "192.168.1.3"; + user = "${username}"; + port = 22; + identityFile = "~/vault/docs/secure/ssh-key-2022-02-16.key"; + }; + "router" = { + hostname = "192.168.1.1"; + user = "root"; + port = 22; + }; + "ap" = { + hostname = "192.168.1.2"; + user = "root"; + port = 22; + extraOptions = { + HostKeyAlgorithms = "+ssh-rsa"; + }; + }; + }; + }; + +} diff --git a/home/tofi.nix b/home/tofi.nix @@ -0,0 +1,17 @@ +{ + programs.tofi = { + enable = true; + settings = { + width = "100%"; + height = "100%"; + border-width = "0"; + outline-width = "0"; + padding-left = "35%"; + padding-top = "35%"; + result-spacing = "25"; + num-results = "10"; + font = "monospace"; + background-color = "#000A"; + }; + }; +} diff --git a/machines/arcadia-hardware.nix b/machines/arcadia-hardware.nix @@ -0,0 +1,37 @@ +{ config, lib, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/705ee72a-0cbf-40a3-a6cb-4ddd976b3d8f"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/7D86-A86F"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + + # Bootloader + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Networking, use DHCP + networking.networkmanager.enable = true; + networking.useDHCP = lib.mkDefault true; + +} diff --git a/machines/arcadia.nix b/machines/arcadia.nix @@ -0,0 +1,83 @@ +# HTPC + +{ config, pkgs, domain, machine, username, fullname, sshkey, ... }: + +let + home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz; # stable + # home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/master.tar.gz; # unstable +in + +{ + # Common OS imports + imports = + [ # Include the results of the hardware scan. + ./${machine}-hardware.nix + ../common/audio.nix + ../common/flakes.nix + ../common/garbage.nix + ../common/locale.nix + ../common/nfs.nix + # ../common/kodi-module.nix + ../common/packages.nix + (import ../common/syncthing.nix {inherit config pkgs username;}) + (import ../common/user.nix {inherit config pkgs username fullname;}) + (import ../common/ssh.nix {inherit username sshkey;}) + ../scripts/htpc-launcher.nix + (import "${home-manager}/nixos") + ]; + + # Home-Manager + home-manager.backupFileExtension = "hm-bak"; + home-manager.users.${username} = { pkgs, ... }: { + imports = [ + ../home/fish.nix + ../home/hyprland.nix + (import ../home/kodi.nix {inherit username;}) + (import ../home/ssh.nix {inherit domain username;}) + ]; + + # The state version is required and should stay at the version you + # originally installed. + home.stateVersion = "24.11"; + }; + + # Hostname + networking.hostName = "arcadia"; # Define your hostname. + + # Hardware acceleration + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver + libvdpau-va-gl + vaapiIntel + ]; + }; + + # Enable programs + programs.hyprland.enable = true; + + # Packages + environment.systemPackages = with pkgs; [ + alacritty + # duckstation + hyprland + kodiPackages.inputstream-adaptive + kodi-wayland + moonlight-qt + mpv + # spotify + yt-dlp + ]; + + # Kodi settings + # HDMI CEC input groups + users.users.${username}.extraGroups = [ "networkmanager" "wheel" "input" "dialout" "video" ]; # Extra groups for Kodi CEC input + + # Web UI firewall rules + networking.firewall.allowedTCPPorts = [ 8080 ]; + networking.firewall.allowedUDPPorts = [ 8080 ]; + + system.stateVersion = "24.11"; + +} diff --git a/machines/ilias-hardware.nix b/machines/ilias-hardware.nix @@ -0,0 +1,39 @@ +{ config, lib, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/8018d8fb-dffe-40a2-b5f9-500000b24c36"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/EE4D-E953"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/3397e636-91db-44ae-9572-923e4b3acbbe"; } + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + + # Bootloader + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Networking, use DHCP + networking.networkmanager.enable = true; + networking.useDHCP = lib.mkDefault true; + +} diff --git a/machines/ilias.nix b/machines/ilias.nix @@ -0,0 +1,109 @@ +# NAS +{ + config, + pkgs, + machine, + username, + email, + fullname, + domain, + sshkey, + ... +}: let + media-sort = import ../common/media-sort.nix {inherit pkgs;}; + # home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz; # Stable + home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/master.tar.gz; # Unstable +in { + # Core OS imports + imports = [ + # Include the results of the hardware scan. + ./${machine}-hardware.nix + ../common/flakes.nix + ../common/locale.nix + ../common/packages.nix + ../scripts/phone-dump.nix + ../scripts/watchedlist.nix + ../scripts/ctimerename.nix + ../scripts/duupmove.nix + ../scripts/youtube-id-rss.nix + (import ../scripts/overtid.nix {inherit pkgs;}) + (import ../scripts/blog-sort-archives.nix {inherit pkgs domain;}) + (import ../scripts/blog-sort-quotes.nix {inherit pkgs domain;}) + (import ../scripts/blog-sort-languages.nix {inherit pkgs domain;}) + (import ../common/ssh-tunnel.nix {inherit config pkgs username domain;}) + (import ../common/syncthing.nix {inherit config pkgs username;}) + (import ../common/user.nix {inherit config pkgs username fullname;}) + (import ../common/ssh.nix {inherit username sshkey;}) + (import "${home-manager}/nixos") + ]; + + # Home-Manager + home-manager.backupFileExtension = "hm-bak"; + home-manager.users.${username} = {pkgs, ...}: { + imports = [ + ../home/fish.nix + ../home/htop.nix + ../home/neovim.nix + (import ../home/git.nix {inherit fullname email;}) + (import ../home/rbw.nix {inherit pkgs domain email;}) + (import ../home/ssh.nix {inherit domain username;}) + ]; + # The state version is required and should stay at the version you + # originally installed. + home.stateVersion = "24.11"; + }; + + # Hostname + networking.hostName = "ilias"; # Define your hostname. + + # Second drive and NFS + fileSystems."/mnt" = { + device = "/dev/disk/by-uuid/9b205675-7376-45ba-b575-2f36eb50ea99"; + fsType = "ext4"; + }; + services.nfs.server = { + enable = true; + exports = '' + /mnt 192.168.1.0/24(rw) + ''; + }; + # Firewall and NFS server ports + networking.firewall.enable = true; + networking.firewall.allowPing = true; + networking.firewall.allowedTCPPorts = [111 2049]; + networking.firewall.allowedUDPPorts = [111 2049]; + + # Packages + environment.systemPackages = with pkgs; [ + czkawka + atool + dos2unix + fzf + gallery-dl + imagemagick + jdupes + media-sort + mmv + lf + mnamer + mp3val + ngrok + nixfmt-rfc-style + ocrmypdf + optipng + opustags + pciutils + powertop + python3 + qpdf + rbw + rclone + shellcheck-minimal + shfmt + sqlite + unrar + yt-dlp + ]; + + system.stateVersion = "24.11"; +} diff --git a/machines/minerva-hardware.nix b/machines/minerva-hardware.nix @@ -0,0 +1,32 @@ +{ config, lib, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/e9802357-1ee2-4e24-bf94-580c96205012"; + fsType = "ext4"; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + + # Bootloader + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; + boot.loader.grub.useOSProber = true; + + # Networking, use DHCP + networking.networkmanager.enable = true; + networking.useDHCP = lib.mkDefault true; + +} diff --git a/machines/minerva.nix b/machines/minerva.nix @@ -0,0 +1,99 @@ +# Laptop +{ + config, + pkgs, + machine, + username, + fullname, + domain, + email, + sshkey, + ... +}: let + media-sort = import ../common/media-sort.nix {inherit pkgs;}; + # home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz; + home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/master.tar.gz; +in { + # Core OS imports + imports = [ + # Include the results of the hardware scan. + ./${machine}-hardware.nix + ../common/audio.nix + ../common/flakes.nix + ../common/fonts.nix + ../common/garbage.nix + ../common/locale.nix + ../common/nfs.nix + ../common/packages.nix + (import ../common/syncthing.nix {inherit config pkgs username;}) + (import ../common/user.nix {inherit config pkgs username fullname;}) + (import ../common/ssh.nix {inherit username sshkey;}) + (import ../common/ydotool.nix {inherit pkgs username;}) + (import "${home-manager}/nixos") + ]; + + # Home-Manager + home-manager.backupFileExtension = "hm-bak"; + home-manager.users.${username} = {pkgs, ...}: { + imports = [ + ../home/fish.nix + ../home/alacritty.nix + ../home/ghostty.nix + ../home/cursor.nix + ../home/firefox.nix + ../home/fish.nix + ../home/htop.nix + # ../home/iamb.nix + ../home/hyprland.nix + ../home/lf.nix + ../home/mpv.nix + ../home/neovim.nix + ../home/tofi.nix + (import ../home/git.nix {inherit fullname email;}) + (import ../home/rbw.nix {inherit pkgs domain email;}) + (import ../home/ssh.nix {inherit domain username;}) + (import ../home/newsboat.nix {inherit pkgs domain username;}) + ]; + # The state version is required and should stay at the version you + # originally installed. + home.stateVersion = "24.11"; + }; + + # Hostname + networking.hostName = "minerva"; # Define your hostname. + + # Packages + environment.systemPackages = with pkgs; [ + atool + media-sort + brightnessctl + dos2unix + firefox + fzf + gallery-dl + glib + hyprcursor + hypridle + hyprland + imagemagick + jre8 + lf + mpv + newsboat + pinentry-tty + posy-cursors + rbw + seatd + swayimg + tofi + unzip + wl-clipboard + yt-dlp + ]; + + programs.hyprland.enable = true; + users.users.${username}.extraGroups = ["seat" "video"]; + services.seatd.enable = true; + + system.stateVersion = "24.11"; # Did you read the comment? +} diff --git a/scripts/blog-sort-archives.nix b/scripts/blog-sort-archives.nix @@ -0,0 +1,52 @@ +{ + pkgs, + domain, + ... +}: let + blog-sort-archives = pkgs.writeShellScriptBin "blog-sort-archives" '' + # variables + movies_export="$HOME/vault/src/blog.${domain}/content/posts/archived-movies.md" + tvshows_export="$HOME/vault/src/blog.${domain}/content/posts/archived-television.md" + # functions + function lastmod { + echo -n "Amending lastmod value... " + mod_timestamp="$(date +%FT%H:%M:00)" + sed -i "s/lastmod: .*/lastmod: $mod_timestamp/g" "$1" + echo -e "$i \e[32mdone\e[39m" + } + # process + movies_shasum_original="$(sha512sum "$movies_export" | awk '{print $1}')" + movie_header="$(grep -v "^*" "$movies_export")" + movies_raw="$(grep "^*" "$movies_export")" + echo -n "Writing movies export... " + { + printf "%s\n" "$movie_header" + printf "\n%s" "$movies_raw" | sort | uniq -i + } >"$movies_export" + movies_shasum_modified="$(sha512sum "$movies_export" | awk '{print $1}')" + if [[ "$movies_shasum_original" != "$movies_shasum_modified" ]]; then + lastmod "$movies_export" 1>/dev/null + echo -e "\e[32mmodified\e[39m" + else + echo -e "\e[33munmodified\e[39m" + fi + # tv shows + tvshows_shasum_original="$(sha512sum "$tvshows_export" | awk '{print $1}')" + tvshows_header="$(grep -v "^*" "$tvshows_export")" + tvshows_raw="$(grep "^*" "$tvshows_export")" + echo -n "Writing TV shows export... " + { + printf "%s\n" "$tvshows_header" + printf "\n%s" "$tvshows_raw" | sort | uniq -i + } >"$tvshows_export" + tvshows_shasum_modified="$(sha512sum "$tvshows_export" | awk '{print $1}')" + if [[ "$tvshows_shasum_original" != "$tvshows_shasum_modified" ]]; then + lastmod "$tvshows_export" 1>/dev/null + echo -e "\e[32mmodified\e[39m" + else + echo -e "\e[33munmodified\e[39m" + fi + ''; +in { + environment.systemPackages = [blog-sort-archives]; +} diff --git a/scripts/blog-sort-languages.nix b/scripts/blog-sort-languages.nix @@ -0,0 +1,35 @@ +{ + pkgs, + domain, + ... +}: let + blog-sort-languages = pkgs.writeShellScriptBin "blog-sort-languages" '' + # functions + function lastmod { + echo -n "Amending lastmod value... " + mod_timestamp="$(date +%FT%H:%M:00)" + sed -i "s/lastmod: .*/lastmod: $mod_timestamp/g" "$1" + echo -e "$i \e[32mdone\e[39m" + } + for i in $HOME/vault/src/blog.${domain}/content/languages/*; do + if [[ "$i" = *index.md ]]; then continue; fi # there's probably a better way of doing this, but I can't figure it out + echo -n "Processing $(basename "$i")... " + shasum_original="$(sha512sum "$i" | awk '{print $1}')" + file_header="$(head -n 8 "$i")" + file_body="$(tail -n +9 "$i" | sort | uniq -i)" + { + printf "%s\n" "$file_header" + printf "%s" "$file_body" + } >"$i" + shasum_modified="$(sha512sum "$i" | awk '{print $1}')" + if [[ "$shasum_original" != "$shasum_modified" ]]; then + lastmod "$i" 1>/dev/null + echo -e "\e[32mmodified\e[39m" + else + echo -e "\e[33munmodified\e[39m" + fi + done + ''; +in { + environment.systemPackages = [blog-sort-languages]; +} diff --git a/scripts/blog-sort-quotes.nix b/scripts/blog-sort-quotes.nix @@ -0,0 +1,34 @@ +{ + pkgs, + domain, + ... +}: let + blog-sort-quotes = pkgs.writeShellScriptBin "blog-sort-quotes" '' + # variables + quote_file="$HOME/vault/src/blog.${domain}/content/quotes.md" + file_header="$(head -n 7 "$quote_file")" + file_body="$(tail -n +7 "$quote_file" | sort | uniq -i | sed G)" + # functions + function lastmod { + echo -n "Amending lastmod value... " + mod_timestamp="$(date +%FT%H:%M:00)" + sed -i "s/lastmod: .*/lastmod: $mod_timestamp/g" "$1" + echo -e "$i \e[32mdone\e[39m" + } + echo -n "Processing $(basename "$quote_file")... " + shasum_original="$(sha512sum "$quote_file" | awk '{print $1}')" + { + printf "%s\n" "$file_header" + printf "%s" "$file_body" + } >"$quote_file" + shasum_modified="$(sha512sum "$quote_file" | awk '{print $1}')" + if [[ "$shasum_original" != "$shasum_modified" ]]; then + lastmod "$i" 1>/dev/null + echo -e "\e[32mmodified\e[39m" + else + echo -e "\e[33munmodified\e[39m" + fi + ''; +in { + environment.systemPackages = [blog-sort-quotes]; +} diff --git a/scripts/ctimerename.nix b/scripts/ctimerename.nix @@ -0,0 +1,27 @@ +{pkgs, ...}: let + ctimerename = pkgs.writeShellScriptBin "ctimerename" '' + extension="$1" + if [ -z "$extension" ]; then + echo "Extension variable is empty. Please specify a extension, e.g. jpg" + exit 1 + fi + for file in *."$extension"; do + if [ -f "$file" ]; then + timestamp=$(stat -c %y "$file" | cut -d'.' -f1 | sed 's/[: ]/-/g') + newname="''${timestamp}.$extension" + + # If the filename exists, add a counter + count=1 + while [ -e "$newname" ]; do + newname="''${timestamp}_$count.$extension" + ((count++)) + done + + echo "Renaming '$file' to '$newname'" + mv "$file" "$newname" + fi + done + ''; +in { + environment.systemPackages = [ctimerename]; +} diff --git a/scripts/duupmove.nix b/scripts/duupmove.nix @@ -0,0 +1,34 @@ +{pkgs, ...}: let + duupmove = pkgs.writeShellScriptBin "duupmove" '' + + target_dir="$1" + + if [ -z "$target_dir" ]; then + echo "Target directory variable is empty. Please specify a directory, e.g. /mnt/destination/" + exit 1 + fi + + mkdir -p "$target_dir" + + # Pictures + for file in *.jpg; do + if [[ "$file" =~ ^[0-9]+_[0-9a-f]{32}\.jpg$ ]]; then + mv "$file" "$target_dir/" -vin + fi + if [[ "$file" =~ ^[0-9]{9}_[A-Za-z0-9]{10}\.jpg$ ]]; then + mv "$file" "$target_dir/" -vin + fi + done + + # Videos + for file in *.mp4; do + if [[ "$file" =~ ^[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.mp4$ ]]; then + mv "$file" "$target_dir/" -vin + fi + done + + jdupes "$target_dir" "." -d + ''; +in { + environment.systemPackages = [duupmove]; +} diff --git a/scripts/htpc-launcher.nix b/scripts/htpc-launcher.nix @@ -0,0 +1,11 @@ +{pkgs, ...}: let + htpc-launcher = pkgs.writeShellScriptBin "htpc-launcher" '' + kodi & + sleep 4 + kodi-send -a toggleFullscreen + sleep 1 + kodi-send -a toggleFullscreen + ''; +in { + environment.systemPackages = [htpc-launcher]; +} diff --git a/scripts/overtid.nix b/scripts/overtid.nix @@ -0,0 +1,36 @@ +{ pkgs, ... }: + +let + overtid = pkgs.writeShellScriptBin "overtid" '' + # variables + time_start="08:30" + time_end="18:00" + # check for arguments + if [ $# -eq 0 ]; then + printf "Decimal overtime calculator\\nUsage: %s HH:MM (HH:MM)\\n" "''${0##*/}" + exit 1 + fi + # main logic + # no second variable, calculate singularly + if [ -z ''${2+x} ]; then + start="$(date -d "Yesterday $1" "+%s")" + if [ "''${time_start:0:2}" -gt "''${1:0:2}" ]; then + end="$(date -d "Yesterday $time_start" "+%s")" + printf "Early start: %s hours\\n" "$(date -d\@$((end - start)) -u +'scale=2; %H + %M/60' | ${pkgs.bc}/bin/bc)" + else + end="$(date -d "Yesterday $time_end" "+%s")" + printf "Late finish: %s hours\\n" "$(date -d\@$((start - end)) -u +'scale=2; %H + %M/60' | ${pkgs.bc}/bin/bc)" + fi + # second variable, calculate both and combine + else + start_am="$(date -d "Yesterday $1" "+%s")" + start_pm="$(date -d "Yesterday $2" "+%s")" + end_am="$(date -d "Yesterday $time_start" "+%s")" + end_pm="$(date -d "Yesterday $time_end" "+%s")" + printf "Combined overtimes: %s hours\\n" "$(echo "$(date -d\@$((end_am - start_am)) -u +'scale=2; %H + %M/60' | ${pkgs.bc}/bin/bc)" + "$(date -d\@$((start_pm - end_pm)) -u +'scale=2; %H + %M/60' | ${pkgs.bc}/bin/bc)" | ${pkgs.bc}/bin/bc)" + fi + ''; + +in { + environment.systemPackages = [ overtid ]; +} diff --git a/scripts/phone-dump.nix b/scripts/phone-dump.nix @@ -0,0 +1,57 @@ +{pkgs, ...}: let + phone-dump = pkgs.writeShellScriptBin "phone-dump" '' + # variables + phone_remote=phone + phone_ip=$(grep -A4 "$phone_remote" "$(rclone config file | tail -1)" | awk '/host/ {print $3}') + destination="/mnt/pictures/personal" + if [ ! -d "$destination" ]; then + echo "Destination $destination does not exist." + exit 1 + fi + + # if ping phone + if ping -c 1 "$phone_ip" &>/dev/null; then + echo "Phone reachable, mounting remote" + directory_temp="$(mktemp -d)" + rclone mount "$phone_remote": "$directory_temp" --daemon + cd "$directory_temp" || exit + + declare -a directories=( + "$directory_temp/DCIM/Camera" + "$directory_temp/Pictures" + "$directory_temp/Pictures/Whatsapp" + "$directory_temp/Android/media/com.whatsapp/WhatsApp/Media" + "$directory_temp/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Images" + "$directory_temp/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Video" + ) + for i in "''${directories[@]}" + do + if [ -d "$i" ]; then + echo "$i" + find "$i" -type f -name '.nomedia*' -delete -print + ${pkgs.phockup}/bin/phockup "$i" "$destination/" -m + fi + done + + if [ -d "$directory_temp/Pictures/Screenshots" ]; then + find "$directory_temp/Pictures/Screenshots" -type f -exec mv '{}' "$destination/screenshots/" -vi \; + fi + + echo "Tidying up..." + find "$destination" -type f -iname 'thumbs.db' -delete -print + find "$destination" -type f -name '.nomedia*' -delete -print + find "$destination" -type d -name '.thumbnails*' -delete -print + find "$directory_temp" -maxdepth 2 -type d -not -path "*/\.*" -empty -delete -print 2>/dev/null + echo "Unmounting storage..." + sleep 2s + umount "$directory_temp" || fusermount -uz "$directory_temp" + echo "Deduplicating photos..." + ${pkgs.jdupes}/bin/jdupes "$destination" -r + find "/tmp/tmp.*" -maxdepth 1 -type d -not -path "*/\.*" -empty -delete -print 2>/dev/null + else + echo "Phone not reachable via ping, exiting" && exit 1 + fi + ''; +in { + environment.systemPackages = [phone-dump]; +} diff --git a/scripts/watchedlist.nix b/scripts/watchedlist.nix @@ -0,0 +1,36 @@ +{ pkgs, ... }: + +let + watchedlist = pkgs.writeShellScriptBin "watchedlist" '' + # variables + if [ -z "$1" ] + then + database="watchedlist.db" + else + database="$1" + fi + # checks + if [ ! -f "$database" ] + then + echo Database "$database" file missing, exiting + exit 0 + fi + # TODO: blank database check + # movies + if [ -f "movies.csv" ]; then rm movies.csv; fi + sqlite3 -noheader -csv $database "select title from movie_watched;" > movies.csv + sed -i -e 's|\"||g' -e 's|^|* |g' movies.csv + sort -k 2 < movies.csv > movies.md + rm movies.csv + # tv shows + sqlite3 -noheader -csv $database "select * from tvshows;" > tv_shows_index.csv + watched_id=$(sqlite3 -noheader $database "select idShow from episode_watched;" | uniq) + for i in $watched_id; do grep "$i" tv_shows_index.csv | cut -f2- -d, >> tv_shows.csv; done + sed -i -e 's|\"||g' -e 's|^|* |g' tv_shows.csv + sort -k 2 < tv_shows.csv > tv_shows.md + rm tv_shows.csv tv_shows_index.csv + ''; + +in { + environment.systemPackages = [ watchedlist ]; +} diff --git a/scripts/youtube-id-rss.nix b/scripts/youtube-id-rss.nix @@ -0,0 +1,20 @@ +{ pkgs, ... }: + +let + youtube-id-rss = pkgs.writeShellScriptBin "youtube-id-rss" '' + if [ "$#" -eq 0 ] + then + echo "No URI argument supplied, using clipboard" + uri="$(wl-paste)" + else + uri="$1" + fi + + uri_id=$(curl --silent "$uri" | tr "\"" "\n" | grep -P '^(?=.*https)(?=.*channel)' | uniq -c | sort -rn | awk 'NR==1{print $2}' ) + base_id="$(echo "$uri_id" | awk -F "/" '{print $5}')" + printf "https://www.youtube.com/feeds/videos.xml?channel_id=%s\\n" "$base_id" + ''; + +in { + environment.systemPackages = [ youtube-id-rss ]; +}