Compare commits

...

20 commits

Author SHA1 Message Date
4e74eceeee home: jujutsu: explicitly create 'conf.d'
All checks were successful
ci/woodpecker/push/check Pipeline was successful
This is to serve as a reminder of _how_ to add a local configuration
file.
2025-04-22 13:57:15 +00:00
9443efeec4 WIP: ADD NOTE FOR FUTURE SELF 2025-04-22 13:57:15 +00:00
dd00d042d8 home: jj: use verbose draft commit messages 2025-04-22 13:57:15 +00:00
a0a8dde6ee WIP: add jujutsu (w/ Delta) 2025-04-22 13:57:05 +00:00
946eab9ec0 home: git: extract 'delta' configuration
All checks were successful
ci/woodpecker/push/check Pipeline was successful
I want to be able to re-use it between different source control systems
(e.g: `jj`).

As a first step, extract it to a proper module so that I can have it
live in a single space.
2025-04-22 13:53:35 +00:00
ec1c94676a home: vim: highlight over-extended commit subjects
All checks were successful
ci/woodpecker/push/check Pipeline was successful
2025-04-22 13:15:04 +00:00
29b47d7f84 home: tmux: rename 'mkTerminalFeature'
This is a more accurate name to describe what the function is doing.
2025-04-22 13:04:36 +00:00
135cef2536 home: atuin: add daemon
All checks were successful
ci/woodpecker/push/check Pipeline was successful
Enabled by default, I probably won't have a reason *not* to use it.
2025-04-16 16:05:14 +00:00
ee1139713c hosts: nixos: porthos: services: enable cross-seed
All checks were successful
ci/woodpecker/push/check Pipeline was successful
2025-04-16 17:26:10 +02:00
058096079e hosts: nixos: porthos: secrets: add cross-seed 2025-04-16 17:26:10 +02:00
c40090d176 nixos: services: servarr: add cross-seed 2025-04-16 17:26:10 +02:00
1b6a48d6c2 flake: bump inputs 2025-04-16 17:07:38 +02:00
e4bc0444bf nixos: services: transmission: fix umask
I want downloads to be readable by the `media` group. The permissions
weren't correctly applied without `umask`.
2025-04-16 17:01:18 +02:00
c69aaa7adb nixos: services: servarr: autobrr: fix websockets
I found some logs complaining about websockets before enabling this.
2025-04-16 17:01:18 +02:00
26ee59ef6e home: atuin: use 'uk' dialect for dates
All checks were successful
ci/woodpecker/push/check Pipeline was successful
This should be for date *parsing*, from my looking at the code.

Unlikely to be relevant, but might as well set it to the saner of the
two options.
2025-04-14 13:54:57 +00:00
6f5ac4e55f home: vim: signtoggle: only show signs if 'number'
All checks were successful
ci/woodpecker/push/check Pipeline was successful
If a buffer doesn't show a number column, I probably also don't want a
sign column to be toggled on/off in there.
2025-04-14 10:24:33 +00:00
67936af4c7 home: vim: signtoggle: remove 'TermOpen' event
It's now part of upstream's default setup.
2025-04-14 10:20:02 +00:00
e82ae4a219 home: vim: numbertoggle: remove 'TermOpen' event
It's now part of upstream's default setup.
2025-04-14 10:20:02 +00:00
a0473a5c6c nixos: services: servarr: autobrr: fix fail2ban
All checks were successful
ci/woodpecker/push/check Pipeline was successful
The log line for authentication failures has been updated since the
original PR.

It also happens to be logged in JSON, and I'm a bit too lazy to match it
more properly than this.
2025-04-12 11:30:14 +02:00
a28295da27 nixos: services: servarr: autobrr: fix comment
All checks were successful
ci/woodpecker/push/check Pipeline was successful
2025-04-11 19:01:08 +02:00
17 changed files with 357 additions and 58 deletions

6
flake.lock generated
View file

@ -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": {

View file

@ -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";

View file

@ -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;

View file

@ -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

View file

@ -8,6 +8,7 @@
./bluetooth
./calibre
./comma
./delta
./dircolors
./direnv
./discord
@ -23,6 +24,7 @@
./gtk
./htop
./jq
./jujutsu
./keyboard
./mail
./mpv

View file

