1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.minidlna;
10 format = pkgs.formats.keyValue { listsAsDuplicateKeys = true; };
11 cfgfile = format.generate "minidlna.conf" cfg.settings;
12
13in
14{
15 options.services.minidlna.enable = lib.mkEnableOption "MiniDLNA, a simple DLNA server. Consider adding `openFirewall = true` into your config";
16 options.services.minidlna.openFirewall = lib.mkEnableOption "opening HTTP (TCP) and SSDP (UDP) ports in the firewall";
17 options.services.minidlna.package = lib.mkPackageOption pkgs "minidlna" { };
18
19 options.services.minidlna.settings = lib.mkOption {
20 default = { };
21 description = "Configuration for {manpage}`minidlna.conf(5)`.";
22 type = lib.types.submodule {
23 freeformType = format.type;
24
25 options.media_dir = lib.mkOption {
26 type = lib.types.listOf lib.types.str;
27 default = [ ];
28 example = [
29 "/data/media"
30 "V,/home/alice/video"
31 ];
32 description = ''
33 Directories to be scanned for media files.
34 The `A,` `V,` `P,` prefixes restrict a directory to audio, video or image files.
35 The directories must be accessible to the `minidlna` user account.
36 '';
37 };
38 options.notify_interval = lib.mkOption {
39 type = lib.types.int;
40 default = 90000;
41 description = ''
42 The interval between announces (in seconds).
43 Instead of waiting for announces, you should set `openFirewall` option to use SSDP discovery.
44 Lower values (e.g. 30 seconds) should be used if your network is blocking the SSDP multicast.
45 Some relevant information can be found [here](https://sourceforge.net/p/minidlna/discussion/879957/thread/1389d197/).
46 '';
47 };
48 options.port = lib.mkOption {
49 type = lib.types.port;
50 default = 8200;
51 description = "Port number for HTTP traffic (descriptions, SOAP, media transfer).";
52 };
53 options.db_dir = lib.mkOption {
54 type = lib.types.path;
55 default = "/var/cache/minidlna";
56 example = "/tmp/minidlna";
57 description = "Specify the directory to store database and album art cache.";
58 };
59 options.friendly_name = lib.mkOption {
60 type = lib.types.str;
61 default = config.networking.hostName;
62 defaultText = lib.literalExpression "config.networking.hostName";
63 example = "rpi3";
64 description = "Name that the server presents to clients.";
65 };
66 options.root_container = lib.mkOption {
67 type = lib.types.str;
68 default = "B";
69 example = ".";
70 description = "Use a different container as the root of the directory tree presented to clients.";
71 };
72 options.log_level = lib.mkOption {
73 type = lib.types.str;
74 default = "warn";
75 example = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn";
76 description = "Defines the type of messages that should be logged and down to which level of importance.";
77 };
78 options.enable_subtitles = lib.mkOption {
79 type = lib.types.enum [
80 "yes"
81 "no"
82 ];
83 default = "yes";
84 description = "Enable subtitle support on unknown clients.";
85 };
86 options.inotify = lib.mkOption {
87 type = lib.types.enum [
88 "yes"
89 "no"
90 ];
91 default = "no";
92 description = "Whether to enable inotify monitoring to automatically discover new files.";
93 };
94 options.enable_tivo = lib.mkOption {
95 type = lib.types.enum [
96 "yes"
97 "no"
98 ];
99 default = "no";
100 description = "Support for streaming .jpg and .mp3 files to a TiVo supporting HMO.";
101 };
102 options.wide_links = lib.mkOption {
103 type = lib.types.enum [
104 "yes"
105 "no"
106 ];
107 default = "no";
108 description = "Set this to yes to allow symlinks that point outside user-defined `media_dir`.";
109 };
110 };
111 };
112
113 config = lib.mkIf cfg.enable {
114 networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.settings.port ];
115 networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 1900 ];
116
117 users.groups.minidlna.gid = config.ids.gids.minidlna;
118 users.users.minidlna = {
119 description = "MiniDLNA daemon user";
120 group = "minidlna";
121 uid = config.ids.uids.minidlna;
122 };
123
124 systemd.services.minidlna = {
125 description = "MiniDLNA Server";
126 wantedBy = [ "multi-user.target" ];
127 after = [ "network.target" ];
128
129 serviceConfig = {
130 User = "minidlna";
131 Group = "minidlna";
132 CacheDirectory = "minidlna";
133 RuntimeDirectory = "minidlna";
134 PIDFile = "/run/minidlna/pid";
135 ExecStart = "${lib.getExe cfg.package} -S -P /run/minidlna/pid -f ${cfgfile}";
136 };
137 };
138 };
139}