den
  1{lib, ...}: {
  2  flake.modules.homeManager.desktop = {
  3    config,
  4    pkgs,
  5    ...
  6  }: {
  7    options.programs.deadbeef = let
  8      inherit (lib) mkOption types;
  9
 10      keyValueFormat = pkgs.formats.keyValue {};
 11      JSONFormat = pkgs.formats.json {};
 12
 13      embededJSONType = types.submodule {freeformType = JSONFormat.type;};
 14    in {
 15      enable = lib.mkEnableOption "Enable DeaDBeeF";
 16      package = lib.mkPackageOption pkgs "deadbeef-with-plugins" {};
 17      plugins = mkOption {
 18        type = types.listOf types.package;
 19        default = [];
 20        example = lib.literalExpression ''
 21          with pkgs.deadbeefPlugins; [
 22            mpris2
 23          ];
 24        '';
 25      };
 26      settings = mkOption {
 27        default = {};
 28        example = lib.literalExpression ''
 29          {
 30            "gtkui.start_hidden" = 1;
 31            "hotkey.key1" = "\"space\" 0 0 toggle_pause";
 32          }
 33        '';
 34        type = types.submodule {
 35          freeformType = keyValueFormat.type;
 36          options = {
 37            gtkui.layout = mkOption {
 38              default = {};
 39              description = ''
 40                This option will generate a JSON string into "gtkui.layout.1.9.0" key.
 41              '';
 42              type = embededJSONType;
 43            };
 44            gtkui.columns.playlist = mkOption {
 45              default = [];
 46              description = ''
 47                This option will generate a JSON string into "gtkui.columns.playlist" key.
 48              '';
 49              type = types.listOf embededJSONType;
 50            };
 51            gtkui.columns.search = mkOption {
 52              default = [];
 53              description = ''
 54                This option will generate a JSON string into "gtkui.columns.search" key.
 55              '';
 56              type = types.listOf embededJSONType;
 57            };
 58          };
 59        };
 60      };
 61    };
 62
 63    config = let
 64      cfg = config.programs.deadbeef;
 65    in
 66      lib.mkIf cfg.enable {
 67        assertions = [
 68          {
 69            assertion = pkgs.stdenv.hostPlatform.isLinux;
 70            message = "DeaDBeeF is a Linux software.";
 71          }
 72        ];
 73        home.packages = [(cfg.package.override {plugins = cfg.plugins;})];
 74        systemd.user.services.merge-deadbeef-config = let
 75          deadbeefProcessedConfig =
 76            {
 77              "gtkui.layout.1.9.0" = builtins.toJSON cfg.settings.gtkui.layout;
 78              "gtkui.columns.playlist" = builtins.toJSON cfg.settings.gtkui.columns.playlist;
 79              "gtkui.columns.search" = builtins.toJSON cfg.settings.gtkui.columns.search;
 80            }
 81            // (lib.removeAttrs cfg.settings ["gtkui"]);
 82          deadbeefConfig = with lib.generators;
 83            toKeyValue {mkKeyValue = mkKeyValueDefault {} " ";} deadbeefProcessedConfig;
 84        in {
 85          Unit = {
 86            Description = "Merge Nix-managed DeaDBeeF configuration";
 87            After = ["graphical-session-pre.target"];
 88            PartOf = ["graphical-session.target"];
 89          };
 90          Service = {
 91            Type = "oneshot";
 92            ExecStart = lib.getExe (pkgs.writeShellScriptBin "merge-deadbeef-config" ''
 93              #!${pkgs.runtimeShell}
 94              set -eu
 95
 96              MANAGED_CONFIG_FILE="${pkgs.writeText "deadbeef-managed-config" deadbeefConfig}"
 97
 98              TARGET_CONFIG_FILE="$HOME/.config/deadbeef/config"
 99              mkdir -p "$(dirname "$TARGET_CONFIG_FILE")"
100              touch "$TARGET_CONFIG_FILE"
101
102              ${pkgs.gawk}/bin/awk '
103                NR==FNR { a[$1]=$0; next }
104                {
105                  if ($1 in a) {
106                    print a[$1]
107                    delete a[$1]
108                  } else {
109                    print $0
110                  }
111                }
112                END {
113                  for (k in a) {
114                    print a[k]
115                  }
116                }
117              ' "$MANAGED_CONFIG_FILE" "$TARGET_CONFIG_FILE" > "$TARGET_CONFIG_FILE.tmp" && \
118              mv "$TARGET_CONFIG_FILE.tmp" "$TARGET_CONFIG_FILE"
119              echo "DeaDBeeF config merged successfully."
120            '');
121          };
122          Install = {
123            WantedBy = ["graphical-session.target"];
124          };
125        };
126      };
127  };
128}