{ pkgs, config, lib, ... }: let cfg = config.services.jellyfin; plugin = name: pkgs."jellyfin-plugin-${name}"; per-file = pkg: fn: lib.lists.foldl (acc: dll: acc ++ lib.toList (fn dll)) [ ] pkg.pluginLibraries; serviceConfig = pkg: let make-rw = pkgs.writeShellScript "make-rw" '' readonly src="${pkg}/''${1}" readonly dst="${cfg.dataDir}/''${1}" mkdir -p "''${dst%/*}" [[ -f "''${dst}" ]] || cp "''${src}" "''${dst}" ''; in { BindReadOnlyPaths = per-file pkg ( name: "${pkg}/${name}.dll:${cfg.dataDir}/plugins/${pkg.name}/${name}.dll" ); BindPaths = [ "${cfg.dataDir}/plugins/${pkg.name}/meta.json" ]; }; type.plugin = lib.types.addCheck lib.types.package (builtins.hasAttr "pluginLibraries"); in { options.services.jellyfin.plugins = lib.mkOption { type = lib.types.listOf (lib.types.coercedTo lib.types.nonEmptyStr plugin type.plugin); default = [ ]; }; config.systemd = lib.mkIf (cfg.plugins != { }) { services.jellyfin.serviceConfig = let plugins = pkgs.linkFarm "jellyfin-plugins" ( lib.lists.foldl ( acc: plugin: acc ++ per-file (dll: { name = "${plugin.name}/${dll}.dll"; path = plugin + "/${dll}.dll"; }) ) [ ] cfg.plugins ); in { BindReadOnlyPaths = [ "${plugins}:${cfg.dataDir}/plugins" ]; BindPaths = [ "${cfg.dataDir}/plugins/configurations/" ] ++ builtins.map (plugin: "${cfg.dataDir}/pluins/${pkg.name}/meta.json") cfg.plugins; }; tmpfiles.settings = lib.lists.foldl ( acc: pkg: acc // { ${pkg.name}."${cfg.dataDir}/plugins/${pkg.name}/meta.json".C = { group = cfg.group; user = cfg.user; mode = "0700"; argument = "${pkg}/meta.json"; }; } ) { } cfg.plugins; }; }