From e896844a06deec40878c5e852ec07f2bc9671379 Mon Sep 17 00:00:00 2001 From: Jonas Rabenstein Date: Sat, 20 Sep 2025 00:17:10 +0200 Subject: [PATCH] package: extend jellyfin with .plugin method --- package/jellyfin.nix | 159 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 package/jellyfin.nix diff --git a/package/jellyfin.nix b/package/jellyfin.nix new file mode 100644 index 0000000..14728a3 --- /dev/null +++ b/package/jellyfin.nix @@ -0,0 +1,159 @@ +{ + lib, + original, + callPackage, + dotnetCorePackages, + fetchFromGitHub, + buildDotnetModule, + gnused, + jprm, + unzip, +}: +let + capitalize = + upper: str: + let + length = builtins.stringLength str; + head = builtins.substring 0 1 str; + tail = builtins.substring 1 length str; + in + "${upper head}${tail}"; + jellyfin = original.overrideAttrs ( + final: prev: + assert !prev ? "plugin"; + { + passthru.plugin = + base: args: + let + meta = from: { inherit (from) license homepage description; }; + + helper = { + inherit base; + name = builtins.baseNameOf info.base; + self = info; + owner = "jellyfin"; + hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + rev = "v${info.version}"; + description = "${info.name} plugin for jellyfin"; + homepage = original.meta.homepage; + license = original.meta.license; + override = + assert false; + null; + overrideAttrs = + assert false; + null; + overrideDerivation = + assert false; + null; + mkPlugin = info: result: buildDotnetModule result; + inherit jellyfin; + }; + + defaults = { + pname = "jellyfin-plugin-${info.name}"; + nugetDeps = + let + options = builtins.filter builtins.pathExists [ + "${info.base}/deps.json" + ]; + in + assert options != [ ]; + builtins.head options; + pluginLibraries = lib.attrsets.foldlAttrs ( + acc: name: value: + acc ++ lib.optional (value == "directory") name + ) [ ] (builtins.readDir ("${info.src}/src")); + dotnet-sdk = dotnetCorePackages.sdk_8_0; + dotnet-runtime = dotnetCorePackages.aspnetcore_8_0; + dontDotnetBuild = true; + dontDotnetInstall = true; + project = "Jellyfin.Plugin.${capitalize lib.strings.toUpper info.name}"; + prePatch = '' + sed --sandbox --separate \ + -e 's:\(PackageReference Include="Jellyfin\..*" Version="\)[^"]\+":\1${info.jellyfin.version}":' \ + -e 's:<\(enerateDocumentationFile\|TreatWarningsAsErrors\)>true:<\1>false:' \ + -i ${ + lib.strings.escapeShellArgs (builtins.map (lib: "src/${lib}/${lib}.csproj") info.pluginLibraries) + } + + success=true + for x in ${ + lib.strings.escapeShellArgs (builtins.map (lib: "src/${lib}/${lib}.csproj") info.pluginLibraries) + } + do + diff -q $src/$x $x 2>/dev/null || continue + printf >&2 'no change: %s\n' $x + success=false + done + $success || exit 1 + ''; + projectFile = "src/${info.project}/${info.project}.csproj"; + src = fetchFromGitHub { + owner = info.owner; + repo = "jellyfin-plugin-${info.name}"; + inherit (info) rev hash; + }; + nativeBuildInputs = [ + gnused + jprm + unzip + ]; + patches = + lib.optional (builtins.pathExists "${info.base}.patch") "${info.base}.patch" + ++ lib.optionals (builtins.pathExists info.base) ( + lib.attrsets.foldlAttrs ( + acc: name: type: + acc + ++ lib.optional (type == "regular" && lib.strings.hasSuffix ".patch" name) "${info.base}/${name}" + ) [ ] (builtins.readDir info.base) + ); + outputs = [ + "out" + "zip" + ]; + postInstall = + let + dlls = builtins.map (name: "${name}.dll") info.pluginLibraries; + in + '' + tmp_output_dir="$(mktemp -d)" + jprm plugin build . --output="''${tmp_output_dir}" --version="${info.version}" --dotnet-configuration="''${dotnetBuildType-Release}" + mv "''${tmp_output_dir}/${info.name}_${info.version}.zip" $zip + mkdir -p $out + unzip $zip -d $out + + success=true + for file in $out/*; + do + case "''${file##*/}" in + meta.json) + ;; + ${builtins.concatStringsSep "|" (builtins.map lib.strings.escapeShellArg dlls)}) ;; + *) + printf 'unknown file: %s\n' ''${file@Q} + success=false + ;; + esac + done + + for file in meta.json ${lib.strings.escapeShellArgs dlls} + do + [[ -f "$out/$file" ]] && continue + printf 'missing file: %s\n' ''${file@Q} + success=false + done + + $success || exit 42 + ''; + meta = meta original.meta // meta info; + }; + + info = helper // defaults // callPackage base ({ inherit info; } // args); + result = lib.attrsets.removeAttrs info (builtins.attrNames helper); + in + info.mkPlugin info result; + } + ); +in +jellyfin