1# Module for MiniDLNA, a simple DLNA server.
2{ config, lib, pkgs, ... }:
3
4with lib;
5
6let
7 cfg = config.services.minidlna;
8 port = 8200;
9in
10
11{
12 ###### interface
13 options = {
14 services.minidlna.enable = mkOption {
15 type = types.bool;
16 default = false;
17 description =
18 ''
19 Whether to enable MiniDLNA, a simple DLNA server. It serves
20 media files such as video and music to DLNA client devices
21 such as televisions and media players.
22 '';
23 };
24
25 services.minidlna.mediaDirs = mkOption {
26 type = types.listOf types.str;
27 default = [];
28 example = [ "/data/media" "V,/home/alice/video" ];
29 description =
30 ''
31 Directories to be scanned for media files. The prefixes
32 <literal>A,</literal>, <literal>V,</literal> and
33 <literal>P,</literal> restrict a directory to audio, video
34 or image files. The directories must be accessible to the
35 <literal>minidlna</literal> user account.
36 '';
37 };
38
39 services.minidlna.friendlyName = mkOption {
40 type = types.str;
41 default = "${config.networking.hostName} MiniDLNA";
42 defaultText = "$HOSTNAME MiniDLNA";
43 example = "rpi3";
44 description =
45 ''
46 Name that the DLNA server presents to clients.
47 '';
48 };
49
50 services.minidlna.rootContainer = mkOption {
51 type = types.str;
52 default = ".";
53 example = "B";
54 description =
55 ''
56 Use a different container as the root of the directory tree presented
57 to clients. The possible values are:
58 - "." - standard container
59 - "B" - "Browse Directory"
60 - "M" - "Music"
61 - "P" - "Pictures"
62 - "V" - "Video"
63 - Or, you can specify the ObjectID of your desired root container
64 (eg. 1$F for Music/Playlists)
65 If you specify "B" and the client device is audio-only then
66 "Music/Folders" will be used as root.
67 '';
68 };
69
70 services.minidlna.loglevel = mkOption {
71 type = types.str;
72 default = "warn";
73 example = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn";
74 description =
75 ''
76 Defines the type of messages that should be logged, and down to
77 which level of importance they should be considered.
78
79 The possible types are “artwork”, “database”, “general”, “http”,
80 “inotify”, “metadata”, “scanner”, “ssdp” and “tivo”.
81
82 The levels are “off”, “fatal”, “error”, “warn”, “info” and
83 “debug”, listed here in order of decreasing importance. “off”
84 turns off logging messages entirely, “fatal” logs the most
85 critical messages only, and so on down to “debug” that logs every
86 single messages.
87
88 The types are comma-separated, followed by an equal sign (‘=’),
89 followed by a level that applies to the preceding types. This can
90 be repeated, separating each of these constructs with a comma.
91
92 Defaults to “general,artwork,database,inotify,scanner,metadata,
93 http,ssdp,tivo=warn” which logs every type of message at the
94 “warn” level.
95 '';
96 };
97
98 services.minidlna.announceInterval = mkOption {
99 type = types.int;
100 default = 895;
101 description =
102 ''
103 The interval between announces (in seconds).
104
105 By default miniDLNA will announce its presence on the network
106 approximately every 15 minutes.
107
108 Many people prefer shorter announce intervals (e.g. 60 seconds)
109 on their home networks, especially when DLNA clients are
110 started on demand.
111 '';
112 };
113
114 services.minidlna.config = mkOption {
115 type = types.lines;
116 description =
117 ''
118 The contents of MiniDLNA's configuration file.
119 When the service is activated, a basic template is generated
120 from the current options opened here.
121 '';
122 };
123
124 services.minidlna.extraConfig = mkOption {
125 type = types.lines;
126 default = "";
127 example = ''
128 # Not exhaustive example
129 # Support for streaming .jpg and .mp3 files to a TiVo supporting HMO.
130 enable_tivo=no
131 # SSDP notify interval, in seconds.
132 notify_interval=10
133 # maximum number of simultaneous connections
134 # note: many clients open several simultaneous connections while
135 # streaming
136 max_connections=50
137 # set this to yes to allow symlinks that point outside user-defined
138 # media_dirs.
139 wide_links=yes
140 '';
141 description =
142 ''
143 Extra minidlna options not yet opened for configuration here
144 (strict_dlna, model_number, model_name, etc...). This is appended
145 to the current service already provided.
146 '';
147 };
148 };
149
150 ###### implementation
151 config = mkIf cfg.enable {
152 services.minidlna.config =
153 ''
154 port=${toString port}
155 friendly_name=${cfg.friendlyName}
156 db_dir=/var/cache/minidlna
157 log_level=${cfg.loglevel}
158 inotify=yes
159 root_container=${cfg.rootContainer}
160 ${concatMapStrings (dir: ''
161 media_dir=${dir}
162 '') cfg.mediaDirs}
163 notify_interval=${toString cfg.announceInterval}
164 ${cfg.extraConfig}
165 '';
166
167 users.users.minidlna = {
168 description = "MiniDLNA daemon user";
169 group = "minidlna";
170 uid = config.ids.uids.minidlna;
171 };
172
173 users.groups.minidlna.gid = config.ids.gids.minidlna;
174
175 systemd.services.minidlna =
176 { description = "MiniDLNA Server";
177
178 wantedBy = [ "multi-user.target" ];
179 after = [ "network.target" ];
180
181 serviceConfig =
182 { User = "minidlna";
183 Group = "minidlna";
184 CacheDirectory = "minidlna";
185 RuntimeDirectory = "minidlna";
186 PIDFile = "/run/minidlna/pid";
187 ExecStart =
188 "${pkgs.minidlna}/sbin/minidlnad -S -P /run/minidlna/pid" +
189 " -f ${pkgs.writeText "minidlna.conf" cfg.config}";
190 };
191 };
192 };
193}