From 544c87716cb912dad3cc9568781470dcde5c64d2 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Sat, 21 Apr 2018 13:07:12 +0200 Subject: Touch up mpd --- custom/mpd.nix | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 custom/mpd.nix (limited to 'custom/mpd.nix') diff --git a/custom/mpd.nix b/custom/mpd.nix new file mode 100644 index 00000000..8df2a955 --- /dev/null +++ b/custom/mpd.nix @@ -0,0 +1,199 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + name = "mpd"; + + uid = config.ids.uids.mpd; + gid = config.ids.gids.mpd; + cfg = config.services.mpd; + + mpdConf = pkgs.writeText "mpd.conf" '' + music_directory "${cfg.musicDirectory}" + playlist_directory "${cfg.playlistDirectory}" + db_file "${cfg.dbFile}" + state_file "${cfg.dataDir}/state" + sticker_file "${cfg.dataDir}/sticker.sql" + log_file "syslog" + user "${cfg.user}" + group "${cfg.group}" + + ${optionalString (cfg.network.listenAddress != "any") ''bind_to_address "${cfg.network.listenAddress}"''} + ${optionalString (cfg.network.port != 6600) ''port "${toString cfg.network.port}"''} + + ${cfg.extraConfig} + ''; + + tcpAddress = { + options = { + address = mkOption { + type = with types; either (enum ["any"]) str; + example = "localhost"; + }; + + port = mkOption { + type = types.int; + default = 6600; + }; + }; + }; + + listenStream = arg: if isString arg then arg else (optionalString (arg.address != "any") (arg.address + ":")) + toString arg.port; + bindAddress = arg: if isString arg then arg + else arg.address + ":" + toString arg.port; + +in { + + disabledModules = [ "services/audio/mpd.nix" ]; + + ###### interface + + options = { + + services.mpd = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable MPD, the music player daemon. + ''; + }; + + startWhenNeeded = mkOption { + type = types.bool; + default = false; + description = '' + If set, mpd is socket-activated; that + is, instead of having it permanently running as a daemon, + systemd will start it on the first incoming connection. + ''; + }; + + musicDirectory = mkOption { + type = with types; either path str; + default = "${cfg.dataDir}/music"; + defaultText = ''''${dataDir}/music''; + description = '' + The directory where mpd reads music from. + ''; + }; + + playlistDirectory = mkOption { + type = types.path; + default = "${cfg.dataDir}/playlists"; + defaultText = ''''${dataDir}/playlists''; + description = '' + The directory where mpd stores playlists. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra directives added to to the end of MPD's configuration file, + mpd.conf. Basic configuration like file location and uid/gid + is added automatically to the beginning of the file. For available + options see man 5 mpd.conf'. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/${name}"; + description = '' + The directory where MPD stores its state, tag cache, + playlists etc. + ''; + }; + + user = mkOption { + type = types.str; + default = name; + description = "User account under which MPD runs."; + }; + + group = mkOption { + type = types.str; + default = name; + description = "Group account under which MPD runs."; + }; + + listenAddresses = mkOption { + type = with types; listOf (either (submodule tcpAddress) str); + default = [{ address = "127.0.0.1"; }]; + }; + + dbFile = mkOption { + type = types.str; + default = "${cfg.dataDir}/tag_cache"; + defaultText = ''''${dataDir}/tag_cache''; + description = '' + The path to MPD's database. + ''; + }; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + systemd.sockets.mpd = mkIf cfg.startWhenNeeded { + description = "Music Player Daemon Socket"; + wantedBy = [ "sockets.target" ]; + listenStreams = map listenStream cfg.listenAddresses; + socketConfig = { + Backlog = 5; + KeepAlive = true; + PassCredentials = true; + }; + }; + + systemd.services.mpd = { + after = [ "network.target" "sound.target" ]; + description = "Music Player Daemon"; + wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; + + preStart = '' + mkdir -p "${cfg.dataDir}" && chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}" + mkdir -p "${cfg.playlistDirectory}" && chown -R ${cfg.user}:${cfg.group} "${cfg.playlistDirectory}" + ''; + serviceConfig = { + User = "${cfg.user}"; + PermissionsStartOnly = true; + ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}"; + Type = "notify"; + LimitRTPRIO = 50; + LimitRTTIME = "infinity"; + ProtectSystem = true; + NoNewPrivileges = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + ProtectKernelModules = true; + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK"; + RestrictNamespaces = true; + }; + }; + + users.extraUsers = optionalAttrs (cfg.user == name) (singleton { + inherit uid; + inherit name; + group = cfg.group; + extraGroups = [ "audio" ]; + description = "Music Player Daemon user"; + home = "${cfg.dataDir}"; + }); + + users.extraGroups = optionalAttrs (cfg.group == name) (singleton { + inherit name; + gid = gid; + }); + }; + +} -- cgit v1.2.3