{ config, lib, pkgs, ... }: with lib; let cfg = config.services.motion; cameraConfig = { options = { configFiles = mkOption { type = types.listOf types.path; default = []; description = "Config files to append to camera config"; }; extraConfig = mkOption { type = types.lines; default = ""; description = "Config to append verbatim"; }; }; }; cameraConfig' = cameraId: cCfg: pkgs.writeText "${toString cameraId}.conf" '' camera_id ${toString cameraId} ${cCfg.extraConfig} ''; compileCamera = cameraId: cCfg: '' cat ${cameraConfig' cameraId cCfg} ${escapeShellArgs cCfg.configFiles} > cameras/${toString cameraId}.conf ''; motionConfig = pkgs.writeText "motion.conf" '' ${cfg.extraConfig} camera_dir cameras ''; preStart = pkgs.writeScript "motion-pre-start" '' #!${pkgs.stdenv.shell} cat ${motionConfig} ${escapeShellArgs cfg.configFiles} > motion.conf mkdir -p cameras ${concatStringsSep "\n" (imap0 compileCamera cfg.cameras)} chown -R ${cfg.user.name} . chmod -R u+rX . ''; in { options = { services.motion = { cameras = mkOption{ type = types.listOf (types.submodule cameraConfig); default = []; }; extraConfig = mkOption { type = types.lines; default = ""; description = "Config to append verbatim"; }; configFiles = mkOption { type = types.listOf types.path; default = []; description = "Config files to append to service config"; }; user = { name = mkOption { type = types.str; default = "motion"; description = "Name of the dedicated user"; }; overrides = mkOption { type = types.attrs; default = {}; }; }; }; }; config = mkIf (cfg.cameras != []) { users.users."${cfg.user.name}" = { name = cfg.user.name; isSystemUser = true; isNormalUser = false; description = "User for motion daemon"; } // cfg.user.overrides; systemd.services."motion" = { serviceConfig = { User = cfg.user.name; RuntimeDirectory = [ "motion" ]; RuntimeDirectoryMode = "0700"; WorkingDirectory = "/run/motion"; ExecStart = "${pkgs.motion}/bin/motion -n -c motion.conf"; ExecStartPre = "+${preStart}"; }; wantedBy = [ "multi-user.target" ]; }; }; }