buildNavidromePlugin: refactor and rename to buildNavidromeGoPlugin

Co-authored-by: Ross Smyth <18294397+RossSmyth@users.noreply.github.com>
This commit is contained in:
Chris Moultrie
2026-07-28 18:00:07 -04:00
parent c1ce6ad8be
commit 511eba4038
15 changed files with 167 additions and 95 deletions

View File

@@ -274,6 +274,10 @@
- `typescript` 7.0.2 now uses the Golang implementation. The [announcement document](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/) has information on what was changed.
- `navidrome`'s plugin infrastructure has significantly changed. `buildNavidromePlugin` is renamed to `buildNavidromeGoPlugin` to allow for other language types. Plugins must now be sourced from `pkgsCross.wasi32.navidromePlugins.<name>`.
- `navidromePlugins.apple-music` now uses a `bundleName` attribute which sets the plugin's name to match the plugin's documentation for easier use. You will need to update your Agent from `apple-music-plugin` to `apple-music` as noted in [their docs](https://github.com/navidrome/apple-music-plugin#installation).
### Deprecations {#sec-nixpkgs-release-26.11-lib-deprecations}
- Setting `config.allowBrokenPredicate` is deprecated in favor of

View File

@@ -45,7 +45,7 @@ in
default = [ ];
description = "List of Navidrome plugins";
example = literalExpression ''
with pkgs.navidromePlugins; [
with pkgs.pkgsCross.wasi32.navidromePlugins; [
listenbrainz-daily-playlist
];
'';

View File

@@ -1,15 +1,21 @@
{ pkgs, ... }:
{ ... }:
{
name = "navidrome";
nodes.machine =
{ ... }:
{ pkgs, ... }:
{
services.navidrome = {
enable = true;
plugins = with pkgs.navidromePlugins; [
plugins = with pkgs.pkgsCross.wasi32.navidromePlugins; [
listenbrainz-daily-playlist
# uses bundleName instead of pname
apple-music
];
settings = {
# Disables all external network connections
EnableExternalServices = "false";
};
};
};

View File

@@ -82,7 +82,10 @@ buildGo127Module (finalAttrs: {
postInstall = ''
mkdir -p $out/share/plugins/
${lib.concatMapStringsSep "\n" (plugin: ''
ln -s ${plugin}/share/${plugin.pname}.ndp $out/share/plugins/
find ${plugin}/share/ \
-type f \
-name "*.ndp" \
-exec ln -s {} $out/share/plugins/${plugin.bundleName or plugin.pname}.ndp \;
'') plugins}
'';

View File

@@ -6,3 +6,21 @@ Each navidrome plugin is a `.zip` file named `${pname}.ndp`. Inside this zip is
two files named exactly:
- `manifest.json` which defines permissions and configuration
- `plugin.wasm` which is the output of the plugin build
## Builders
The builders all currently have their platforms set to `wasi` and are
accessed/built through `pkgs.pkgsCross.wasi32.navidromePlugins.<name>`. This is
the most efficient way to cross-compile the plugins under wasip1-wasm.
### `bundleName`
This property allows you to specify the name of the ndp file that is symlinked
within Navidrome. Navidrome keys off of the file name for plugins and the output
name may differ from the documentation, so we allow setting `bundleName` which
makes the documentation of a particular plugin easier to follow.
### `buildNavidromeGoPlugin`
This builder uses the standard `buildGoModule` under the hood (from within the
wasi arch's `callPackage`).

View File

@@ -1,26 +1,28 @@
{
lib,
pkgs,
buildNavidromePlugin,
fetchFromGitHub,
buildNavidromeGoPlugin,
}:
buildNavidromePlugin rec {
buildNavidromeGoPlugin (finalAttrs: {
pname = "apple-music-plugin";
bundleName = "apple-music";
version = "0.2.0";
src = pkgs.fetchFromGitHub {
src = fetchFromGitHub {
owner = "navidrome";
repo = "apple-music-plugin";
tag = "v${version}";
tag = "v${finalAttrs.version}";
hash = "sha256-45nUrIDXCtkh08TeZoc6j2BcGLQnpVJu23L56nIBN1s=";
};
vendorHash = "sha256-G1B6W8ZKoLuNwvOt3z5vSKcQmF2574j41A0lC+u39uI=";
meta = {
changelog = "https://github.com/navidrome/apple-music-plugin/releases/tag/v${finalAttrs.version}";
description = "Fetches artist metadata from Apple Music using free iTunes/Apple Music endpoints";
homepage = "https://github.com/navidrome/apple-music-plugin";
license = lib.licenses.gpl3Only;
sourceProvenance = with lib.sourceTypes; [ fromSource ];
};
}
})

View File

@@ -1,25 +1,26 @@
{
lib,
pkgs,
buildNavidromePlugin,
fetchFromGitHub,
buildNavidromeGoPlugin,
}:
buildNavidromePlugin rec {
buildNavidromeGoPlugin (finalAttrs: {
pname = "audiomuseai";
version = "8";
src = pkgs.fetchFromGitHub {
src = fetchFromGitHub {
owner = "NeptuneHub";
repo = "AudioMuse-AI-NV-plugin";
tag = "v${version}";
tag = "v${finalAttrs.version}";
hash = "sha256-WyobjyadD9IcY6mFYhCmuQgLbnoHpDoiLfINNfKmQM8=";
};
vendorHash = "sha256-mXes+doBSa5kcfHp1cuzTz30wnyyPN7NLC0iOSL8FDo=";
meta = {
changelog = "https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin/releases/tag/v${finalAttrs.version}";
description = "Navidrome plugin that integrates core AudioMuse-AI features into the Navidrome frontend.";
homepage = "https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin";
license = lib.licenses.agpl3Only;
sourceProvenance = with lib.sourceTypes; [ fromSource ];
};
}
})

View File

@@ -0,0 +1,61 @@
{
buildGoModule,
lib,
navidrome,
navidromePluginInstallHook,
go,
gitMinimal,
cacert,
}:
lib.extendMkDerivation {
constructDrv = buildGoModule;
excludeDrvArgNames = [
"meta"
"passthru"
];
extendDrvArgs =
finalAttrs:
{
pname,
version,
src,
vendorHash,
meta,
passthru ? { },
...
}@args:
{
__structuredAttrs = true;
nativeBuildInputs = [
navidromePluginInstallHook
];
ldflags = [ "-buildmode=c-shared" ];
overrideModAttrs = {
nativeBuildInputs = [
go
gitMinimal
cacert
];
};
# Go plugins are built using go install which lands in $GOPATH/bin without
# .wasm extension
preInstall = ''
find "$GOPATH"/bin/ -type f -exec cp {} "./plugin.wasm" \;
'';
passthru = {
isNavidromePlugin = true;
}
// passthru;
meta = meta // {
platforms = lib.platforms.wasi;
maintainers = navidrome.meta.maintainers ++ meta.maintainers or [ ];
};
};
}

View File

@@ -1,67 +0,0 @@
{
buildGoModule,
lib,
navidrome,
zip,
}:
{
pname,
src,
version,
vendorHash,
meta,
...
}@args:
buildGoModule (
finalAttrs:
{
inherit
pname
version
src
vendorHash
;
env = {
CGO_ENABLED = "0";
}
// (args.env or { });
postBuild = ''
GOOS=wasip1 \
GOARCH=wasm \
go build \
-buildmode=c-shared \
-o $GOPATH/bin/plugin.wasm .
'';
postInstall = ''
mkdir $out/share
pushd $(mktemp -d)
cp $GOPATH/bin/plugin.wasm .
cp ${finalAttrs.src}/manifest.json .
${lib.getExe zip} \
$out/share/${finalAttrs.pname}.ndp \
plugin.wasm \
manifest.json
popd
rm -r $out/bin
'';
passthru = {
isNavidromePlugin = true;
}
// args.passthru or { };
meta = {
inherit (navidrome.meta) platforms maintainers;
}
// args.meta or { };
}
// removeAttrs args [
"meta"
"passthru"
]
)

View File

@@ -1,25 +1,26 @@
{
lib,
pkgs,
buildNavidromePlugin,
fetchFromGitHub,
buildNavidromeGoPlugin,
}:
buildNavidromePlugin rec {
buildNavidromeGoPlugin (finalAttrs: {
pname = "discord-rich-presence-plugin";
version = "2.0.0";
src = pkgs.fetchFromGitHub {
src = fetchFromGitHub {
owner = "navidrome";
repo = "discord-rich-presence-plugin";
tag = "v${version}";
tag = "v${finalAttrs.version}";
hash = "sha256-j4iGymXH9JstPGdpPl5TFLiH8ShfE46U+BZk1n7a2yQ=";
};
vendorHash = "sha256-5ZlqyUa+UcLCBdLQaYAlb818Y8sOENjIFfb2hpRsbpQ=";
meta = {
changelog = "https://github.com/navidrome/discord-rich-presence-plugin/releases/tag/v${finalAttrs.version}";
description = "Displays your currently playing track in your Discord status";
homepage = "https://github.com/navidrome/discord-rich-presence-plugin";
license = lib.licenses.gpl3Only;
sourceProvenance = with lib.sourceTypes; [ fromSource ];
};
}
})

View File

@@ -1,25 +1,26 @@
{
lib,
pkgs,
buildNavidromePlugin,
buildNavidromeGoPlugin,
}:
buildNavidromePlugin rec {
buildNavidromeGoPlugin (finalAttrs: {
pname = "listenbrainz-daily-playlist";
version = "6.0.0";
src = pkgs.fetchFromGitHub {
owner = "kgarner7";
repo = "navidrome-listenbrainz-daily-playlist";
tag = "v${version}";
tag = "v${finalAttrs.version}";
hash = "sha256-Pzn6KwYzaCNGRH93lR4wfVnTiFr2zo8J2DAAZd41oas=";
};
vendorHash = "sha256-wvRQjLom1ZmDabsPwin5uiR8ggSDWBrEvaFljuUd/bo=";
meta = {
changelog = "https://github.com/kgarner7/navidrome-listenbrainz-daily-playlist/releases/tag/v${finalAttrs.version}";
description = "fetch daily/weekly playlists from ListenBrainz";
homepage = "https://github.com/kgarner7/navidrome-listenbrainz-daily-playlist";
license = lib.licenses.mit;
sourceProvenance = with lib.sourceTypes; [ fromSource ];
};
}
})

View File

@@ -0,0 +1,27 @@
# shellcheck shell=bash disable=SC2154,SC2164
naviPluginInstall() {
echo "Executing installPhase"
runHook preInstall
mkdir -p "$out"/share
buildDir="$(mktemp -d)"
find . -type f -name "*.wasm" -exec cp {} "$buildDir/plugin.wasm" \;
cp manifest.json "$buildDir"
pushd "$buildDir"
zip --must-match \
"$out/share/$pname.ndp" \
plugin.wasm \
manifest.json
popd
runHook postInstall
}
installPhase=naviPluginInstall

View File

@@ -0,0 +1,11 @@
{
makeSetupHook,
zip,
}:
makeSetupHook {
name = "navidrome-plugin-install-hook";
propagatedBuildInputs = [
zip
];
} ./install-phase.sh

View File

@@ -2310,7 +2310,8 @@ with pkgs;
nanoemoji = with python3Packages; toPythonApplication nanoemoji;
buildNavidromePlugin = callPackage ../by-name/na/navidrome/plugins/build-plugin.nix { };
buildNavidromeGoPlugin = callPackage ../by-name/na/navidrome/plugins/build-go-plugin.nix { };
navidromePlugins = recurseIntoAttrs (
lib.makeExtensible (
self:

View File

@@ -121,6 +121,9 @@ let
gmp = nativePlatforms;
boehmgc = nativePlatforms;
hello = nativePlatforms;
navidromePlugins =
mapAttrs (_: _: nativePlatforms)
(pkgsForCross systems.examples.wasi32 (builtins.head supportedSystems)).navidromePlugins;
tree-sitter.builtGrammars =
mapAttrs (_: _: nativePlatforms)
(pkgsForCross systems.examples.wasm32-wasip1 (builtins.head supportedSystems))