diff --git a/inventories/default.nix b/inventories/default.nix index 3badb1b..442ea6a 100644 --- a/inventories/default.nix +++ b/inventories/default.nix @@ -180,6 +180,23 @@ ]; }; }; + jukebox = { + module = { + name = "jukebox"; + input = "self"; + }; + roles.default.machines.neptune = { + settings = { + binds = [ + "10.0.0.39" + ]; + disks.m3 = { + uuid = "105D-319E"; + mountOptions = ["utf8"]; + }; + }; + }; + }; }; }; }; diff --git a/modules/clan/jukebox/default.nix b/modules/clan/jukebox/default.nix new file mode 100644 index 0000000..8630d91 --- /dev/null +++ b/modules/clan/jukebox/default.nix @@ -0,0 +1,115 @@ +{ ... }: +{ + _class = "clan.service"; + manifest.name = "jukebox"; + manifest.description = "mpd server, library on removable disks"; + manifest.categories = [ "System" ]; + + roles.default = { + interface = + { lib, ... }: + { + options = { + baseDir = lib.mkOption { + type = lib.types.str; + default = "/mnt/jukebox"; + }; + binds = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + disks = lib.mkOption { + type = with lib.types; attrsOf (submodule ({name, ... }: { + options = { + name = lib.mkOption { + type = str; + default = name; + }; + uuid = lib.mkOption { + type = str; + }; + mountOptions = lib.mkOption { + type = listOf str; + default = []; + }; + }; + })); + default = {}; + description = "disks comprising library"; + }; + }; + }; + perInstance = + { + settings, + ... + }: + { + nixosModule = + { config, lib, pkgs, ... }: + { + services.pulseaudio.enable = true; + + # workaround cookie permissions + services.pulseaudio.tcp.enable = true; + services.pulseaudio.tcp.anonymousClients = { + allowedIpRanges = ["127.0.0.1"]; + allowAll = true; + }; + + systemd.tmpfiles.rules = [ + "d ${settings.baseDir} 0755 root root" + ]; + + fileSystems = let + disk2fs = + { name, uuid, mountOptions, ... }: + lib.nameValuePair "${settings.baseDir}/${name}" { + device = "/dev/disk/by-uuid/${uuid}"; + fsType = "auto"; + options = ["noauto" "nofail"] ++ mountOptions; + }; + in lib.listToAttrs + (lib.mapAttrsToList (_: disk2fs) settings.disks); + + services.udev.extraRules = let + translate-prefix = path: + (lib.removePrefix "-" + (lib.replaceStrings ["/"] ["-"] path)); + mount-name = name: + "${translate-prefix settings.baseDir}-${name}.mount"; + disk2rule = + { name, uuid, ... }: + lib.concatStringsSep ", " [ + ''ACTION=="add"'' + ''SUBSYSTEM=="block"'' + ''ENV{DEVLINKS}=="*/dev/disk/by-uuid/${uuid}*"'' + ''ENV{SYSTEMD_WANTS}="${mount-name name}"'' + ]; + in lib.concatMapStringsSep "\n" disk2rule + (lib.attrValues settings.disks); + + services.mpd = { + enable = true; + musicDirectory = settings.baseDir; + network.listenAddress = "127.0.0.1"; # additive but singleton opt + extraConfig = '' + audio_output { + type "pulse" + name "jukebox" + server "localhost" + } + '' + lib.concatMapStringsSep "\n" + (addr: ''bind_to_address "${addr}"'') + settings.binds; + }; + + networking.firewall.allowedTCPPorts = lib.optional + (settings.binds != []) + config.services.mpd.network.port; + + environment.systemPackages = [pkgs.mpc]; + }; + }; + }; +} diff --git a/modules/clan/jukebox/flake-module.nix b/modules/clan/jukebox/flake-module.nix new file mode 100644 index 0000000..19fb1f9 --- /dev/null +++ b/modules/clan/jukebox/flake-module.nix @@ -0,0 +1,9 @@ +{ lib, ... }: +let + module = lib.modules.importApply ./default.nix { }; +in +{ + clan.modules = { + jukebox = module; + }; +}