1 { config, lib, pkgs, ... }:
6 cfg = config.services.mirakurun;
7 mirakurun = pkgs.mirakurun;
8 username = config.users.users.mirakurun.name;
9 groupname = config.users.users.mirakurun.group;
10 settingsFmt = pkgs.formats.yaml {};
12 polkitRule = pkgs.writeTextDir "share/polkit-1/rules.d/10-mirakurun.rules" ''
13 polkit.addRule(function (action, subject) {
15 (action.id == "org.debian.pcsc-lite.access_pcsc" ||
16 action.id == "org.debian.pcsc-lite.access_card") &&
17 subject.user == "${username}"
19 return polkit.Result.YES;
26 services.mirakurun = {
27 enable = mkEnableOption "the Mirakurun DVR Tuner Server";
30 type = with types; nullOr port;
33 Port to listen on. If `null`, it won't listen on
38 openFirewall = mkOption {
42 Open ports in the firewall for Mirakurun.
45 Exposing Mirakurun to the open internet is generally advised
46 against. Only use it inside a trusted local network, or
47 consider putting it behind a VPN if you want remote access.
52 unixSocket = mkOption {
53 type = with types; nullOr path;
54 default = "/var/run/mirakurun/mirakurun.sock";
56 Path to unix socket to listen on. If `null`, it
57 won't listen on any unix sockets.
61 allowSmartCardAccess = mkOption {
65 Install polkit rules to allow Mirakurun to access smart card readers
66 which is commonly used along with tuner devices.
70 serverSettings = mkOption {
71 type = settingsFmt.type;
73 example = literalExpression ''
75 highWaterMark = 25165824;
76 overflowTimeLimit = 30000;
80 Options for server.yml.
83 <https://github.com/Chinachu/Mirakurun/blob/master/doc/Configuration.md>
87 tunerSettings = mkOption {
88 type = with types; nullOr settingsFmt.type;
90 example = literalExpression ''
94 types = [ "GR" "BS" "CS" "SKY" ];
95 dvbDevicePath = "/dev/dvb/adapterX/dvrX";
100 Options which are added to tuners.yml. If none is specified, it will
101 automatically be generated at runtime.
104 <https://github.com/Chinachu/Mirakurun/blob/master/doc/Configuration.md>
108 channelSettings = mkOption {
109 type = with types; nullOr settingsFmt.type;
111 example = literalExpression ''
121 Options which are added to channels.yml. If none is specified, it
122 will automatically be generated at runtime.
125 <https://github.com/Chinachu/Mirakurun/blob/master/doc/Configuration.md>
131 config = mkIf cfg.enable {
132 environment.systemPackages = [ mirakurun ] ++ optional cfg.allowSmartCardAccess polkitRule;
134 "mirakurun/server.yml".source = settingsFmt.generate "server.yml" cfg.serverSettings;
135 "mirakurun/tuners.yml" = mkIf (cfg.tunerSettings != null) {
136 source = settingsFmt.generate "tuners.yml" cfg.tunerSettings;
141 "mirakurun/channels.yml" = mkIf (cfg.channelSettings != null) {
142 source = settingsFmt.generate "channels.yml" cfg.channelSettings;
149 networking.firewall = mkIf cfg.openFirewall {
150 allowedTCPPorts = mkIf (cfg.port != null) [ cfg.port ];
153 users.users.mirakurun = {
154 description = "Mirakurun user";
158 # NPM insists on creating ~/.npm
159 home = "/var/cache/mirakurun";
162 services.mirakurun.serverSettings = {
163 logLevel = mkDefault 2;
164 path = mkIf (cfg.unixSocket != null) cfg.unixSocket;
165 port = mkIf (cfg.port != null) cfg.port;
168 systemd.tmpfiles.settings."10-mirakurun"."/etc/mirakurun".d = {
173 systemd.services.mirakurun = {
174 description = mirakurun.meta.description;
175 wantedBy = [ "multi-user.target" ];
176 after = [ "network.target" ];
178 ExecStart = "${mirakurun}/bin/mirakurun start";
181 CacheDirectory = "mirakurun";
182 RuntimeDirectory="mirakurun";
183 StateDirectory="mirakurun";
185 IOSchedulingClass = "realtime";
186 IOSchedulingPriority = 7;
190 SERVER_CONFIG_PATH = "/etc/mirakurun/server.yml";
191 TUNERS_CONFIG_PATH = "/etc/mirakurun/tuners.yml";
192 CHANNELS_CONFIG_PATH = "/etc/mirakurun/channels.yml";
193 SERVICES_DB_PATH = "/var/lib/mirakurun/services.json";
194 PROGRAMS_DB_PATH = "/var/lib/mirakurun/programs.json";
195 LOGO_DATA_DIR_PATH = "/var/lib/mirakurun/logos";
196 NODE_ENV = "production";
199 restartTriggers = let
200 getconf = target: config.environment.etc."mirakurun/${target}.yml".source;
203 ] ++ optional (cfg.tunerSettings != null) "tuners"
204 ++ optional (cfg.channelSettings != null) "channels";
205 in (map getconf targets);