{ 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 = lib.mkMerge ( [ { TemporaryFileSystem = [ "${cfg.dataDir}/plugins:ro" ]; } { BindPaths = [ "${cfg.dataDir}/plugins/configurations/" ]; } ] ++ builtins.map serviceConfig 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; }; }