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.string;
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.int;
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.int;
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 description = ''
97 List of paths to transcoder executables that should be accessible
98 from Subsonic. Symlinks will be created to each executable inside
99 ${cfg.home}/transcoders.
100 '';
101 };
102 };
103 };
104
105 config = mkIf cfg.enable {
106 systemd.services.subsonic = {
107 description = "Personal media streamer";
108 after = [ "local-fs.target" "network.target" ];
109 wantedBy = [ "multi-user.target" ];
110 script = ''
111 ${pkgs.jre}/bin/java -Xmx${toString cfg.maxMemory}m \
112 -Dsubsonic.home=${cfg.home} \
113 -Dsubsonic.host=${cfg.listenAddress} \
114 -Dsubsonic.port=${toString cfg.port} \
115 -Dsubsonic.httpsPort=${toString cfg.httpsPort} \
116 -Dsubsonic.contextPath=${cfg.contextPath} \
117 -Dsubsonic.defaultMusicFolder=${cfg.defaultMusicFolder} \
118 -Dsubsonic.defaultPodcastFolder=${cfg.defaultPodcastFolder} \
119 -Dsubsonic.defaultPlaylistFolder=${cfg.defaultPlaylistFolder} \
120 -Djava.awt.headless=true \
121 -verbose:gc \
122 -jar ${pkgs.subsonic}/subsonic-booter-jar-with-dependencies.jar
123 '';
124
125 preStart = ''
126 # Formerly this module set cfg.home to /var/subsonic. Try to move
127 # /var/subsonic to cfg.home.
128 oldHome="/var/subsonic"
129 if [ "${cfg.home}" != "$oldHome" ] &&
130 ! [ -e "${cfg.home}" ] &&
131 [ -d "$oldHome" ] &&
132 [ $(${pkgs.coreutils}/bin/stat -c %u "$oldHome") -eq \
133 ${toString config.users.extraUsers.subsonic.uid} ]; then
134 logger Moving "$oldHome" to "${cfg.home}"
135 ${pkgs.coreutils}/bin/mv -T "$oldHome" "${cfg.home}"
136 fi
137
138 # Install transcoders.
139 ${pkgs.coreutils}/bin/rm -rf ${cfg.home}/transcode ; \
140 ${pkgs.coreutils}/bin/mkdir -p ${cfg.home}/transcode ; \
141 ${pkgs.bash}/bin/bash -c ' \
142 for exe in "$@"; do \
143 ${pkgs.coreutils}/bin/ln -sf "$exe" ${cfg.home}/transcode; \
144 done' IGNORED_FIRST_ARG ${toString cfg.transcoders}
145 '';
146 serviceConfig = {
147 # Needed for Subsonic to find subsonic.war.
148 WorkingDirectory = "${pkgs.subsonic}";
149 Restart = "always";
150 User = "subsonic";
151 UMask = "0022";
152 };
153 };
154
155 users.extraUsers.subsonic = {
156 description = "Subsonic daemon user";
157 home = cfg.home;
158 createHome = true;
159 group = "subsonic";
160 uid = config.ids.uids.subsonic;
161 };
162
163 users.extraGroups.subsonic.gid = config.ids.gids.subsonic;
164 };
165}