at 22.05-pre 6.0 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.mpdscribble; 7 mpdCfg = config.services.mpd; 8 9 endpointUrls = { 10 "last.fm" = "http://post.audioscrobbler.com"; 11 "libre.fm" = "http://turtle.libre.fm"; 12 "jamendo" = "http://postaudioscrobbler.jamendo.com"; 13 "listenbrainz" = "http://proxy.listenbrainz.org"; 14 }; 15 16 mkSection = secname: secCfg: '' 17 [${secname}] 18 url = ${secCfg.url} 19 username = ${secCfg.username} 20 password = {{${secname}_PASSWORD}} 21 journal = /var/lib/mpdscribble/${secname}.journal 22 ''; 23 24 endpoints = concatStringsSep "\n" (mapAttrsToList mkSection cfg.endpoints); 25 cfgTemplate = pkgs.writeText "mpdscribble.conf" '' 26 ## This file was automatically genenrated by NixOS and will be overwritten. 27 ## Do not edit. Edit your NixOS configuration instead. 28 29 ## mpdscribble - an audioscrobbler for the Music Player Daemon. 30 ## http://mpd.wikia.com/wiki/Client:mpdscribble 31 32 # HTTP proxy URL. 33 ${optionalString (cfg.proxy != null) "proxy = ${cfg.proxy}"} 34 35 # The location of the mpdscribble log file. The special value 36 # "syslog" makes mpdscribble use the local syslog daemon. On most 37 # systems, log messages will appear in /var/log/daemon.log then. 38 # "-" means log to stderr (the current terminal). 39 log = - 40 41 # How verbose mpdscribble's logging should be. Default is 1. 42 verbose = ${toString cfg.verbose} 43 44 # How often should mpdscribble save the journal file? [seconds] 45 journal_interval = ${toString cfg.journalInterval} 46 47 # The host running MPD, possibly protected by a password 48 # ([PASSWORD@]HOSTNAME). 49 host = ${(optionalString (cfg.passwordFile != null) "{{MPD_PASSWORD}}@") + cfg.host} 50 51 # The port that the MPD listens on and mpdscribble should try to 52 # connect to. 53 port = ${toString cfg.port} 54 55 ${endpoints} 56 ''; 57 58 cfgFile = "/run/mpdscribble/mpdscribble.conf"; 59 60 replaceSecret = secretFile: placeholder: targetFile: 61 optionalString (secretFile != null) '' 62 ${pkgs.replace-secret}/bin/replace-secret '${placeholder}' '${secretFile}' '${targetFile}' ''; 63 64 preStart = pkgs.writeShellScript "mpdscribble-pre-start" '' 65 cp -f "${cfgTemplate}" "${cfgFile}" 66 ${replaceSecret cfg.passwordFile "{{MPD_PASSWORD}}" cfgFile} 67 ${concatStringsSep "\n" (mapAttrsToList (secname: cfg: 68 replaceSecret cfg.passwordFile "{{${secname}_PASSWORD}}" cfgFile) 69 cfg.endpoints)} 70 ''; 71 72 localMpd = (cfg.host == "localhost" || cfg.host == "127.0.0.1"); 73 74in { 75 ###### interface 76 77 options.services.mpdscribble = { 78 79 enable = mkEnableOption "mpdscribble"; 80 81 proxy = mkOption { 82 default = null; 83 type = types.nullOr types.str; 84 description = '' 85 HTTP proxy URL. 86 ''; 87 }; 88 89 verbose = mkOption { 90 default = 1; 91 type = types.int; 92 description = '' 93 Log level for the mpdscribble daemon. 94 ''; 95 }; 96 97 journalInterval = mkOption { 98 default = 600; 99 example = 60; 100 type = types.int; 101 description = '' 102 How often should mpdscribble save the journal file? [seconds] 103 ''; 104 }; 105 106 host = mkOption { 107 default = (if mpdCfg.network.listenAddress != "any" then 108 mpdCfg.network.listenAddress 109 else 110 "localhost"); 111 type = types.str; 112 description = '' 113 Host for the mpdscribble daemon to search for a mpd daemon on. 114 ''; 115 }; 116 117 passwordFile = mkOption { 118 default = if localMpd then 119 (findFirst 120 (c: any (x: x == "read") c.permissions) 121 { passwordFile = null; } 122 mpdCfg.credentials).passwordFile 123 else 124 null; 125 type = types.nullOr types.str; 126 description = '' 127 File containing the password for the mpd daemon. 128 If there is a local mpd configured using <option>services.mpd.credentials</option> 129 the default is automatically set to a matching passwordFile of the local mpd. 130 ''; 131 }; 132 133 port = mkOption { 134 default = mpdCfg.network.port; 135 type = types.port; 136 description = '' 137 Port for the mpdscribble daemon to search for a mpd daemon on. 138 ''; 139 }; 140 141 endpoints = mkOption { 142 type = (let 143 endpoint = { name, ... }: { 144 options = { 145 url = mkOption { 146 type = types.str; 147 default = endpointUrls.${name} or ""; 148 description = 149 "The url endpoint where the scrobble API is listening."; 150 }; 151 username = mkOption { 152 type = types.str; 153 description = '' 154 Username for the scrobble service. 155 ''; 156 }; 157 passwordFile = mkOption { 158 type = types.nullOr types.str; 159 description = 160 "File containing the password, either as MD5SUM or cleartext."; 161 }; 162 }; 163 }; 164 in types.attrsOf (types.submodule endpoint)); 165 default = { }; 166 example = { 167 "last.fm" = { 168 username = "foo"; 169 passwordFile = "/run/secrets/lastfm_password"; 170 }; 171 }; 172 description = '' 173 Endpoints to scrobble to. 174 If the endpoint is one of "${ 175 concatStringsSep "\", \"" (attrNames endpointUrls) 176 }" the url is set automatically. 177 ''; 178 }; 179 180 }; 181 182 ###### implementation 183 184 config = mkIf cfg.enable { 185 systemd.services.mpdscribble = { 186 after = [ "network.target" ] ++ (optional localMpd "mpd.service"); 187 description = "mpdscribble mpd scrobble client"; 188 wantedBy = [ "multi-user.target" ]; 189 serviceConfig = { 190 DynamicUser = true; 191 StateDirectory = "mpdscribble"; 192 RuntimeDirectory = "mpdscribble"; 193 RuntimeDirectoryMode = "700"; 194 # TODO use LoadCredential= instead of running preStart with full privileges? 195 ExecStartPre = "+${preStart}"; 196 ExecStart = 197 "${pkgs.mpdscribble}/bin/mpdscribble --no-daemon --conf ${cfgFile}"; 198 }; 199 }; 200 }; 201 202}