diff --git a/flake.lock b/flake.lock index 9e61219b..65b8f048 100644 --- a/flake.lock +++ b/flake.lock @@ -175,11 +175,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1744174375, - "narHash": "sha256-oxI9TLgnQbQ/WL0tIwVSIooLbXq4PW1QUhf5aQmXFgk=", + "lastModified": 1744777043, + "narHash": "sha256-O6jgTxz9BKUiaJl03JsVHvSjtCOC8gHfDvC2UCfcLMc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ef3a956f697525883b77192cbe208233ea0f8f79", + "rev": "7a6f7f4c1c69eee05641beaa40e7f85da8e69fb0", "type": "github" }, "original": { diff --git a/hosts/nixos/porthos/secrets/secrets.nix b/hosts/nixos/porthos/secrets/secrets.nix index 425756c5..b3812b43 100644 --- a/hosts/nixos/porthos/secrets/secrets.nix +++ b/hosts/nixos/porthos/secrets/secrets.nix @@ -81,6 +81,7 @@ in "pyload/credentials.age".publicKeys = all; "servarr/autobrr/session-secret.age".publicKeys = all; + "servarr/cross-seed/configuration.json.age".publicKeys = all; "sso/auth-key.age" = { owner = "nginx-sso"; diff --git a/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age b/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age new file mode 100644 index 00000000..e9af03f4 Binary files /dev/null and b/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age differ diff --git a/hosts/nixos/porthos/services.nix b/hosts/nixos/porthos/services.nix index 561da278..96f15d38 100644 --- a/hosts/nixos/porthos/services.nix +++ b/hosts/nixos/porthos/services.nix @@ -148,6 +148,9 @@ in autobrr = { sessionSecretFile = secrets."servarr/autobrr/session-secret".path; }; + cross-seed = { + secretSettingsFile = secrets."servarr/cross-seed/configuration.json".path; + }; # ... But not Lidarr because I don't care for music that much lidarr = { enable = false; diff --git a/modules/home/atuin/default.nix b/modules/home/atuin/default.nix index 3f062638..dbd9690a 100644 --- a/modules/home/atuin/default.nix +++ b/modules/home/atuin/default.nix @@ -8,6 +8,10 @@ in # I want the full experience by default package = mkPackageOption pkgs "atuin" { }; + + daemon = { + enable = my.mkDisableOption "atuin daemon"; + }; }; config = lib.mkIf cfg.enable { @@ -15,12 +19,18 @@ in enable = true; inherit (cfg) package; + daemon = lib.mkIf cfg.daemon.enable { + enable = true; + }; + flags = [ # I *despise* this hijacking of the up key, even though I use Ctrl-p "--disable-up-arrow" ]; settings = { + # Reasonable date format + dialect = "uk"; # The package is managed by Nix update_check = false; # I don't care for the fancy display diff --git a/modules/home/delta/default.nix b/modules/home/delta/default.nix index f691fe72..6970b78e 100644 --- a/modules/home/delta/default.nix +++ b/modules/home/delta/default.nix @@ -21,6 +21,13 @@ in assertions = [ { # For its configuration + assertion = cfg.enable -> cfg.git.enable; + message = '' + `config.my.home.delta` must enable `config.my.home.delta.git` to be + properly configured. + ''; + } + { assertion = cfg.jujutsu.enable -> cfg.git.enable; message = '' `config.my.home.delta.jujutsu` relies on `config.my.home.delta.git` diff --git a/modules/home/tmux/default.nix b/modules/home/tmux/default.nix index 08b9202c..82ceb3a3 100644 --- a/modules/home/tmux/default.nix +++ b/modules/home/tmux/default.nix @@ -6,7 +6,7 @@ let (config.my.home.wm.windowManager != null) ]; - mkTerminalFlags = opt: flag: + mkTerminalFeature = opt: flag: let mkFlag = term: ''set -as terminal-features ",${term}:${flag}"''; enabledTerminals = lib.filterAttrs (_: v: v.${opt}) cfg.terminalFeatures; @@ -123,9 +123,9 @@ in } # Force OSC8 hyperlinks for each relevant $TERM - ${mkTerminalFlags "hyperlinks" "hyperlinks"} + ${mkTerminalFeature "hyperlinks" "hyperlinks"} # Force 24-bit color for each relevant $TERM - ${mkTerminalFlags "trueColor" "RGB"} + ${mkTerminalFeature "trueColor" "RGB"} ''; }; } diff --git a/modules/home/vim/after/queries/gitcommit/highlights.scm b/modules/home/vim/after/queries/gitcommit/highlights.scm new file mode 100644 index 00000000..05162c9d --- /dev/null +++ b/modules/home/vim/after/queries/gitcommit/highlights.scm @@ -0,0 +1,6 @@ +; extends + +; Highlight over-extended subject lines (rely on wrapping for message body) +((subject) @comment.error + (#vim-match? @comment.error ".\{50,}") + (#offset! @comment.error 0 50 0 0)) diff --git a/modules/home/vim/plugin/numbertoggle.lua b/modules/home/vim/plugin/numbertoggle.lua index 80427101..b1e3df21 100644 --- a/modules/home/vim/plugin/numbertoggle.lua +++ b/modules/home/vim/plugin/numbertoggle.lua @@ -22,13 +22,3 @@ vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "InsertEnter", "WinLeave" end end, }) - --- Never show the sign column in a terminal buffer -vim.api.nvim_create_autocmd({ "TermOpen" }, { - pattern = "*", - group = numbertoggle, - callback = function() - vim.opt.number = false - vim.opt.relativenumber = false - end, -}) diff --git a/modules/home/vim/plugin/signtoggle.lua b/modules/home/vim/plugin/signtoggle.lua index 9765a818..3deca340 100644 --- a/modules/home/vim/plugin/signtoggle.lua +++ b/modules/home/vim/plugin/signtoggle.lua @@ -1,26 +1,21 @@ local signtoggle = vim.api.nvim_create_augroup("signtoggle", { clear = true }) --- Only show sign column for the currently focused buffer +-- Only show sign column for the currently focused buffer, if it has a number column vim.api.nvim_create_autocmd({ "BufEnter", "FocusGained", "WinEnter" }, { pattern = "*", group = signtoggle, callback = function() - vim.opt.signcolumn = "yes" + if vim.opt.number:get() then + vim.opt.signcolumn = "yes" + end end, }) vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "WinLeave" }, { pattern = "*", group = signtoggle, callback = function() - vim.opt.signcolumn = "no" - end, -}) - --- Never show the sign column in a terminal buffer -vim.api.nvim_create_autocmd({ "TermOpen" }, { - pattern = "*", - group = signtoggle, - callback = function() - vim.opt.signcolumn = "no" + if vim.opt.number:get() then + vim.opt.signcolumn = "no" + end end, }) diff --git a/modules/nixos/services/servarr/autobrr.nix b/modules/nixos/services/servarr/autobrr.nix index afb07f4c..c3370cb8 100644 --- a/modules/nixos/services/servarr/autobrr.nix +++ b/modules/nixos/services/servarr/autobrr.nix @@ -1,4 +1,4 @@ -# IRC-based +# IRC-based indexer { config, lib, ... }: let cfg = config.my.services.servarr.autobrr; @@ -40,6 +40,7 @@ in my.services.nginx.virtualHosts = { autobrr = { inherit (cfg) port; + websocketsLocations = [ "/api" ]; }; }; @@ -54,7 +55,7 @@ in environment.etc = { "fail2ban/filter.d/autobrr.conf".text = '' [Definition] - failregex = ^.*Auth: invalid login \[.*\] from: $ + failregex = "message":"Auth: Failed login attempt username: \[.*\] ip: " journalmatch = _SYSTEMD_UNIT=autobrr.service ''; }; diff --git a/modules/nixos/services/servarr/cross-seed.nix b/modules/nixos/services/servarr/cross-seed.nix new file mode 100644 index 00000000..74f216ae --- /dev/null +++ b/modules/nixos/services/servarr/cross-seed.nix @@ -0,0 +1,96 @@ +# Automatic cross-seeding for video media +{ config, lib, ... }: +let + cfg = config.my.services.servarr.cross-seed; +in +{ + options.my.services.servarr.cross-seed = with lib; { + enable = mkEnableOption "cross-seed daemon" // { + default = config.my.services.servarr.enableAll; + }; + + port = mkOption { + type = types.port; + default = 2468; + example = 8080; + description = "Internal port for daemon"; + }; + + linkDirectory = mkOption { + type = types.str; + default = "/data/downloads/complete/links"; + example = "/var/lib/cross-seed/links"; + description = "Link directory"; + }; + + secretSettingsFile = mkOption { + type = types.str; + example = "/run/secrets/cross-seed-secrets.json"; + description = '' + File containing secret settings. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.cross-seed = { + enable = true; + group = "media"; + + # Rely on recommended defaults for tracker snatches etc... + useGenConfigDefaults = true; + + settings = { + inherit (cfg) port; + host = "127.0.0.1"; + + # Inject torrents to client directly + action = "inject"; + # Query the client for torrents to match + useClientTorrents = true; + # Use hardlinks + linkType = "hardlink"; + # Use configured link directory + linkDirs = [ cfg.linkDirectory ]; + # Match as many torrents as possible + matchMode = "partial"; + # Cross-seed full season if at least 50% of episodes are already downloaded + seasonFromEpisodes = 0.5; + }; + + settingsFile = cfg.secretSettingsFile; + }; + + systemd.services.cross-seed = { + serviceConfig = { + # Loose umask to make cross-seed links readable by `media` + UMask = "0002"; + }; + }; + + # Set-up media group + users.groups.media = { }; + + my.services.nginx.virtualHosts = { + cross-seed = { + inherit (cfg) port; + }; + }; + + services.fail2ban.jails = { + cross-seed = '' + enabled = true + filter = cross-seed + action = iptables-allports + ''; + }; + + environment.etc = { + "fail2ban/filter.d/cross-seed.conf".text = '' + [Definition] + failregex = ^.*Unauthorized API access attempt to .* from $ + journalmatch = _SYSTEMD_UNIT=cross-seed.service + ''; + }; + }; +} diff --git a/modules/nixos/services/servarr/default.nix b/modules/nixos/services/servarr/default.nix index 409fcdc6..dca57cf6 100644 --- a/modules/nixos/services/servarr/default.nix +++ b/modules/nixos/services/servarr/default.nix @@ -7,6 +7,7 @@ imports = [ ./autobrr.nix ./bazarr.nix + ./cross-seed.nix ./jackett.nix ./nzbhydra.nix ./prowlarr.nix diff --git a/modules/nixos/services/transmission/default.nix b/modules/nixos/services/transmission/default.nix index ac8b24dd..16d51e3f 100644 --- a/modules/nixos/services/transmission/default.nix +++ b/modules/nixos/services/transmission/default.nix @@ -65,6 +65,8 @@ in # Proxied behind Nginx. rpc-whitelist-enabled = true; rpc-whitelist = "127.0.0.1"; + + umask = "002"; # To go with `downloadDirPermissions` }; };