summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif')
-rw-r--r--accounts/gkleen@sif/default.nix81
-rw-r--r--accounts/gkleen@sif/emacs.el2
-rw-r--r--accounts/gkleen@sif/niri/default.nix205
-rw-r--r--accounts/gkleen@sif/niri/mako.nix4
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix7
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix21
-rw-r--r--accounts/gkleen@sif/synadm/default.nix9
-rw-r--r--accounts/gkleen@sif/synadm/synadm_yaml15
-rw-r--r--accounts/gkleen@sif/utils/async-yt-dlp.nix57
9 files changed, 367 insertions, 34 deletions
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix
index e07362fc..706eb241 100644
--- a/accounts/gkleen@sif/default.nix
+++ b/accounts/gkleen@sif/default.nix
@@ -71,6 +71,7 @@ in {
71 imports = [ 71 imports = [
72 ./libvirt 72 ./libvirt
73 ./niri 73 ./niri
74 ./synadm
74 flakeInputs.nix-index-database.hmModules.nix-index 75 flakeInputs.nix-index-database.hmModules.nix-index
75 flakeInputs.impermanence.nixosModules.home-manager.impermanence 76 flakeInputs.impermanence.nixosModules.home-manager.impermanence
76 ]; 77 ];
@@ -282,6 +283,16 @@ in {
282 pro = "$HOME/projects/pro"; 283 pro = "$HOME/projects/pro";
283 media = "$HOME/media"; 284 media = "$HOME/media";
284 }; 285 };
286 jq.colors = {
287 arrays = "1;37";
288 "false" = "0;37";
289 "null" = "2;37";
290 numbers = "0;37";
291 objectKeys = "1;34";
292 objects = "1;37";
293 strings = "0;32";
294 "true" = "0;37";
295 };
285 296
286 obs-studio = { 297 obs-studio = {
287 enable = true; 298 enable = true;
@@ -317,8 +328,10 @@ in {
317 # notify_on_cmd_finish = "invisible 120"; 328 # notify_on_cmd_finish = "invisible 120";
318 }; 329 };
319 keybindings = { 330 keybindings = {
320 "kitty_mod+n" = "detach_window"; 331 "kitty_mod+n" = "new_os_window_with_cwd";
321 "kitty_mod+m" = "detach_window ask"; 332 "kitty_mod+m" = "detach_window ask";
333 "kitty_mod+enter" = "new_window_with_cwd";
334 "kitty_mod+t" = "new_tab_with_cwd";
322 }; 335 };
323 }; 336 };
324 fuzzel = { 337 fuzzel = {
@@ -331,7 +344,7 @@ in {
331 font = "Fira Sans"; 344 font = "Fira Sans";
332 }; 345 };
333 colors = { 346 colors = {
334 background = "000000aa"; 347 background = "000000cc";
335 text = "cdd6f4ff"; 348 text = "cdd6f4ff";
336 match = "94e2d5ff"; 349 match = "94e2d5ff";
337 selection = "585b70ff"; 350 selection = "585b70ff";
@@ -352,6 +365,7 @@ in {
352 enable = true; 365 enable = true;
353 settings.show_banner = false; 366 settings.show_banner = false;
354 }; 367 };
368 fd.enable = true;
355 }; 369 };
356 370
357 services = { 371 services = {
@@ -477,6 +491,13 @@ in {
477 }; 491 };
478 }; 492 };
479 493
494 qt.kde.settings = {
495 kwalletrc = {
496 KSecretD.Enabled = false;
497 Wallet."Default Wallet" = "store";
498 };
499 };
500
480 xsession.preferStatusNotifierItems = true; 501 xsession.preferStatusNotifierItems = true;
481 502
482 xresources.properties = import ./xresources.nix; 503 xresources.properties = import ./xresources.nix;
@@ -496,8 +517,7 @@ in {
496 libguestfs-with-appliance nerd-fonts.fira-mono 517 libguestfs-with-appliance nerd-fonts.fira-mono
497 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts 518 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts
498 swtpm (hunspellWithDicts (with hunspellDicts; [en_GB-large de_DE])) 519 swtpm (hunspellWithDicts (with hunspellDicts; [en_GB-large de_DE]))
499 libation 520 libation libqalculate
500 # synadm
501 ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; }); 521 ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; });
502 522
503 file = { 523 file = {
@@ -520,6 +540,7 @@ in {
520 STACK_XDG = 1; 540 STACK_XDG = 1;
521 EDITOR = lib.getExe' editor "emacsclient"; 541 EDITOR = lib.getExe' editor "emacsclient";
522 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone"; 542 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone";
543 SYSTEMD_TINT_BACKGROUND = "false";
523 }; 544 };
524 545
525 extraProfileCommands = '' 546 extraProfileCommands = ''
@@ -556,9 +577,17 @@ in {
556 General = { 577 General = {
557 dot_as_separator = 0; 578 dot_as_separator = 0;
558 }; 579 };
580 Mode = {
581 calculate_as_you_type = 1;
582 };
559 }; 583 };
560 }; 584 };
561 "emacs/init.el".source = ./emacs.el; 585 "emacs/init.el".source = pkgs.substitute {
586 src = ./emacs.el;
587 substitutions = [
588 "--subst-var-by" "ksshaskpass" (lib.getExe pkgs.kdePackages.ksshaskpass)
589 ];
590 };
562 "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = '' 591 "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = ''
563 [Unit] 592 [Unit]
564 After=graphical-session.target 593 After=graphical-session.target
@@ -576,6 +605,8 @@ in {
576 xdg.dataFile = { 605 xdg.dataFile = {
577 "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service"; 606 "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service";
578 "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service"; 607 "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service";
608 "dbus-1/services/org.kde.kwalletd6.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd6.service";
609 "dbus-1/services/org.kde.kwalletd5.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd5.service";
579 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation { 610 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation {
580 inherit (sources.emoji-data) pname src; 611 inherit (sources.emoji-data) pname src;
581 version = lib.removePrefix "v" sources.emoji-data.version; 612 version = lib.removePrefix "v" sources.emoji-data.version;
@@ -663,10 +694,10 @@ in {
663 exec -- \ 694 exec -- \
664 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \ 695 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \
665 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ 696 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \
666 --property 'Environment=DSCP=46' \ 697 -E DSCP=46 -E NIXOS_OZONE_WL \
667 -- ${lib.getExe pkgs.dscp} ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \ 698 -- ${lib.getExe pkgs.dscp} ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \
668 --class=Rainbow \ 699 --class=Rainbow \
669 --kiosk "https://web.openrainbow.com" \ 700 --app="https://web.openrainbow.com" \
670 --user-data-dir=''${HOME}/.config/google-chrome-rainbow 701 --user-data-dir=''${HOME}/.config/google-chrome-rainbow
671 ''); 702 '');
672 icon = pkgs.fetchurl { 703 icon = pkgs.fetchurl {
@@ -677,6 +708,42 @@ in {
677 StartupWMClass = "Rainbow"; 708 StartupWMClass = "Rainbow";
678 }; 709 };
679 }; 710 };
711 kimai = {
712 name = "Kimai";
713 exec = toString (pkgs.writeShellScript "kimai" ''
714 exec -- \
715 ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \
716 --class=Kimai \
717 --app="https://kimai.yggdrasil.li" \
718 --user-data-dir=''${HOME}/.config/google-chrome-kimai
719 '');
720 icon = pkgs.fetchurl {
721 url = "https://www.kimai.org/images/kimai_logo.png";
722 hash = "sha256-lnlOttzR2SwXA70R+egJUkeKr4U5V0avqTk8uX4bqfs=";
723 };
724 settings = {
725 StartupWMClass = "Kimai";
726 StartupNotify = "true";
727 };
728 };
729 audiobookshelf = {
730 name = "Audiobookshelf";
731 exec = toString (pkgs.writeShellScript "audiobookshelf" ''
732 exec -- \
733 ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \
734 --class=Audiobookshelf \
735 --app="https://audiobookshelf.yggdrasil.li" \
736 --user-data-dir=''${HOME}/.config/google-chrome-audiobookshelf
737 '');
738 icon = pkgs.fetchurl {
739 url = "https://www.audiobookshelf.org/Logo.png";
740 hash = "sha256-JGPk+WNT1C4DC4lSMb0K0YmAMT5LvmSOeO0QRzkc7Lk=";
741 };
742 settings = {
743 StartupWMClass = "Audiobookshelf";
744 StartupNotify = "true";
745 };
746 };
680 thunderbird-lmu = { 747 thunderbird-lmu = {
681 name = "Thunderbird (LMU)"; 748 name = "Thunderbird (LMU)";
682 exec = "thunderbird --name thunderbird -P lmu %U"; 749 exec = "thunderbird --name thunderbird -P lmu %U";
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
index 563c5d0b..3beefba6 100644
--- a/accounts/gkleen@sif/emacs.el
+++ b/accounts/gkleen@sif/emacs.el
@@ -254,3 +254,5 @@ necessarily running."
254(bind-key "C-x C-m" #'move-file) 254(bind-key "C-x C-m" #'move-file)
255 255
256(let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock)) 256(let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock))
257(setenv "SSH_ASKPASS_REQUIRE" "prefer")
258(setenv "SSH_ASKPASS" "@ksshaskpass@")
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index 803b3a0d..8752f3e3 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -35,7 +35,11 @@ let
35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then 35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
36 niri msg action focus-workspace-previous 36 niri msg action focus-workspace-previous
37 else 37 else
38 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 38 if [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].is_focused' <<<"$workspaces_json") != "true" ]] && [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].id' <<<"$workspaces_json") = $(jq -r '.workspace_id' <<<"$window_json") ]]; then
39 niri msg action focus-workspace "$workspace_name"
40 else
41 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
42 fi
39 fi 43 fi
40 exit 0 44 exit 0
41 fi 45 fi
@@ -45,7 +49,6 @@ let
45 ''; 49 '';
46 }; 50 };
47 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); 51 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
48 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
49 52
50 with_adjacent_workspace = pkgs.writeShellApplication { 53 with_adjacent_workspace = pkgs.writeShellApplication {
51 name = "with-adjacent-workspace"; 54 name = "with-adjacent-workspace";
@@ -84,7 +87,7 @@ let
84 }; 87 };
85 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; 88 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
86 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 89 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
87 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 90 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
88 91
89 with_unnamed_workspace = pkgs.writeShellApplication { 92 with_unnamed_workspace = pkgs.writeShellApplication {
90 name = "with-unnamed-workspace"; 93 name = "with-unnamed-workspace";
@@ -131,7 +134,7 @@ let
131 134
132 windows_json="$(niri msg -j windows)" 135 windows_json="$(niri msg -j windows)"
133 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 136 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
134 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --log-level=warning --dmenu --index)" 137 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --width=60 --log-level=warning --dmenu --index)"
135 # shellcheck disable=SC2016 138 # shellcheck disable=SC2016
136 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" 139 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
137 140
@@ -141,6 +144,25 @@ let
141 ''; 144 '';
142 }; 145 };
143 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); 146 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
147
148 with_predicate_window = pred: pkgs.writeShellApplication {
149 name = "with-predicate-window";
150 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
151 text = ''
152 action="$1"
153 shift
154
155 windows_json="$(niri msg -j windows)"
156 window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")"
157
158 [[ -z "$window_json" || $window_json = "null" ]] && exit 1
159
160 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
161 '';
162 };
163
164 with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent"));
165 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
144in { 166in {
145 imports = [ 167 imports = [
146 ./waybar.nix 168 ./waybar.nix
@@ -171,6 +193,17 @@ in {
171 type = lib.types.nullOr lib.types.str; 193 type = lib.types.nullOr lib.types.str;
172 default = null; 194 default = null;
173 }; 195 };
196 moveKey = lib.mkOption {
197 type = lib.types.nullOr lib.types.str;
198 default = let
199 keys = lib.splitString "+" config.key;
200 defMoveKey = lib.concatStringsSep "+" (lib.flatten [
201 (lib.take (lib.length keys - 1) keys)
202 ["Shift"]
203 (lib.takeEnd 1 keys)
204 ]);
205 in if config.key == null then null else defMoveKey;
206 };
174 spawn = lib.mkOption { 207 spawn = lib.mkOption {
175 type = lib.types.nullOr (lib.types.listOf lib.types.str); 208 type = lib.types.nullOr (lib.types.listOf lib.types.str);
176 default = null; 209 default = null;
@@ -245,7 +278,7 @@ in {
245 Service = { 278 Service = {
246 Type = "simple"; 279 Type = "simple";
247 Sockets = [ "niri-workspace-history.socket" ]; 280 Sockets = [ "niri-workspace-history.socket" ];
248 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' 281 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
249 import os 282 import os
250 import socket 283 import socket
251 import json 284 import json
@@ -274,7 +307,7 @@ in {
274 307
275 def focus_workspace(output, workspace): 308 def focus_workspace(output, workspace):
276 with history_lock: 309 with history_lock:
277 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 310 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
278 # print(json.dumps(workspace_history), file=sys.stderr) 311 # print(json.dumps(workspace_history), file=sys.stderr)
279 312
280 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 313 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -297,14 +330,14 @@ in {
297 330
298 class RequestHandler(StreamRequestHandler): 331 class RequestHandler(StreamRequestHandler):
299 def handle(self): 332 def handle(self):
300 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 333 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
301 with history_lock: 334 with history_lock:
302 json.dump(workspace_history, out) 335 json.dump(workspace_history, out)
303 336
304 337
305 class Server(ThreadingTCPServer): 338 class Server(ThreadingTCPServer):
306 def __init__(self): 339 def __init__(self):
307 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 340 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
308 self.socket = socket.fromfd(3, self.address_family, self.socket_type) 341 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
309 342
310 343
@@ -330,6 +363,79 @@ in {
330 ''; 363 '';
331 }; 364 };
332 }; 365 };
366 systemd.user.services.niri-workspace-sort = {
367 Unit = {
368 BindsTo = [ "niri.service" ];
369 After = [ "niri.service" ];
370 };
371 Install = {
372 WantedBy = [ "niri.service" ];
373 };
374 Service = {
375 Type = "simple";
376 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
377 import os
378 import sys
379 import socket
380 import json
381
382 outputs = None
383 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
384
385
386 class Niri(socket.socket):
387 def __init__(self):
388 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
389 super().connect(os.environ["NIRI_SOCKET"])
390 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
391
392 def cmd(self, obj):
393 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
394
395 def event_stream(self):
396 self.cmd("EventStream")
397 return self.fh
398
399
400 with Niri() as niri, Niri().event_stream() as niri_stream:
401 for line in niri_stream:
402 workspaces = None
403 if line_json := json.loads(line):
404 if "WorkspacesChanged" in line_json:
405 workspaces = line_json["WorkspacesChanged"]["workspaces"]
406
407 if workspaces is None:
408 continue
409
410 old_outputs = outputs
411 outputs = {ws["output"] for ws in workspaces}
412 if old_outputs is None:
413 print("Initial outputs: {}".format(outputs), file=sys.stderr)
414 continue
415
416 new_outputs = outputs - old_outputs
417 if not new_outputs:
418 continue
419 print("New outputs: {}".format(new_outputs), file=sys.stderr)
420
421 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
422 target_output = next(iter(outputs - set(only.keys())))
423 if not target_output:
424 continue
425 for ws in relevant_workspaces:
426 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
427 if ws["output"] not in set(only.keys()):
428 continue
429 if ws_ident in only[ws["output"]]:
430 continue
431
432 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
433 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
434 '';
435 Restart = "on-failure";
436 RestartSec = 10;
437 };
438 };
333 439
334 programs.niri.scratchspaces = [ 440 programs.niri.scratchspaces = [
335 { name = "pwctl"; 441 { name = "pwctl";
@@ -343,7 +449,7 @@ in {
343 { title = "^Access Request.*"; } 449 { title = "^Access Request.*"; }
344 { title = ".*Passkey credentials$"; } 450 { title = ".*Passkey credentials$"; }
345 ]; 451 ];
346 windowRuleExtra = [ 452 windowRuleExtra = with kdl; [
347 (kdl.leaf "open-focused" false) 453 (kdl.leaf "open-focused" false)
348 ]; 454 ];
349 key = "Mod+Control+P"; 455 key = "Mod+Control+P";
@@ -371,6 +477,20 @@ in {
371 app-id = "com.github.wwmm.easyeffects"; 477 app-id = "com.github.wwmm.easyeffects";
372 spawn = [ "easyeffects" ]; 478 spawn = [ "easyeffects" ];
373 } 479 }
480 { name = "time";
481 key = "Mod+Control+K";
482 app-id = "chrome-kimai.yggdrasil.li__-Default";
483 spawn = [ (toString (pkgs.resholve.writeScript "kimai" {
484 interpreter = pkgs.runtimeShell;
485 inputs = [ pkgs.dex ];
486 execer = [ "cannot:${lib.getExe pkgs.dex}" ];
487 } ''
488 exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop
489 '')) ];
490 windowRuleExtra = with kdl; [
491 (leaf "block-out-from" "screencast")
492 ];
493 }
374 ]; 494 ];
375 programs.niri.config = 495 programs.niri.config =
376 let 496 let
@@ -415,6 +535,10 @@ in {
415 ]) 535 ])
416 ]) 536 ])
417 537
538 (plain "gestures" [
539 (plain "hot-corners" [(flag "off")])
540 ])
541
418 (plain "environment" (lib.mapAttrsToList leaf { 542 (plain "environment" (lib.mapAttrsToList leaf {
419 NIXOS_OZONE_WL = "1"; 543 NIXOS_OZONE_WL = "1";
420 QT_QPA_PLATFORM = "wayland"; 544 QT_QPA_PLATFORM = "wayland";
@@ -422,6 +546,10 @@ in {
422 GDK_BACKEND = "wayland"; 546 GDK_BACKEND = "wayland";
423 SDL_VIDEODRIVER = "wayland"; 547 SDL_VIDEODRIVER = "wayland";
424 DISPLAY = ":0"; 548 DISPLAY = ":0";
549 ELECTRON_OZONE_PLATFORM_HINT = "auto";
550 SSH_ASKPASS_REQUIRE = "prefer";
551 SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
552 SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
425 })) 553 }))
426 554
427 (node "output" "eDP-1" [ 555 (node "output" "eDP-1" [
@@ -536,7 +664,7 @@ in {
536 (plain "window-rule" [ 664 (plain "window-rule" [
537 (map (title: 665 (map (title:
538 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) 666 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
539 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"]) 667 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
540 (leaf "open-focused" true) 668 (leaf "open-focused" true)
541 (leaf "open-floating" true) 669 (leaf "open-floating" true)
542 ]) 670 ])
@@ -565,7 +693,7 @@ in {
565 (plain "window-rule" [ 693 (plain "window-rule" [
566 (leaf "match" { app-id = "^thunderbird$"; }) 694 (leaf "match" { app-id = "^thunderbird$"; })
567 (leaf "match" { app-id = "^Element$"; }) 695 (leaf "match" { app-id = "^Element$"; })
568 (leaf "match" { app-id = "^Rainbow$"; }) 696 (leaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
569 (leaf "open-on-workspace" "comm") 697 (leaf "open-on-workspace" "comm")
570 ]) 698 ])
571 (plain "window-rule" [ 699 (plain "window-rule" [
@@ -584,6 +712,11 @@ in {
584 (leaf "open-focused" false) 712 (leaf "open-focused" false)
585 ]) 713 ])
586 (plain "window-rule" [ 714 (plain "window-rule" [
715 (leaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
716 (leaf "match" { app-id = "^YouTube Music Desktop App$"; })
717 (leaf "open-on-workspace" "vid")
718 ])
719 (plain "window-rule" [
587 (leaf "match" { app-id = "^pdfpc$"; }) 720 (leaf "match" { app-id = "^pdfpc$"; })
588 (plain "default-column-width" [(leaf "proportion" 1.)]) 721 (plain "default-column-width" [(leaf "proportion" 1.)])
589 ]) 722 ])
@@ -633,7 +766,21 @@ in {
633 "Mod+Slash".action = show-hotkey-overlay; 766 "Mod+Slash".action = show-hotkey-overlay;
634 767
635 "Mod+Return".action = spawn terminal; 768 "Mod+Return".action = spawn terminal;
636 "Mod+Shift+Return".action = spawn terminal (lib.getExe config.programs.nushell.package); 769 "Mod+Shift+Return".action =
770 let
771 nushellKitty = pkgs.symlinkJoin {
772 name = "nushell-kitty";
773 paths = [ config.programs.kitty.package ];
774 buildInputs = [ pkgs.makeWrapper ];
775 postBuild = ''
776 wrapProgram $out/bin/kitty \
777 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
778 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
779 shell ${lib.getExe config.programs.nushell.package}
780 ''}"
781 '';
782 };
783 in spawn (lib.getExe' nushellKitty "kitty");
637 "Mod+Q".action = close-window; 784 "Mod+Q".action = close-window;
638 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); 785 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
639 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; 786 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
@@ -669,12 +816,12 @@ in {
669 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat) 816 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
670 $FOUND || echo 817 $FOUND || echo
671 } 818 }
672 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $? 819 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
673 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then 820 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
674 QALC_RES="$FUZZEL_RES" 821 QALC_RES="$FUZZEL_RES"
675 QALC_RET=0 822 QALC_RET=0
676 else 823 else
677 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1) 824 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
678 QALC_RET=$? 825 QALC_RET=$?
679 fi 826 fi
680 [[ -n "$QALC_RES" ]] || exit 1 827 [[ -n "$QALC_RES" ]] || exit 1
@@ -694,18 +841,33 @@ in {
694 notify-send "$QALC_RES" 841 notify-send "$QALC_RES"
695 ''; 842 '';
696 })); 843 }));
844 "Mod+Shift+U".action =
845 let
846 qalcKitty = pkgs.symlinkJoin {
847 name = "qalc-kitty";
848 paths = [ config.programs.kitty.package ];
849 buildInputs = [ pkgs.makeWrapper ];
850 postBuild = ''
851 wrapProgram $out/bin/kitty \
852 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
853 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
854 shell ${lib.getExe pkgs.libqalculate}
855 ''}"
856 '';
857 };
858 in spawn (lib.getExe' qalcKitty "kitty");
697 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { 859 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
698 name = "emoji-fuzzel"; 860 name = "emoji-fuzzel";
699 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; 861 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
700 text = '' 862 text = ''
701 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $? 863 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
702 [[ -n "$FUZZEL_RES" ]] || exit 1 864 [[ -n "$FUZZEL_RES" ]] || exit 1
703 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste 865 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
704 ''; 866 '';
705 })); 867 }));
706 "Print".action = screenshot; 868 "Print".action = screenshot;
707 "Control+Print".action = screenshot-window; 869 "Control+Print".action = screenshot-window;
708 # "Shift+Print".action = screenshot-screen; 870 "Shift+Print".action = kdl.magic-leaf "screenshot-screen";
709 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 871 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
710 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 872 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
711 873
@@ -759,7 +921,7 @@ in {
759 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid"; 921 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid";
760 922
761 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 923 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
762 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 924 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
763 925
764 "Mod+M".action = consume-or-expel-window-left; 926 "Mod+M".action = consume-or-expel-window-left;
765 "Mod+W".action = consume-or-expel-window-right; 927 "Mod+W".action = consume-or-expel-window-right;
@@ -831,13 +993,20 @@ in {
831 "Mod+Comma".action = spawn makoctl "restore"; 993 "Mod+Comma".action = spawn makoctl "restore";
832 994
833 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 995 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
834 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 996 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
835 997
836 "Mod+X".action = set-dynamic-cast-window; 998 "Mod+X".action = set-dynamic-cast-window;
837 "Mod+Shift+X".action = set-dynamic-cast-monitor; 999 "Mod+Shift+X".action = set-dynamic-cast-monitor;
838 "Mod+Control+Shift+X".action = clear-dynamic-cast-target; 1000 "Mod+Control+Shift+X".action = clear-dynamic-cast-target;
1001
1002 "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
1003 "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}";
1004
1005 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui");
1006 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
839 })) 1007 }))
840 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces) 1008 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces)
1009 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
841 ] 1010 ]
842 )) 1011 ))
843 ]; 1012 ];
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
index 9373dc21..eba26caa 100644
--- a/accounts/gkleen@sif/niri/mako.nix
+++ b/accounts/gkleen@sif/niri/mako.nix
@@ -16,14 +16,16 @@
16 max-icon-size = 48; 16 max-icon-size = 48;
17 }; 17 };
18 criteria = { 18 criteria = {
19 grouped.format = "<b>(%g)</b> <i>%s</i>\n%b"; 19 grouped.format = "<b>(%g)</b> <i>%s</i>\\n%b";
20 "urgency=low".text-color = "#999999ff"; 20 "urgency=low".text-color = "#999999ff";
21 "urgency=critical".background-color = "#900000dd"; 21 "urgency=critical".background-color = "#900000dd";
22 "app-name=Element".group-by = "summary"; 22 "app-name=Element".group-by = "summary";
23 "app-name=poweralertd" = { 23 "app-name=poweralertd" = {
24 history = false;
24 ignore-timeout = true; 25 ignore-timeout = true;
25 default-timeout = 2000; 26 default-timeout = 2000;
26 }; 27 };
28 "app-name=worktime".history = false;
27 "mode=silent".invisible = true; 29 "mode=silent".invisible = true;
28 }; 30 };
29 package = pkgs.symlinkJoin { 31 package = pkgs.symlinkJoin {
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
index 984927c2..54ebb302 100644
--- a/accounts/gkleen@sif/niri/swayosd.nix
+++ b/accounts/gkleen@sif/niri/swayosd.nix
@@ -3,9 +3,10 @@
3 config = { 3 config = {
4 services.swayosd = { 4 services.swayosd = {
5 enable = true; 5 enable = true;
6 topMargin = 0.946154; 6 topMargin = 0.4769706078;
7 stylePath = pkgs.runCommand "style.css" { 7 stylePath = pkgs.runCommand "style.css" {
8 src = pkgs.writeText "style.scss" '' 8 passAsFile = [ "src" ];
9 src = ''
9 window#osd { 10 window#osd {
10 padding: 12px 20px; 11 padding: 12px 20px;
11 border-radius: 999px; 12 border-radius: 999px;
@@ -59,7 +60,7 @@
59 } 60 }
60 ''; 61 '';
61 buildInputs = with pkgs; [sass]; 62 buildInputs = with pkgs; [sass];
62 } "scss -C --sourcemap=none --style=compact $src $out"; 63 } "scss -C --sourcemap=none --style=compact $srcPath $out";
63 }; 64 };
64 }; 65 };
65} 66}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
index cc131c08..c02a9a76 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -27,8 +27,14 @@ in {
27 modules-right = [ "custom/worktime" "custom/worktime-today" 27 modules-right = [ "custom/worktime" "custom/worktime-today"
28 "custom/weather" 28 "custom/weather"
29 "custom/keymap" 29 "custom/keymap"
30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ]; 30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "custom/lid_inhibitor" "clock" ];
31 31
32 "custom/lid_inhibitor" = {
33 format = "{}";
34 return-type = "json";
35 exec = lib.getExe pkgs.waybar-systemd-inhibit;
36 on-click = lib.getExe' pkgs.waybar-systemd-inhibit "waybar-systemd-inhibit-toggle";
37 };
32 "custom/mako" = { 38 "custom/mako" = {
33 format = "{}"; 39 format = "{}";
34 return-type = "json"; 40 return-type = "json";
@@ -211,7 +217,7 @@ in {
211 layer = "top"; 217 layer = "top";
212 position = "top"; 218 position = "top";
213 height = 14; 219 height = 14;
214 output = [ "!eDP-1" "!DP-2" "!DP-3" ]; 220 output = [ "!eDP-1" "!DP-2" "!DP-3" "*" ];
215 modules-left = [ "niri/workspaces" ]; 221 modules-left = [ "niri/workspaces" ];
216 modules-center = [ "niri/window" ]; 222 modules-center = [ "niri/window" ];
217 modules-right = [ "clock" ]; 223 modules-right = [ "clock" ];
@@ -293,7 +299,7 @@ in {
293 #tray { 299 #tray {
294 margin: 0; 300 margin: 0;
295 } 301 }
296 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako { 302 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako, #custom-lid_inhibitor {
297 color: @grey; 303 color: @grey;
298 margin: 0 5px 0 2px; 304 margin: 0 5px 0 2px;
299 } 305 }
@@ -302,7 +308,11 @@ in {
302 margin-left: 6px; 308 margin-left: 6px;
303 } 309 }
304 #custom-mako { 310 #custom-mako {
305 margin-right: 2px; 311 margin-right: 4px;
312 margin-left: 3px;
313 }
314 #custom-lid_inhibitor {
315 margin-right: 3px;
306 margin-left: 3px; 316 margin-left: 3px;
307 } 317 }
308 #battery { 318 #battery {
@@ -330,7 +340,7 @@ in {
330 color: @orange; 340 color: @orange;
331 } 341 }
332 342
333 #idle_inhibitor { 343 #idle_inhibitor, #custom-lid_inhibitor {
334 padding-top: 1px; 344 padding-top: 1px;
335 } 345 }
336 346
@@ -340,6 +350,7 @@ in {
340 } 350 }
341 #clock { 351 #clock {
342 /* margin-right: 5px; */ 352 /* margin-right: 5px; */
353 font-feature-settings: "tnum";
343 } 354 }
344 ''; 355 '';
345 }; 356 };
diff --git a/accounts/gkleen@sif/synadm/default.nix b/accounts/gkleen@sif/synadm/default.nix
new file mode 100644
index 00000000..0a8e0d4c
--- /dev/null
+++ b/accounts/gkleen@sif/synadm/default.nix
@@ -0,0 +1,9 @@
1{ config, pkgs, ... }:
2{
3 home.packages = with pkgs; [ synadm ];
4 sops.secrets."synadm.yaml" = {
5 format = "binary";
6 sopsFile = ./synadm_yaml;
7 path = config.xdg.configHome + "/synadm.yaml";
8 };
9}
diff --git a/accounts/gkleen@sif/synadm/synadm_yaml b/accounts/gkleen@sif/synadm/synadm_yaml
new file mode 100644
index 00000000..8d951ccc
--- /dev/null
+++ b/accounts/gkleen@sif/synadm/synadm_yaml
@@ -0,0 +1,15 @@
1{
2 "data": "ENC[AES256_GCM,data:qJy4Pmbbxja4jmW7OaHsD0mQZ7anZwLhiVmAgkavb+CqwWGDnUBXdz22/MHCbxng5NshcFSpBoCBhgY6B9V2bUiES6bH9AtMlDcs9ebKGMArBTUTnQ2MjWQGfQTqraWdNgy+n327uj9swwCH8EZXdYH/Hlv0t/re470W+VOHeXhGghQ3Y9IGz2sgfvMGr8QxaJNydZz85rgs5QUP/PglCwWIOw2mY1EX2vYwnmiAo49LmIEaxWvRi++KHaeBveDt0nlkJwzUlipL2VOKWxkgpK3yGucQn2mz+FRe1btp+4KGm8H17eUI9FO9sBwq,iv:kgM921ovwCgDYHQj3c5Rupy/8JxHehxUD2jb1k9Ik2Y=,tag:3TLQkJbv679VWy8V2TMugw==,type:str]",
3 "sops": {
4 "age": [
5 {
6 "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866",
7 "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bzVHUGNxZTF2WC9MYmZr\neGdVVzJXN3lGdEk3cTBER3J6UTFtcUJna2d3CjdNQmRXd2haZW1MYlJzNkk1dWVD\nVTFQc2gvS0JrejJ6SFh2MXpPWDZpRE0KLS0tIE0wTC85bEpvSnlGdGFkZVFhNjFZ\nbzRiZkxMWUg2ODNVUlBmNFlPNGRrZlkK1VXLJWcssv3ETyZSSM/Hhn5VIaI9iov9\nzShZA9Zx/FX6PYTuUMC29pJ57gKourcIxa/7HwSv/xYn1A6WcYfgSg==\n-----END AGE ENCRYPTED FILE-----\n"
8 }
9 ],
10 "lastmodified": "2025-05-18T11:03:42Z",
11 "mac": "ENC[AES256_GCM,data:yonJC68PhilAgEHNNJQ8nO53Qo3rx/LnfiOWfuMm24bOUIH9QM3WZZxpigd7bHI4eC4TqRb4LvcSi0nEURTRAhwiTqGNrWbpw2Iv3n5dhLEN9aTcetG5ZuhaXqfVUoML45/ovdBZG/0l8+XIHqxN2M/g/h4JwKoR/6lqzcrVhgo=,iv:xvxBJwy+E5zUdjhGPdZPdy7tnBIEj50hfiDJFsS3wNg=,tag:L4Fas36ZOg4h0QQwC4gjNA==,type:str]",
12 "unencrypted_suffix": "_unencrypted",
13 "version": "3.10.2"
14 }
15}
diff --git a/accounts/gkleen@sif/utils/async-yt-dlp.nix b/accounts/gkleen@sif/utils/async-yt-dlp.nix
new file mode 100644
index 00000000..c3b82ec5
--- /dev/null
+++ b/accounts/gkleen@sif/utils/async-yt-dlp.nix
@@ -0,0 +1,57 @@
1{ writers, python3Packages, ... }:
2
3writers.writePython3Bin "async-yt-dlp" {
4 libraries = with python3Packages; [ yt-dlp ];
5 flakeIgnore = ["E501"];
6} ''
7import sys
8import os
9
10import yt_dlp
11import yt_dlp.options
12from collections import namedtuple
13import socket
14from pathlib import Path
15import json
16
17create_parser = yt_dlp.options.create_parser
18
19
20def parse_patched_options(opts):
21 patched_parser = create_parser()
22 patched_parser.defaults.update({
23 'ignoreerrors': False,
24 'retries': 0,
25 'fragment_retries': 0,
26 'extract_flat': False,
27 'concat_playlist': 'never',
28 })
29 yt_dlp.options.create_parser = lambda: patched_parser
30 try:
31 return yt_dlp.parse_options(opts)
32 finally:
33 yt_dlp.options.create_parser = create_parser
34
35
36default_opts = parse_patched_options([]).ydl_opts
37
38
39def cli_to_api(opts):
40 opts = parse_patched_options(opts)
41 urls = opts.urls
42 opts = opts.ydl_opts
43
44 diff = {k: v for k, v in opts.items() if default_opts[k] != v}
45 if 'postprocessors' in diff:
46 diff['postprocessors'] = [pp for pp in diff['postprocessors']
47 if pp not in default_opts['postprocessors']]
48 return namedtuple('Options', ('params', 'urls'))(diff, urls)
49
50
51if __name__ == '__main__':
52 opts = cli_to_api(sys.argv[1:])
53 with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
54 sock.connect(str(Path(os.environ["XDG_RUNTIME_DIR"]) / "yt-dlp.sock").encode('utf-8'))
55 with sock.makefile(mode='w', buffering=1, encoding='utf-8') as fh:
56 json.dump(opts._asdict(), fh)
57''