Skip to content

Building from Source

RadicalMuffinMan edited this page Oct 6, 2026 · 5 revisions

Building from Source

This page takes you from a clean computer to the same zip files the Releases page ships. Windows, macOS and Linux all work. You don't need a running Jellyfin or Emby to build, the plugins compile against their host packages (Jellyfin 10.10.0, Emby 4.9.1.90).

For ready-made packages instead, see Installation.

What's in the repo

Two independent plugins live in one repository:

  • Jellyfin/ the Jellyfin plugin, .NET 8
  • Emby/ the Emby plugin, .NET Standard 2.1

They share manifest.json (the Jellyfin plugin catalogue file), README.md and LICENSE at the root.

Plugin/
├── manifest.json              shared Jellyfin plugin repository manifest
├── README.md, LICENSE
├── Jellyfin/                  .NET 8 Jellyfin plugin
│   ├── build.sh, build.ps1
│   ├── backend/
│   │   ├── Moonfin.Server.csproj
│   │   ├── Api/               controllers
│   │   ├── Services/          settings, games, caches, sync tasks
│   │   ├── Models/
│   │   ├── Helpers/           File Transformation patches
│   │   ├── Pages/             admin config page
│   │   ├── Web/               loader.js and inject.html
│   │   ├── EmulatorJS/        in-browser player shell
│   │   └── assets/
│   ├── frontend/              the Moonfin web app goes here (only the theme editor is committed)
│   ├── tests/                 unit tests
│   └── tools/verify-plugin/   build-time DLL verifier
└── Emby/                      netstandard2.1 Emby plugin
    ├── build.sh, build.ps1
    ├── Emby.Plugins.Moonfin/
    │   ├── Emby.Plugins.Moonfin.csproj
    │   ├── Api/               services, requests, and game logic
    │   ├── Services/, Models/, Pages/, Web/, EmulatorJS/, assets/
    ├── tests/
    ├── web/                   the Moonfin web app goes here (not committed)
    └── release/               build output staging

Step 1: Install the .NET 8 SDK

The SDK, not just the runtime. Check afterwards with dotnet --version, which should print 8.x.

  • Windows: winget install Microsoft.DotNet.SDK.8 in a terminal, or the installer from dotnet.microsoft.com. Open a new terminal afterwards.
  • macOS: brew install dotnet@8, or the installer from the same page. Apple silicon and Intel both work.
  • Linux: your distribution's dotnet-sdk-8.0 package (Fedora and Ubuntu have it, Debian through Microsoft's repository), or the official script:
curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
bash /tmp/dotnet-install.sh --channel 8.0
export PATH="$HOME/.dotnet:$PATH"    # add this line to ~/.bashrc or ~/.zshrc too

The script installs into ~/.dotnet, which is not on your PATH until you add it. A bare dotnet that says "command not found" right after installing is that.

The Emby plugin targets .NET Standard 2.1, and the .NET 8 SDK builds that too. Nothing extra to install.

Also needed for build.sh: zip, jq and an MD5 tool (md5sum on Linux, md5 on macOS). On Ubuntu sudo apt install zip jq, on macOS brew install jq. On Windows use build.ps1, which needs none of them.

Step 2: Get the code

git clone https://github.com/Moonfin-Client/Plugin.git
cd Plugin

Step 3: Decide what to do about the web app

Both plugins serve the Moonfin web app at /Moonfin/Web/, Jellyfin from Jellyfin/frontend/ and Emby from Emby/web/. The web app is not in this repository. Only the theme editor under frontend/theme/ is. You have three options:

  1. Skip it. If you only care about the server side, build without it. The plugin works, and /Moonfin/Web/ answers 404 until a web bundle is added. The build script prints a warning and carries on.
  2. Download it. Every Moonfin-Core release attaches a ready-built web bundle named moonfin-web-v<version>.tar.gz. Get it from the Moonfin-Core Releases page and extract it so that index.html ends up directly inside Jellyfin/frontend/ (and Emby/web/ for Emby). Keep the existing theme/ folder.
  3. Build it. Needs Flutter. From a checkout of Moonfin-Core next to this repo, run ./build-web-plugin.sh. It builds once and copies the result into both plugin folders. Pass the two target folders as arguments if your checkouts live elsewhere, or set MOONFIN_PLUGIN_FRONTEND_DIR and MOONFIN_EMBY_WEB_DIR. The Moonfin-Core Building from Source page covers installing Flutter.

