1{
2 config,
3 lib,
4 options,
5 pkgs,
6 ...
7}:
8let
9 cfg = config.services.subsonic;
10 opt = options.services.subsonic;
11in
12{
13 options = {
14 services.subsonic = {
15 enable = lib.mkEnableOption "Subsonic daemon";
16
17 home = lib.mkOption {
18 type = lib.types.path;
19 default = "/var/lib/subsonic";
20 description = ''
21 The directory where Subsonic will create files.
22 Make sure it is writable.
23 '';
24 };
25
26 listenAddress = lib.mkOption {
27 type = lib.types.str;
28 default = "0.0.0.0";
29 description = ''
30 The host name or IP address on which to bind Subsonic.
31 Only relevant if you have multiple network interfaces and want
32 to make Subsonic available on only one of them. The default value
33 will bind Subsonic to all available network interfaces.
34 '';
35 };
36
37 port = lib.mkOption {
38 type = lib.types.port;
39 default = 4040;
40 description = ''
41 The port on which Subsonic will listen for
42 incoming HTTP traffic. Set to 0 to disable.
43 '';
44 };
45
46 httpsPort = lib.mkOption {
47 type = lib.types.port;
48 default = 0;
49 description = ''
50 The port on which Subsonic will listen for
51 incoming HTTPS traffic. Set to 0 to disable.
52 '';
53 };
54
55 contextPath = lib.mkOption {
56 type = lib.types.path;
57 default = "/";
58 description = ''
59 The context path, i.e., the last part of the Subsonic
60 URL. Typically '/' or '/subsonic'. Default '/'
61 '';
62 };
63
64 maxMemory = lib.mkOption {
65 type = lib.types.int;
66 default = 100;
67 description = ''
68 The memory limit (max Java heap size) in megabytes.
69 Default: 100
70 '';
71 };
72
73 defaultMusicFolder = lib.mkOption {
74 type = lib.types.path;
75 default = "/var/music";
76 description = ''
77 Configure Subsonic to use this folder for music. This option
78 only has effect the first time Subsonic is started.
79 '';
80 };
81
82 defaultPodcastFolder = lib.mkOption {
83 type = lib.types.path;
84 default = "/var/music/Podcast";
85 description = ''
86 Configure Subsonic to use this folder for Podcasts. This option
87 only has effect the first time Subsonic is started.
88 '';
89 };
90
91 defaultPlaylistFolder = lib.mkOption {
92 type = lib.types.path;
93 default = "/var/playlists";
94 description = ''
95 Configure Subsonic to use this folder for playlists. This option
96 only has effect the first time Subsonic is started.
97 '';
98 };
99
100 transcoders = lib.mkOption {
101 type = lib.types.listOf lib.types.path;
102 default = [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ];
103 defaultText = lib.literalExpression ''[ "''${pkgs.ffmpeg.bin}/bin/ffmpeg" ]'';
104 description = ''
105 List of paths to transcoder executables that should be accessible
106 from Subsonic. Symlinks will be created to each executable inside
107 ''${config.${opt.home}}/transcoders.
108 '';
109 };
110 };
111 };
112
113 config = lib.mkIf cfg.enable {
114 systemd.services.subsonic = {
115 description = "Personal media streamer";
116 after = [ "network.target" ];
117 wantedBy = [ "multi-user.target" ];
118 script = ''
119 ${pkgs.jre8}/bin/java -Xmx${toString cfg.maxMemory}m \
120 -Dsubsonic.home=${cfg.home} \
121 -Dsubsonic.host=${cfg.listenAddress} \
122 -Dsubsonic.port=${toString cfg.port} \
123 -Dsubsonic.httpsPort=${toString cfg.httpsPort} \
124 -Dsubsonic.contextPath=${cfg.contextPath} \
125 -Dsubsonic.defaultMusicFolder=${cfg.defaultMusicFolder} \
126 -Dsubsonic.defaultPodcastFolder=${cfg.defaultPodcastFolder} \
127 -Dsubsonic.defaultPlaylistFolder=${cfg.defaultPlaylistFolder} \
128 -Djava.awt.headless=true \
129 -verbose:gc \
130 -jar ${pkgs.subsonic}/subsonic-booter-jar-with-dependencies.jar
131 '';
132
133 preStart = ''
134 # Formerly this module set cfg.home to /var/subsonic. Try to move
135 # /var/subsonic to cfg.home.
136 oldHome="/var/subsonic"
137 if [ "${cfg.home}" != "$oldHome" ] &&
138 ! [ -e "${cfg.home}" ] &&
139 [ -d "$oldHome" ] &&
140 [ $(${pkgs.coreutils}/bin/stat -c %u "$oldHome") -eq \
141 ${toString config.users.users.subsonic.uid} ]; then
142 logger Moving "$oldHome" to "${cfg.home}"
143 ${pkgs.coreutils}/bin/mv -T "$oldHome" "${cfg.home}"
144 fi
145
146 # Install transcoders.
147 ${pkgs.coreutils}/bin/rm -rf ${cfg.home}/transcode ; \
148 ${pkgs.coreutils}/bin/mkdir -p ${cfg.home}/transcode ; \
149 ${pkgs.bash}/bin/bash -c ' \
150 for exe in "$@"; do \
151 ${pkgs.coreutils}/bin/ln -sf "$exe" ${cfg.home}/transcode; \
152 done' IGNORED_FIRST_ARG ${toString cfg.transcoders}
153 '';
154 serviceConfig = {
155 # Needed for Subsonic to find subsonic.war.
156 WorkingDirectory = "${pkgs.subsonic}";
157 Restart = "always";
158 User = "subsonic";
159 UMask = "0022";
160 };
161 };
162
163 users.users.subsonic = {
164 description = "Subsonic daemon user";
165 home = cfg.home;
166 createHome = true;
167 group = "subsonic";
168 uid = config.ids.uids.subsonic;
169 };
170
171 users.groups.subsonic.gid = config.ids.gids.subsonic;
172 };
173}