python312Packages.publicsuffixlist: 1.0.2.20241207 -> 1.0.2.20241213 (#365192)
[NixPkgs.git] / nixos / modules / services / audio / mpdscribble.nix
blob967853ffc85c06293c9389d601de7b1a3e363244
2   config,
3   lib,
4   options,
5   pkgs,
6   ...
7 }:
8 let
9   cfg = config.services.mpdscribble;
10   mpdCfg = config.services.mpd;
11   mpdOpt = options.services.mpd;
13   endpointUrls = {
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";
18   };
20   mkSection = secname: secCfg: ''
21     [${secname}]
22     url      = ${secCfg.url}
23     username = ${secCfg.username}
24     password = {{${secname}_PASSWORD}}
25     journal  = /var/lib/mpdscribble/${secname}.journal
26   '';
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
36     # HTTP proxy URL.
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).
43     log = -
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
56     # connect to.
57     port = ${toString cfg.port}
59     ${endpoints}
60   '';
62   cfgFile = "/run/mpdscribble/mpdscribble.conf";
64   replaceSecret =
65     secretFile: placeholder: targetFile:
66     lib.optionalString (
67       secretFile != null
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" (
74       lib.mapAttrsToList (
75         secname: cfg: replaceSecret cfg.passwordFile "{{${secname}_PASSWORD}}" cfgFile
76       ) cfg.endpoints
77     )}
78   '';
80   localMpd = (cfg.host == "localhost" || cfg.host == "127.0.0.1");
84   ###### interface
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 {
91       default = null;
92       type = lib.types.nullOr lib.types.str;
93       description = ''
94         HTTP proxy URL.
95       '';
96     };
98     verbose = lib.mkOption {
99       default = 1;
100       type = lib.types.int;
101       description = ''
102         Log level for the mpdscribble daemon.
103       '';
104     };
106     journalInterval = lib.mkOption {
107       default = 600;
108       example = 60;
109       type = lib.types.int;
110       description = ''
111         How often should mpdscribble save the journal file? [seconds]
112       '';
113     };
115     host = lib.mkOption {
116       default = (
117         if mpdCfg.network.listenAddress != "any" then mpdCfg.network.listenAddress else "localhost"
118       );
119       defaultText = lib.literalExpression ''
120         if config.${mpdOpt.network.listenAddress} != "any"
121         then config.${mpdOpt.network.listenAddress}
122         else "localhost"
123       '';
124       type = lib.types.str;
125       description = ''
126         Host for the mpdscribble daemon to search for a mpd daemon on.
127       '';
128     };
130     passwordFile = lib.mkOption {
131       default =
132         if localMpd then
133           (lib.findFirst (c: lib.any (x: x == "read") c.permissions) {
134             passwordFile = null;
135           } mpdCfg.credentials).passwordFile
136         else
137           null;
138       defaultText = lib.literalMD ''
139         The first password file with read access configured for MPD when using a local instance,
140         otherwise `null`.
141       '';
142       type = lib.types.nullOr lib.types.str;
143       description = ''
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.
147       '';
148     };
150     port = lib.mkOption {
151       default = mpdCfg.network.port;
152       defaultText = lib.literalExpression "config.${mpdOpt.network.port}";
153       type = lib.types.port;
154       description = ''
155         Port for the mpdscribble daemon to search for a mpd daemon on.
156       '';
157     };
159     endpoints = lib.mkOption {
160       type = (
161         let
162           endpoint =
163             { name, ... }:
164             {
165               options = {
166                 url = lib.mkOption {
167                   type = lib.types.str;
168                   default = endpointUrls.${name} or "";
169                   description = "The url endpoint where the scrobble API is listening.";
170                 };
171                 username = lib.mkOption {
172                   type = lib.types.str;
173                   description = ''
174                     Username for the scrobble service.
175                   '';
176                 };
177                 passwordFile = lib.mkOption {
178                   type = lib.types.nullOr lib.types.str;
179                   description = "File containing the password, either as MD5SUM or cleartext.";
180                 };
181               };
182             };
183         in
184         lib.types.attrsOf (lib.types.submodule endpoint)
185       );
186       default = { };
187       example = {
188         "last.fm" = {
189           username = "foo";
190           passwordFile = "/run/secrets/lastfm_password";
191         };
192       };
193       description = ''
194         Endpoints to scrobble to.
195         If the endpoint is one of "${lib.concatStringsSep "\", \"" (lib.attrNames endpointUrls)}" the url is set automatically.
196       '';
197     };
199   };
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" ];
208       serviceConfig = {
209         DynamicUser = true;
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}";
216       };
217     };
218   };