@ -0,0 +1,92 @@
{ config, pkgs, lib, ... }:
let
cfg = config.my.home.delta;
in
{
options.my.home.delta = with lib; {
enable = my.mkDisableOption "delta configuration";
package = mkPackageOption pkgs "delta" { };
git = {
enable = my.mkDisableOption "git integration";
};
jujutsu = {
enable = my.mkDisableOption "jujutsu integration";
};
};
config = lib.mkIf cfg.enable {
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`
being enabled.
'';
}
];
home.packages = [ cfg.package ];
programs.git = lib.mkIf cfg.git.enable {
delta = {
enable = true;
inherit (cfg) package;
options = {
features = "diff-highlight decorations";
# Less jarring style for `diff-highlight` emulation
diff-highlight = {
minus-style = "red";
minus-non-emph-style = "red";
minus-emph-style = "bold red 52";
plus-style = "green";
plus-non-emph-style = "green";
plus-emph-style = "bold green 22";
whitespace-error-style = "reverse red";
};
# Personal preference for easier reading
decorations = {
commit-style = "raw"; # Do not recolor meta information
keep-plus-minus-markers = true;
paging = "always";
};
};
};
};
programs.jujutsu = lib.mkIf cfg.jujutsu.enable {
settings = {
merge-tools = {
delta = {
# Errors are signaled with exit codes greater or equal to 2
diff-expected-exit-codes = [ 0 1 ];
};
};
ui = {
diff = {
# Delta expects a `git diff` input
format = "git";
};
pager = "delta";
};
};
};
};
}

View file

@ -42,34 +42,6 @@ in
lfs.enable = true;
delta = {
enable = true;
options = {
features = "diff-highlight decorations";
# Less jarring style for `diff-highlight` emulation
diff-highlight = {
minus-style = "red";
minus-non-emph-style = "red";
minus-emph-style = "bold red 52";
plus-style = "green";
plus-non-emph-style = "green";
plus-emph-style = "bold green 22";
whitespace-error-style = "reverse red";
};
# Personal preference for easier reading
decorations = {
commit-style = "raw"; # Do not recolor meta information
keep-plus-minus-markers = true;
paging = "always";
};
};
};
# There's more
extraConfig = {
# Makes it a bit more readable

View file

@ -0,0 +1,128 @@
{ config, pkgs, lib, ... }:
let
cfg = config.my.home.jujutsu;
inherit (lib.my) mkMailAddress;
in
{
options.my.home.jujutsu = with lib; {
enable = my.mkDisableOption "jujutsu configuration";
package = mkPackageOption pkgs "jujutsu" { };
};
config = lib.mkIf cfg.enable {
assertions = [
{
# For `jj git` commands
assertion = cfg.enable -> config.my.home.git.enable;
message = ''
`config.my.home.jujutsu` relies on `config.my.home.git` being enabled.
'';
}
];
programs.jujutsu = {
enable = true;
inherit (cfg) package;
settings = {
# Who am I?
user = {
name = "Bruno BELANYI";
email = mkMailAddress "bruno" "belanyi.fr";
};
aliases = {
jj = [ "util" "exec" "--" "jj" ];
# FIXME:
# * topo sort by default (I think? test it)
# * still not a big fan of the template
lol = [ "log" "-r" "..@" "-T" "builtin_log_oneline" ];
lola = [ "lol" "-r" "all()" ];
# TODO:
# * `pick` (https://github.com/jj-vcs/jj/issues/5446): [ "util" "exec" "--" "bash" "-c" "jj log -p -r \"diff_contains($1)\"" ]
# * `root`: `jj workspace root` (barely necessary then)
};
# FIXME: git equivalents
# blame = {
# coloring = "repeatedLines";
# markIgnoredLines = true;
# markUnblamables = true;
# };
# FIXME: log colors should probably match git
# FIXME: patience diff?
# FIXME: fetch prune/pruneTags?
# FIXME: pull.rebase=true? Probably true TBH
# FIXME: push.default=simple? Probably true TBH
# FIXME: conflict style? ui.conflict-marker-style=git is diff3/zdiff3
# FIXME: from ma_9's config, plus my own stuff
# snapshot = {
# auto-track = "none()";
# };
#
# ui = {
# diff-editor = ":builtin"; # To silence hints
# movement = {
# edit = false;
# };
# };
templates = {
# Equivalent to `commit.verbose = true` in Git
draft_commit_description = "commit_description_verbose(self)";
};
template-aliases = {
"commit_description_verbose(commit)" = ''
concat(
commit_description(commit),
"JJ: ignore-rest\n",
diff.git(),
)
'';
# FIXME: use `diff.summary()` instead? Supported by syntax highlighting
# See https://github.com/jj-vcs/jj/issues/1946#issuecomment-2572986485
# FIXME: tree-sitter grammar isn't in `nvim-treesitter` (https://github.com/kareigu/tree-sitter-jjdescription)
"commit_description(commit)" = ''
concat(
commit.description(), "\n",
"JJ: This commit contains the following changes:\n",
indent("JJ: ", diff.stat(72)),
)
'';
};
"--scope" = [
# Multiple identities
{
"--when" = {
repositories = [ "~/git/EPITA/" ];
};
user = {
name = "Bruno BELANYI";
email = mkMailAddress "bruno.belanyi" "epita.fr";
};
}
{
"--when" = {
repositories = [ "~/git/work/" ];
};
user = {
name = "Bruno BELANYI";
email = mkMailAddress "ambroisie" "google.com";
};
}
];
};
};
# To drop in a `local.toml` configuration, not-versioned
xdg.configFile = {
"jj/conf.d/.keep".text = "";
};
};
}

View file

@ -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"}
'';
};
}

View file

@ -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))

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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: <HOST>$
failregex = "message":"Auth: Failed login attempt username: \[.*\] ip: <HOST>"
journalmatch = _SYSTEMD_UNIT=autobrr.service
'';
};

View file

@ -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 <HOST>$
journalmatch = _SYSTEMD_UNIT=cross-seed.service
'';
};
};
}

View file

@ -7,6 +7,7 @@
imports = [
./autobrr.nix
./bazarr.nix
./cross-seed.nix
./jackett.nix
./nzbhydra.nix
./prowlarr.nix

View file

@ -65,6 +65,8 @@ in
# Proxied behind Nginx.
rpc-whitelist-enabled = true;
rpc-whitelist = "127.0.0.1";
umask = "002"; # To go with `downloadDirPermissions`
};
};