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