From 05cba47810d350efb9c5a704a6e6b4fabd677d7b Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Date: Sun, 13 Jun 2021 15:59:13 -0700 Subject: [PATCH] nixos/hqplayerd: init --- nixos/modules/misc/ids.nix | 2 + nixos/modules/module-list.nix | 3 +- nixos/modules/services/audio/hqplayerd.nix | 166 +++++++++++++++++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 nixos/modules/services/audio/hqplayerd.nix diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 858c7ee53dbb..0ae6b95ba4f8 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -347,6 +347,7 @@ in #mailman = 316; # removed 2019-08-30 zigbee2mqtt = 317; # shadow = 318; # unused + hqplayer = 319; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -649,6 +650,7 @@ in #mailman = 316; # removed 2019-08-30 zigbee2mqtt = 317; shadow = 318; + hqplayer = 319; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index c9aa18e1edf1..30871de95f64 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -243,8 +243,9 @@ ./services/amqp/rabbitmq.nix ./services/audio/alsa.nix ./services/audio/botamusique.nix - ./services/audio/jack.nix + ./services/audio/hqplayerd.nix ./services/audio/icecast.nix + ./services/audio/jack.nix ./services/audio/jmusicbot.nix ./services/audio/liquidsoap.nix ./services/audio/mpd.nix diff --git a/nixos/modules/services/audio/hqplayerd.nix b/nixos/modules/services/audio/hqplayerd.nix new file mode 100644 index 000000000000..3a703c97c0f7 --- /dev/null +++ b/nixos/modules/services/audio/hqplayerd.nix @@ -0,0 +1,166 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.hqplayerd; + pkg = pkgs.hqplayerd; + # XXX: This is hard-coded in the distributed binary, don't try to change it. + stateDir = "/var/lib/hqplayer"; + configDir = "/etc/hqplayer"; +in +{ + options = { + services.hqplayerd = { + enable = mkEnableOption "HQPlayer Embedded"; + + licenseFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to the HQPlayer license key file. + + Without this, the service will run in trial mode and restart every 30 + minutes. + ''; + }; + + auth = { + username = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Username used for HQPlayer's WebUI. + + Without this you will need to manually create the credentials after + first start by going to http://your.ip/8088/auth + ''; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Password used for HQPlayer's WebUI. + + Without this you will need to manually create the credentials after + first start by going to http://your.ip/8088/auth + ''; + }; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open TCP port 8088 in the firewall for the server. + ''; + }; + + user = mkOption { + type = types.str; + default = "hqplayer"; + description = '' + User account under which hqplayerd runs. + ''; + }; + + group = mkOption { + type = types.str; + default = "hqplayer"; + description = '' + Group account under which hqplayerd runs. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { + assertion = (cfg.auth.username != null -> cfg.auth.password != null) + && (cfg.auth.password != null -> cfg.auth.username != null); + message = "You must set either both services.hqplayer.auth.username and password, or neither."; + } + ]; + + environment = { + etc = { + "hqplayer/hqplayerd4-key.xml" = mkIf (cfg.licenseFile != null) { source = cfg.licenseFile; }; + "modules-load.d/taudio2.conf".source = "${pkg}/etc/modules-load.d/taudio2.conf"; + }; + systemPackages = [ pkg ]; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ 8088 ]; + }; + + services.udev.packages = [ pkg ]; + + systemd = { + tmpfiles.rules = [ + "d ${configDir} 0755 ${cfg.user} ${cfg.group} - -" + "d ${stateDir} 0755 ${cfg.user} ${cfg.group} - -" + ]; + + services.hqplayerd = { + description = "HQPlayer daemon"; + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" "sound.target" "systemd-udev-settle.service" ]; + after = [ "network-online.target" "sound.target" "systemd-udev-settle.service" "local-fs.target" "remote-fs.target" "systemd-tmpfiles-setup.service" ]; + + unitConfig.ConditionPathExists = [ configDir stateDir ]; + + preStart = + let + blankCfg = pkgs.writeText "hqplayerd.xml" '' + + + + ''; + in + '' + cp -r "${pkg}/var/lib/hqplayer/web" "${stateDir}" + chmod -R u+wX "${stateDir}/web" + + if [ ! -f "${configDir}/hqplayerd.xml" ]; then + echo "creating blank config file" + install -m 0644 "${blankCfg}" "${configDir}/hqplayerd.xml" + fi + '' + optionalString (cfg.auth.username != null && cfg.auth.password != null) '' + ${pkg}/bin/hqplayerd -s ${cfg.auth.username} ${cfg.auth.password} + ''; + + serviceConfig = { + ExecStart = "${pkg}/bin/hqplayerd"; + + User = cfg.user; + Group = cfg.group; + + Restart = "on-failure"; + RestartSec = 5; + + Nice = -10; + IOSchedulingClass = "realtime"; + LimitMEMLOCK = "1G"; + LimitNICE = -10; + LimitRTPRIO = 98; + }; + }; + }; + + users.groups = mkIf (cfg.group == "hqplayer") { + hqplayer.gid = config.ids.gids.hqplayer; + }; + + users.users = mkIf (cfg.user == "hqplayer") { + hqplayer = { + description = "hqplayer daemon user"; + extraGroups = [ "audio" ]; + group = cfg.group; + uid = config.ids.uids.hqplayer; + }; + }; + }; +}