at master 6.2 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9 10let 11 cfg = config.services.mirakurun; 12 mirakurun = pkgs.mirakurun; 13 username = config.users.users.mirakurun.name; 14 groupname = config.users.users.mirakurun.group; 15 settingsFmt = pkgs.formats.yaml { }; 16 17 polkitRule = pkgs.writeTextDir "share/polkit-1/rules.d/10-mirakurun.rules" '' 18 polkit.addRule(function (action, subject) { 19 if ( 20 (action.id == "org.debian.pcsc-lite.access_pcsc" || 21 action.id == "org.debian.pcsc-lite.access_card") && 22 subject.user == "${username}" 23 ) { 24 return polkit.Result.YES; 25 } 26 }); 27 ''; 28in 29{ 30 options = { 31 services.mirakurun = { 32 enable = mkEnableOption "the Mirakurun DVR Tuner Server"; 33 34 port = mkOption { 35 type = with types; nullOr port; 36 default = 40772; 37 description = '' 38 Port to listen on. If `null`, it won't listen on 39 any port. 40 ''; 41 }; 42 43 openFirewall = mkOption { 44 type = types.bool; 45 default = false; 46 description = '' 47 Open ports in the firewall for Mirakurun. 48 49 ::: {.warning} 50 Exposing Mirakurun to the open internet is generally advised 51 against. Only use it inside a trusted local network, or 52 consider putting it behind a VPN if you want remote access. 53 ::: 54 ''; 55 }; 56 57 unixSocket = mkOption { 58 type = with types; nullOr path; 59 default = "/var/run/mirakurun/mirakurun.sock"; 60 description = '' 61 Path to unix socket to listen on. If `null`, it 62 won't listen on any unix sockets. 63 ''; 64 }; 65 66 allowSmartCardAccess = mkOption { 67 type = types.bool; 68 default = true; 69 description = '' 70 Install polkit rules to allow Mirakurun to access smart card readers 71 which is commonly used along with tuner devices. 72 ''; 73 }; 74 75 serverSettings = mkOption { 76 type = settingsFmt.type; 77 default = { }; 78 example = literalExpression '' 79 { 80 highWaterMark = 25165824; 81 overflowTimeLimit = 30000; 82 }; 83 ''; 84 description = '' 85 Options for server.yml. 86 87 Documentation: 88 <https://github.com/Chinachu/Mirakurun/blob/master/doc/Configuration.md> 89 ''; 90 }; 91 92 tunerSettings = mkOption { 93 type = with types; nullOr settingsFmt.type; 94 default = null; 95 example = literalExpression '' 96 [ 97 { 98 name = "tuner-name"; 99 types = [ "GR" "BS" "CS" "SKY" ]; 100 dvbDevicePath = "/dev/dvb/adapterX/dvrX"; 101 } 102 ]; 103 ''; 104 description = '' 105 Options which are added to tuners.yml. If none is specified, it will 106 automatically be generated at runtime. 107 108 Documentation: 109 <https://github.com/Chinachu/Mirakurun/blob/master/doc/Configuration.md> 110 ''; 111 }; 112 113 channelSettings = mkOption { 114 type = with types; nullOr settingsFmt.type; 115 default = null; 116 example = literalExpression '' 117 [ 118 { 119 name = "channel"; 120 types = "GR"; 121 channel = "0"; 122 } 123 ]; 124 ''; 125 description = '' 126 Options which are added to channels.yml. If none is specified, it 127 will automatically be generated at runtime. 128 129 Documentation: 130 <https://github.com/Chinachu/Mirakurun/blob/master/doc/Configuration.md> 131 ''; 132 }; 133 }; 134 }; 135 136 config = mkIf cfg.enable { 137 environment.systemPackages = [ mirakurun ] ++ optional cfg.allowSmartCardAccess polkitRule; 138 environment.etc = { 139 "mirakurun/server.yml".source = settingsFmt.generate "server.yml" cfg.serverSettings; 140 "mirakurun/tuners.yml" = mkIf (cfg.tunerSettings != null) { 141 source = settingsFmt.generate "tuners.yml" cfg.tunerSettings; 142 mode = "0644"; 143 user = username; 144 group = groupname; 145 }; 146 "mirakurun/channels.yml" = mkIf (cfg.channelSettings != null) { 147 source = settingsFmt.generate "channels.yml" cfg.channelSettings; 148 mode = "0644"; 149 user = username; 150 group = groupname; 151 }; 152 }; 153 154 networking.firewall = mkIf cfg.openFirewall { 155 allowedTCPPorts = mkIf (cfg.port != null) [ cfg.port ]; 156 }; 157 158 users.users.mirakurun = { 159 description = "Mirakurun user"; 160 group = "video"; 161 isSystemUser = true; 162 163 # NPM insists on creating ~/.npm 164 home = "/var/cache/mirakurun"; 165 }; 166 167 services.mirakurun.serverSettings = { 168 logLevel = mkDefault 2; 169 path = mkIf (cfg.unixSocket != null) cfg.unixSocket; 170 port = mkIf (cfg.port != null) cfg.port; 171 }; 172 173 systemd.tmpfiles.settings."10-mirakurun"."/etc/mirakurun".d = { 174 user = username; 175 group = groupname; 176 }; 177 178 systemd.services.mirakurun = { 179 description = mirakurun.meta.description; 180 wantedBy = [ "multi-user.target" ]; 181 after = [ "network.target" ]; 182 serviceConfig = { 183 ExecStart = "${mirakurun}/bin/mirakurun start"; 184 User = username; 185 Group = groupname; 186 CacheDirectory = "mirakurun"; 187 RuntimeDirectory = "mirakurun"; 188 StateDirectory = "mirakurun"; 189 Nice = -10; 190 IOSchedulingClass = "realtime"; 191 IOSchedulingPriority = 7; 192 }; 193 194 environment = { 195 SERVER_CONFIG_PATH = "/etc/mirakurun/server.yml"; 196 TUNERS_CONFIG_PATH = "/etc/mirakurun/tuners.yml"; 197 CHANNELS_CONFIG_PATH = "/etc/mirakurun/channels.yml"; 198 SERVICES_DB_PATH = "/var/lib/mirakurun/services.json"; 199 PROGRAMS_DB_PATH = "/var/lib/mirakurun/programs.json"; 200 LOGO_DATA_DIR_PATH = "/var/lib/mirakurun/logos"; 201 NODE_ENV = "production"; 202 }; 203 204 restartTriggers = 205 let 206 getconf = target: config.environment.etc."mirakurun/${target}.yml".source; 207 targets = [ 208 "server" 209 ] 210 ++ optional (cfg.tunerSettings != null) "tuners" 211 ++ optional (cfg.channelSettings != null) "channels"; 212 in 213 (map getconf targets); 214 }; 215 }; 216}