9 cfg = config.services.mpdscribble;
10 mpdCfg = config.services.mpd;
11 mpdOpt = options.services.mpd;
14 "last.fm" = "http://post.audioscrobbler.com";
15 "libre.fm" = "http://turtle.libre.fm";
16 "jamendo" = "http://postaudioscrobbler.jamendo.com";
17 "listenbrainz" = "http://proxy.listenbrainz.org";
20 mkSection = secname: secCfg: ''
23 username = ${secCfg.username}
24 password = {{${secname}_PASSWORD}}
25 journal = /var/lib/mpdscribble/${secname}.journal
28 endpoints = lib.concatStringsSep "\n" (lib.mapAttrsToList mkSection cfg.endpoints);
29 cfgTemplate = pkgs.writeText "mpdscribble.conf" ''
30 ## This file was automatically genenrated by NixOS and will be overwritten.
31 ## Do not edit. Edit your NixOS configuration instead.
33 ## mpdscribble - an audioscrobbler for the Music Player Daemon.
34 ## http://mpd.wikia.com/wiki/Client:mpdscribble
37 ${lib.optionalString (cfg.proxy != null) "proxy = ${cfg.proxy}"}
39 # The location of the mpdscribble log file. The special value
40 # "syslog" makes mpdscribble use the local syslog daemon. On most
41 # systems, log messages will appear in /var/log/daemon.log then.
42 # "-" means log to stderr (the current terminal).
45 # How verbose mpdscribble's logging should be. Default is 1.
46 verbose = ${toString cfg.verbose}
48 # How often should mpdscribble save the journal file? [seconds]
49 journal_interval = ${toString cfg.journalInterval}
51 # The host running MPD, possibly protected by a password
52 # ([PASSWORD@]HOSTNAME).
53 host = ${(lib.optionalString (cfg.passwordFile != null) "{{MPD_PASSWORD}}@") + cfg.host}
55 # The port that the MPD listens on and mpdscribble should try to
57 port = ${toString cfg.port}
62 cfgFile = "/run/mpdscribble/mpdscribble.conf";
65 secretFile: placeholder: targetFile:
68 ) ''${pkgs.replace-secret}/bin/replace-secret '${placeholder}' '${secretFile}' '${targetFile}' '';
70 preStart = pkgs.writeShellScript "mpdscribble-pre-start" ''
71 cp -f "${cfgTemplate}" "${cfgFile}"
72 ${replaceSecret cfg.passwordFile "{{MPD_PASSWORD}}" cfgFile}
73 ${lib.concatStringsSep "\n" (
75 secname: cfg: replaceSecret cfg.passwordFile "{{${secname}_PASSWORD}}" cfgFile
80 localMpd = (cfg.host == "localhost" || cfg.host == "127.0.0.1");
86 options.services.mpdscribble = {
88 enable = lib.mkEnableOption "mpdscribble, an MPD client which submits info about tracks being played to Last.fm (formerly AudioScrobbler)";
90 proxy = lib.mkOption {
92 type = lib.types.nullOr lib.types.str;
98 verbose = lib.mkOption {
100 type = lib.types.int;
102 Log level for the mpdscribble daemon.
106 journalInterval = lib.mkOption {
109 type = lib.types.int;
111 How often should mpdscribble save the journal file? [seconds]
115 host = lib.mkOption {
117 if mpdCfg.network.listenAddress != "any" then mpdCfg.network.listenAddress else "localhost"
119 defaultText = lib.literalExpression ''
120 if config.${mpdOpt.network.listenAddress} != "any"
121 then config.${mpdOpt.network.listenAddress}
124 type = lib.types.str;
126 Host for the mpdscribble daemon to search for a mpd daemon on.
130 passwordFile = lib.mkOption {
133 (lib.findFirst (c: lib.any (x: x == "read") c.permissions) {
135 } mpdCfg.credentials).passwordFile
138 defaultText = lib.literalMD ''
139 The first password file with read access configured for MPD when using a local instance,
142 type = lib.types.nullOr lib.types.str;
144 File containing the password for the mpd daemon.
145 If there is a local mpd configured using {option}`services.mpd.credentials`
146 the default is automatically set to a matching passwordFile of the local mpd.
150 port = lib.mkOption {
151 default = mpdCfg.network.port;
152 defaultText = lib.literalExpression "config.${mpdOpt.network.port}";
153 type = lib.types.port;
155 Port for the mpdscribble daemon to search for a mpd daemon on.
159 endpoints = lib.mkOption {
167 type = lib.types.str;
168 default = endpointUrls.${name} or "";
169 description = "The url endpoint where the scrobble API is listening.";
171 username = lib.mkOption {
172 type = lib.types.str;
174 Username for the scrobble service.
177 passwordFile = lib.mkOption {
178 type = lib.types.nullOr lib.types.str;
179 description = "File containing the password, either as MD5SUM or cleartext.";
184 lib.types.attrsOf (lib.types.submodule endpoint)
190 passwordFile = "/run/secrets/lastfm_password";
194 Endpoints to scrobble to.
195 If the endpoint is one of "${lib.concatStringsSep "\", \"" (lib.attrNames endpointUrls)}" the url is set automatically.
201 ###### implementation
203 config = lib.mkIf cfg.enable {
204 systemd.services.mpdscribble = {
205 after = [ "network.target" ] ++ (lib.optional localMpd "mpd.service");
206 description = "mpdscribble mpd scrobble client";
207 wantedBy = [ "multi-user.target" ];
210 StateDirectory = "mpdscribble";
211 RuntimeDirectory = "mpdscribble";
212 RuntimeDirectoryMode = "700";
213 # TODO use LoadCredential= instead of running preStart with full privileges?
214 ExecStartPre = "+${preStart}";
215 ExecStart = "${pkgs.mpdscribble}/bin/mpdscribble --no-daemon --conf ${cfgFile}";