at 24.11-pre 5.3 kB view raw
1{ config, lib, options, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.airsonic; 7 opt = options.services.airsonic; 8in { 9 options = { 10 11 services.airsonic = { 12 enable = mkEnableOption "Airsonic, the Free and Open Source media streaming server (fork of Subsonic and Libresonic)"; 13 14 user = mkOption { 15 type = types.str; 16 default = "airsonic"; 17 description = "User account under which airsonic runs."; 18 }; 19 20 home = mkOption { 21 type = types.path; 22 default = "/var/lib/airsonic"; 23 description = '' 24 The directory where Airsonic will create files. 25 Make sure it is writable. 26 ''; 27 }; 28 29 virtualHost = mkOption { 30 type = types.nullOr types.str; 31 default = null; 32 description = '' 33 Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost. 34 ''; 35 }; 36 37 listenAddress = mkOption { 38 type = types.str; 39 default = "127.0.0.1"; 40 description = '' 41 The host name or IP address on which to bind Airsonic. 42 The default value is appropriate for first launch, when the 43 default credentials are easy to guess. It is also appropriate 44 if you intend to use the virtualhost option in the service 45 module. In other cases, you may want to change this to a 46 specific IP or 0.0.0.0 to listen on all interfaces. 47 ''; 48 }; 49 50 port = mkOption { 51 type = types.port; 52 default = 4040; 53 description = '' 54 The port on which Airsonic will listen for 55 incoming HTTP traffic. Set to 0 to disable. 56 ''; 57 }; 58 59 contextPath = mkOption { 60 type = types.path; 61 default = "/"; 62 description = '' 63 The context path, i.e., the last part of the Airsonic 64 URL. Typically '/' or '/airsonic'. Default '/' 65 ''; 66 }; 67 68 maxMemory = mkOption { 69 type = types.int; 70 default = 100; 71 description = '' 72 The memory limit (max Java heap size) in megabytes. 73 Default: 100 74 ''; 75 }; 76 77 transcoders = mkOption { 78 type = types.listOf types.path; 79 default = [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ]; 80 defaultText = literalExpression ''[ "''${pkgs.ffmpeg.bin}/bin/ffmpeg" ]''; 81 description = '' 82 List of paths to transcoder executables that should be accessible 83 from Airsonic. Symlinks will be created to each executable inside 84 ''${config.${opt.home}}/transcoders. 85 ''; 86 }; 87 88 jre = mkPackageOption pkgs "jre8" { 89 extraDescription = '' 90 ::: {.note} 91 Airsonic only supports Java 8, airsonic-advanced requires at least 92 Java 11. 93 ::: 94 ''; 95 }; 96 97 war = mkOption { 98 type = types.path; 99 default = "${pkgs.airsonic}/webapps/airsonic.war"; 100 defaultText = literalExpression ''"''${pkgs.airsonic}/webapps/airsonic.war"''; 101 description = "Airsonic war file to use."; 102 }; 103 104 jvmOptions = mkOption { 105 description = '' 106 Extra command line options for the JVM running AirSonic. 107 Useful for sending jukebox output to non-default alsa 108 devices. 109 ''; 110 default = [ 111 ]; 112 type = types.listOf types.str; 113 example = [ 114 "-Djavax.sound.sampled.Clip='#CODEC [plughw:1,0]'" 115 "-Djavax.sound.sampled.Port='#Port CODEC [hw:1]'" 116 "-Djavax.sound.sampled.SourceDataLine='#CODEC [plughw:1,0]'" 117 "-Djavax.sound.sampled.TargetDataLine='#CODEC [plughw:1,0]'" 118 ]; 119 }; 120 121 }; 122 }; 123 124 config = mkIf cfg.enable { 125 systemd.services.airsonic = { 126 description = "Airsonic Media Server"; 127 after = [ "network.target" ]; 128 wantedBy = [ "multi-user.target" ]; 129 130 preStart = '' 131 # Install transcoders. 132 rm -rf ${cfg.home}/transcode 133 mkdir -p ${cfg.home}/transcode 134 for exe in ${toString cfg.transcoders}; do 135 ln -sf "$exe" ${cfg.home}/transcode 136 done 137 ''; 138 serviceConfig = { 139 ExecStart = '' 140 ${cfg.jre}/bin/java -Xmx${toString cfg.maxMemory}m \ 141 -Dairsonic.home=${cfg.home} \ 142 -Dserver.address=${cfg.listenAddress} \ 143 -Dserver.port=${toString cfg.port} \ 144 -Dairsonic.contextPath=${cfg.contextPath} \ 145 -Djava.awt.headless=true \ 146 ${optionalString (cfg.virtualHost != null) 147 "-Dserver.use-forward-headers=true"} \ 148 ${toString cfg.jvmOptions} \ 149 -verbose:gc \ 150 -jar ${cfg.war} 151 ''; 152 Restart = "always"; 153 User = "airsonic"; 154 UMask = "0022"; 155 }; 156 }; 157 158 services.nginx = mkIf (cfg.virtualHost != null) { 159 enable = true; 160 recommendedProxySettings = true; 161 virtualHosts.${cfg.virtualHost} = { 162 locations.${cfg.contextPath}.proxyPass = "http://${cfg.listenAddress}:${toString cfg.port}"; 163 }; 164 }; 165 166 users.users.airsonic = { 167 description = "Airsonic service user"; 168 group = "airsonic"; 169 name = cfg.user; 170 home = cfg.home; 171 createHome = true; 172 isSystemUser = true; 173 }; 174 users.groups.airsonic = {}; 175 }; 176}