Step 4: Build the Jellyfin plugin

cd Jellyfin
./build.sh                  # macOS and Linux
pwsh ./build.ps1            # Windows

Both accept an optional version and target ABI:

./build.sh 2.4.0.0 10.10.0
pwsh ./build.ps1 -Version "2.4.0.0" -TargetAbi "10.10.0"

The script compiles the plugin, runs the verify tool as a gate, bundles frontend/ next to the DLL, zips everything and updates the checksum in manifest.json.

Output: Jellyfin/Moonfin.Server-<version>.zip, containing Moonfin.Server.dll, SharpCompress.dll, meta.json and frontend/.

Step 5: Build the Emby plugin

cd Emby
./build.sh                  # macOS and Linux
pwsh ./build.ps1            # Windows

The script compiles the plugin, copies the DLL and SharpCompress.dll (Emby doesn't ship it, and .7z ROM extraction needs it), bundles the web folder if present, and zips them.

Output: Emby/Moonfin.Emby-<version>.zip, containing Emby.Plugins.Moonfin.dll, SharpCompress.dll and web/. The Emby build doesn't touch manifest.json, since Emby installs from a zip rather than a catalogue.

Step 6: Install your build

Follow the hand-install steps on Installation: extract the Jellyfin zip into plugins/Moonfin/, or copy the three Emby items into Emby's plugins/ folder, then restart the server.

For a Jellyfin catalogue install of your own builds, host your edited manifest.json somewhere reachable and point the sourceUrl entries at your zips.

Tests

dotnet test Jellyfin/tests/Moonfin.Server.Tests/Moonfin.Server.Tests.csproj
dotnet test Emby/tests/Emby.Plugins.Moonfin.Tests/Emby.Plugins.Moonfin.Tests.csproj
dotnet run --project Jellyfin/tools/salvage-tests -c Release

CI runs all three plus the verify tool on every pull request, and fails when the version in build.sh drifts from the csproj or the target ABI drifts from the referenced Jellyfin.Controller package.

Advanced: version bumps

A release bumps the version in four places that CI checks against each other: MoonfinVersion in Jellyfin/backend/Moonfin.Server.csproj, the default in Jellyfin/build.sh, AssemblyVersion in the Emby csproj, and a new entry at the top of manifest.json (the build script adds it for you with the checksum). The targetAbi must equal the Jellyfin.Controller package version.

Advanced: push notifications in a local build

The Jellyfin build reads an optional relay key from a git-ignored .env at the repo root. Without it the build still succeeds and the plugin ships with push through the relay disabled. Admins can still point the plugin at their own Firebase service account from the Integrations tab.

Troubleshooting

dotnet: command not found right after installing on Linux or macOS. The script-based install lands in ~/.dotnet. Add it to PATH as shown in Step 1 and open a new terminal.

Warning: frontend/index.html not found. Expected when you skipped Step 3. Add a web bundle and build again if you want the web app in the zip.

jq: command not found or md5sum: command not found. Install them (Step 1), or build on Windows with build.ps1.

The verify tool fails. It checks the built DLL for things that break a Jellyfin install, such as missing types. Read its message. It normally means a dependency version doesn't match the referenced Jellyfin packages.

Jellyfin shows the plugin as Malfunctioned after installing a local build. The targetAbi you built for doesn't match the running Jellyfin. Build with the ABI of your server, for example ./build.sh 2.4.0.0 10.10.0.

Clone this wiki locally