2014-04-14 16:26:48 +02:00
|
|
|
{
|
|
|
|
config,
|
|
|
|
lib,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
2011-12-05 01:51:05 +00:00
|
|
|
let
|
|
|
|
|
2017-02-16 01:17:44 +01:00
|
|
|
name = "mpd";
|
|
|
|
|
2011-12-05 01:51:05 +00:00
|
|
|
uid = config.ids.uids.mpd;
|
|
|
|
gid = config.ids.gids.mpd;
|
2013-01-27 20:21:04 +01:00
|
|
|
cfg = config.services.mpd;
|
2011-12-05 01:51:05 +00:00
|
|
|
|
2020-12-24 00:04:10 +01:00
|
|
|
credentialsPlaceholder = (
|
|
|
|
creds:
|
|
|
|
let
|
2024-08-30 00:46:36 +02:00
|
|
|
placeholders = (
|
|
|
|
lib.imap0 (
|
|
|
|
i: c: ''password "{{password-${toString i}}}@${lib.concatStringsSep "," c.permissions}"''
|
2020-12-24 00:04:10 +01:00
|
|
|
) creds
|
|
|
|
);
|
|
|
|
in
|
2024-08-30 00:46:36 +02:00
|
|
|
lib.concatStringsSep "\n" placeholders
|
|
|
|
);
|
2020-12-24 00:04:10 +01:00
|
|
|
|
2013-01-27 20:21:04 +01:00
|
|
|
mpdConf = pkgs.writeText "mpd.conf" ''
|
2020-09-10 16:51:28 +03:00
|
|
|
# This file was automatically generated by NixOS. Edit mpd's configuration
|
|
|
|
# via NixOS' configuration.nix, as this file will be rewritten upon mpd's
|
|
|
|
# restart.
|
|
|
|
|
2013-01-27 20:21:04 +01:00
|
|
|
music_directory "${cfg.musicDirectory}"
|
2017-08-20 13:34:34 -07:00
|
|
|
playlist_directory "${cfg.playlistDirectory}"
|
2018-06-01 13:37:43 +02:00
|
|
|
${lib.optionalString (cfg.dbFile != null) ''
|
|
|
|
db_file "${cfg.dbFile}"
|
|
|
|
''}
|
2013-01-27 20:21:04 +01:00
|
|
|
state_file "${cfg.dataDir}/state"
|
|
|
|
sticker_file "${cfg.dataDir}/sticker.sql"
|
2015-03-14 12:08:22 +00:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
${lib.optionalString (
|
|
|
|
cfg.network.listenAddress != "any"
|
|
|
|
) ''bind_to_address "${cfg.network.listenAddress}"''}
|
|
|
|
${lib.optionalString (cfg.network.port != 6600) ''port "${toString cfg.network.port}"''}
|
|
|
|
${lib.optionalString (cfg.fluidsynth) ''
|
2020-05-08 16:38:16 +02:00
|
|
|
decoder {
|
|
|
|
plugin "fluidsynth"
|
|
|
|
soundfont "${pkgs.soundfont-fluid}/share/soundfonts/FluidR3_GM2-2.sf2"
|
|
|
|
}
|
|
|
|
''}
|
2015-03-14 12:08:22 +00:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
${lib.optionalString (cfg.credentials != [ ]) (credentialsPlaceholder cfg.credentials)}
|
2020-12-24 00:04:10 +01:00
|
|
|
|
2013-01-27 20:21:04 +01:00
|
|
|
${cfg.extraConfig}
|
2014-09-15 02:06:57 +04:00
|
|
|
'';
|
2011-12-05 01:51:05 +00:00
|
|
|
|
2013-01-27 20:21:04 +01:00
|
|
|
in
|
|
|
|
{
|
2011-12-05 01:51:05 +00:00
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
2014-09-15 02:06:57 +04:00
|
|
|
options = {
|
2011-12-05 01:51:05 +00:00
|
|
|
|
2014-09-15 02:06:57 +04:00
|
|
|
services.mpd = {
|
2011-12-05 01:51:05 +00:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
enable = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2011-12-05 01:51:05 +00:00
|
|
|
default = false;
|
|
|
|
description = ''
|
2013-01-27 20:21:04 +01:00
|
|
|
Whether to enable MPD, the music player daemon.
|
2014-09-15 02:06:57 +04:00
|
|
|
'';
|
|
|
|
};
|
2013-01-27 20:21:04 +01:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
startWhenNeeded = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2017-06-30 23:51:42 +02:00
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
If set, {command}`mpd` is socket-activated; that
|
|
|
|
is, instead of having it permanently running as a daemon,
|
|
|
|
systemd will start it on the first incoming connection.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
musicDirectory = lib.mkOption {
|
|
|
|
type = with lib.types; either path (strMatching "(http|https|nfs|smb)://.+");
|
2013-01-27 20:21:04 +01:00
|
|
|
default = "${cfg.dataDir}/music";
|
2024-08-30 00:46:36 +02:00
|
|
|
defaultText = lib.literalExpression ''"''${dataDir}/music"'';
|
2013-01-27 20:21:04 +01:00
|
|
|
description = ''
|
2020-11-25 08:14:48 -05:00
|
|
|
The directory or NFS/SMB network share where MPD reads music from. If left
|
|
|
|
as the default value this directory will automatically be created before
|
|
|
|
the MPD server starts, otherwise the sysadmin is responsible for ensuring
|
|
|
|
the directory exists with appropriate ownership and permissions.
|
2014-09-15 02:06:57 +04:00
|
|
|
'';
|
|
|
|
};
|
2013-01-27 20:21:04 +01:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
playlistDirectory = lib.mkOption {
|
|
|
|
type = lib.types.path;
|
2017-08-20 13:34:34 -07:00
|
|
|
default = "${cfg.dataDir}/playlists";
|
2024-08-30 00:46:36 +02:00
|
|
|
defaultText = lib.literalExpression ''"''${dataDir}/playlists"'';
|
2017-08-20 13:34:34 -07:00
|
|
|
description = ''
|
2020-11-25 08:14:48 -05:00
|
|
|
The directory where MPD stores playlists. If left as the default value
|
|
|
|
this directory will automatically be created before the MPD server starts,
|
|
|
|
otherwise the sysadmin is responsible for ensuring the directory exists
|
|
|
|
with appropriate ownership and permissions.
|
2017-08-20 13:34:34 -07:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
extraConfig = lib.mkOption {
|
|
|
|
type = lib.types.lines;
|
2014-09-15 02:06:57 +04:00
|
|
|
default = "";
|
2013-01-27 20:21:04 +01:00
|
|
|
description = ''
|
|
|
|
Extra directives added to to the end of MPD's configuration file,
|
|
|
|
mpd.conf. Basic configuration like file location and uid/gid
|
2017-02-16 01:17:44 +01:00
|
|
|
is added automatically to the beginning of the file. For available
|
2023-01-21 11:06:46 +01:00
|
|
|
options see {manpage}`mpd.conf(5)`.
|
2014-09-15 02:06:57 +04:00
|
|
|
'';
|
|
|
|
};
|
2011-12-05 01:51:05 +00:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
dataDir = lib.mkOption {
|
|
|
|
type = lib.types.path;
|
2017-02-16 01:17:44 +01:00
|
|
|
default = "/var/lib/${name}";
|
2011-12-05 01:51:05 +00:00
|
|
|
description = ''
|
2020-11-25 08:14:48 -05:00
|
|
|
The directory where MPD stores its state, tag cache, playlists etc. If
|
|
|
|
left as the default value this directory will automatically be created
|
|
|
|
before the MPD server starts, otherwise the sysadmin is responsible for
|
|
|
|
ensuring the directory exists with appropriate ownership and permissions.
|
2014-09-15 02:06:57 +04:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
user = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2017-02-16 01:17:44 +01:00
|
|
|
default = name;
|
2015-03-08 10:12:20 +00:00
|
|
|
description = "User account under which MPD runs.";
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
group = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2017-02-16 01:17:44 +01:00
|
|
|
default = name;
|
2015-03-08 10:12:20 +00:00
|
|
|
description = "Group account under which MPD runs.";
|
|
|
|
};
|
|
|
|
|
2014-09-15 02:06:57 +04:00
|
|
|
network = {
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
listenAddress = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2017-01-01 13:46:39 +01:00
|
|
|
default = "127.0.0.1";
|
|
|
|
example = "any";
|
2014-09-15 02:06:57 +04:00
|
|
|
description = ''
|
2017-01-01 13:46:39 +01:00
|
|
|
The address for the daemon to listen on.
|
|
|
|
Use `any` to listen on all addresses.
|
2014-09-15 02:06:57 +04:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
port = lib.mkOption {
|
|
|
|
type = lib.types.port;
|
2014-09-15 02:06:57 +04:00
|
|
|
default = 6600;
|
|
|
|
description = ''
|
|
|
|
This setting is the TCP port that is desired for the daemon to get assigned
|
|
|
|
to.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
2015-04-10 23:10:14 +02:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
dbFile = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.str;
|
2015-04-10 23:10:14 +02:00
|
|
|
default = "${cfg.dataDir}/tag_cache";
|
2024-08-30 00:46:36 +02:00
|
|
|
defaultText = lib.literalExpression ''"''${dataDir}/tag_cache"'';
|
2015-04-10 23:10:14 +02:00
|
|
|
description = ''
|
2018-06-01 13:37:43 +02:00
|
|
|
The path to MPD's database. If set to `null` the
|
2018-06-03 09:55:26 +02:00
|
|
|
parameter is omitted from the configuration.
|
2015-04-10 23:10:14 +02:00
|
|
|
'';
|
|
|
|
};
|
2020-05-08 16:38:16 +02:00
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
credentials = lib.mkOption {
|
|
|
|
type = lib.types.listOf (
|
|
|
|
lib.types.submodule {
|
2020-12-24 00:04:10 +01:00
|
|
|
options = {
|
2024-08-30 00:46:36 +02:00
|
|
|
passwordFile = lib.mkOption {
|
|
|
|
type = lib.types.path;
|
2020-12-24 00:04:10 +01:00
|
|
|
description = ''
|
|
|
|
Path to file containing the password.
|
2025-04-01 20:10:43 +02:00
|
|
|
'';
|
|
|
|
};
|
2020-12-24 00:04:10 +01:00
|
|
|
permissions =
|
2025-04-01 20:10:43 +02:00
|
|
|
let
|
|
|
|
perms = [
|
|
|
|
"read"
|
|
|
|
"add"
|
2020-12-24 00:04:10 +01:00
|
|
|
"control"
|
2025-04-01 20:10:43 +02:00
|
|
|
"admin"
|
|
|
|
];
|
|
|
|
in
|
2024-08-30 00:46:36 +02:00
|
|
|
lib.mkOption {
|
|
|
|
type = lib.types.listOf (lib.types.enum perms);
|
2020-12-24 00:04:10 +01:00
|
|
|
default = [ "read" ];
|
2020-05-08 16:38:16 +02:00
|
|
|
description = ''
|
2020-12-24 00:04:10 +01:00
|
|
|
List of permissions that are granted with this password.
|
2024-08-30 00:46:36 +02:00
|
|
|
Permissions can be "${lib.concatStringsSep "\", \"" perms}".
|
2020-12-24 00:04:10 +01:00
|
|
|
'';
|
2025-04-01 20:10:43 +02:00
|
|
|
};
|
2020-12-24 00:04:10 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
);
|
|
|
|
description = ''
|
|
|
|
Credentials and permissions for accessing the mpd server.
|
|
|
|
'';
|
|
|
|
default = [ ];
|
|
|
|
example = [
|
|
|
|
{
|
|
|
|
passwordFile = "/var/lib/secrets/mpd_readonly_password";
|
|
|
|
permissions = [ "read" ];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
passwordFile = "/var/lib/secrets/mpd_admin_password";
|
|
|
|
permissions = [
|
|
|
|
"read"
|
|
|
|
"add"
|
|
|
|
"control"
|
|
|
|
"admin"
|
|
|
|
];
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
fluidsynth = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2020-05-08 16:38:16 +02:00
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
If set, add fluidsynth soundfont and configure the plugin.
|
|
|
|
'';
|
|
|
|
};
|
2014-09-15 02:06:57 +04:00
|
|
|
};
|
2011-12-05 01:51:05 +00:00
|
|
|
|
2014-09-15 02:06:57 +04:00
|
|
|
};
|
2011-12-05 01:51:05 +00:00
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
config = lib.mkIf cfg.enable {
|
2013-01-27 20:21:04 +01:00
|
|
|
|
2022-01-11 13:07:21 +01:00
|
|
|
# install mpd units
|
|
|
|
systemd.packages = [ pkgs.mpd ];
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
systemd.sockets.mpd = lib.mkIf cfg.startWhenNeeded {
|
2017-06-30 23:51:42 +02:00
|
|
|
wantedBy = [ "sockets.target" ];
|
|
|
|
listenStreams = [
|
2022-06-11 20:46:48 +02:00
|
|
|
"" # Note: this is needed to override the upstream unit
|
2020-03-07 19:34:04 +01:00
|
|
|
(
|
|
|
|
if pkgs.lib.hasPrefix "/" cfg.network.listenAddress then
|
|
|
|
cfg.network.listenAddress
|
2024-08-30 00:46:36 +02:00
|
|
|
else
|
|
|
|
"${
|
|
|
|
lib.optionalString (cfg.network.listenAddress != "any") "${cfg.network.listenAddress}:"
|
|
|
|
}${toString cfg.network.port}"
|
|
|
|
)
|
2017-06-30 23:51:42 +02:00
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2013-01-27 20:21:04 +01:00
|
|
|
systemd.services.mpd = {
|
2024-08-30 00:46:36 +02:00
|
|
|
wantedBy = lib.optional (!cfg.startWhenNeeded) "multi-user.target";
|
2016-09-09 02:49:09 +02:00
|
|
|
|
2022-01-11 13:07:21 +01:00
|
|
|
preStart =
|
|
|
|
''
|
|
|
|
set -euo pipefail
|
|
|
|
install -m 600 ${mpdConf} /run/mpd/mpd.conf
|
2024-08-30 00:46:36 +02:00
|
|
|
''
|
|
|
|
+ lib.optionalString (cfg.credentials != [ ]) (
|
|
|
|
lib.concatStringsSep "\n" (
|
|
|
|
lib.imap0 (
|
2022-01-11 13:07:21 +01:00
|
|
|
i: c:
|
|
|
|
''${pkgs.replace-secret}/bin/replace-secret '{{password-${toString i}}}' '${c.passwordFile}' /run/mpd/mpd.conf''
|
|
|
|
) cfg.credentials
|
2025-04-01 20:10:43 +02:00
|
|
|
)
|
2022-01-11 13:07:21 +01:00
|
|
|
);
|
2025-04-01 20:10:43 +02:00
|
|
|
|
2022-01-11 13:07:21 +01:00
|
|
|
serviceConfig = {
|
2020-11-25 08:14:48 -05:00
|
|
|
User = "${cfg.user}";
|
2022-01-11 13:07:21 +01:00
|
|
|
# Note: the first "" overrides the ExecStart from the upstream unit
|
|
|
|
ExecStart = [
|
|
|
|
""
|
|
|
|
"${pkgs.mpd}/bin/mpd --systemd /run/mpd/mpd.conf"
|
|
|
|
];
|
2020-12-24 00:04:10 +01:00
|
|
|
RuntimeDirectory = "mpd";
|
2022-01-11 13:07:21 +01:00
|
|
|
StateDirectory =
|
|
|
|
[ ]
|
2024-08-30 00:46:36 +02:00
|
|
|
++ lib.optionals (cfg.dataDir == "/var/lib/${name}") [ name ]
|
|
|
|
++ lib.optionals (cfg.playlistDirectory == "/var/lib/${name}/playlists") [
|
|
|
|
name
|
|
|
|
"${name}/playlists"
|
|
|
|
]
|
|
|
|
++ lib.optionals (cfg.musicDirectory == "/var/lib/${name}/music") [
|
|
|
|
name
|
|
|
|
"${name}/music"
|
|
|
|
];
|
2022-01-11 13:07:21 +01:00
|
|
|
};
|
2013-01-27 20:21:04 +01:00
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
users.users = lib.optionalAttrs (cfg.user == name) {
|
2019-09-14 19:51:29 +02:00
|
|
|
${name} = {
|
|
|
|
inherit uid;
|
|
|
|
group = cfg.group;
|
|
|
|
extraGroups = [ "audio" ];
|
|
|
|
description = "Music Player Daemon user";
|
|
|
|
home = "${cfg.dataDir}";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-08-30 00:46:36 +02:00
|
|
|
users.groups = lib.optionalAttrs (cfg.group == name) {
|
2019-09-14 19:51:29 +02:00
|
|
|
${name}.gid = gid;
|
|
|
|
};
|
2011-12-05 01:51:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|