NoriSync is distributed as a Jellyfin plugin repository, so the recommended install path is to add the repo to your Jellyfin server and let Jellyfin handle downloads and updates.
NoriSync · latest 1.0.0.71 ·
target ABI 10.11.0.0 · published 2026-05-06
10.11.0.0 (Jellyfin 10.11.x)NORISYNC_EMBEDDER_DEVICE=coreml if you want to experiment.The manifest is published from the project's Gitea releases.
Manifest URL:
https://git.missen.ca/Esmond/jellyfin-plugin-norisync/releases/download/manifest/manifest.json
In Jellyfin:
NoriSync (or any label you prefer)Jellyfin fetches the manifest and merges NoriSync into the plugin catalog.
After restart, the plugin appears under Dashboard → Plugins → My Plugins. Identifying details:
If your server can't reach the manifest URL, download the latest zip
directly and extract it into Jellyfin's
plugins/NoriSync_<version>/ directory, then restart Jellyfin.
NoriSync is licensed under GPL-2.0-or-later. The source archive for this build is available if you'd like to inspect or rebuild it before installing the binary.
To rebuild from source: extract the zip and run
dotnet build Jellyfin.Plugin.NoriSync/Jellyfin.Plugin.NoriSync.csproj -c Release.
Outputs land in bin/Release/net9.0/.
Skip this section if you don't want audio embeddings — the delta-sync API
works without the companion. Otherwise, the
norisync-embedder is a small FastAPI server that
wraps a YAMNet ONNX model and exposes /embed and
/health. The plugin calls it over HTTP from the
Compute Audio Embeddings scheduled task.
Run it on whichever host you want — Jellyfin's box, an Apple Silicon Mac, or a Linux machine with a CUDA GPU. The plugin only needs to reach it on the network.
Source lives in the companion/ directory of this repo. Easiest
path is uv, which the project's
uv.lock is built against. Python ≥ 3.11 is required.
git clone https://git.missen.ca/Esmond/jellyfin-plugin-norisync.git
cd jellyfin-plugin-norisync/companion
uv sync --extra fetch
The fetch extra pulls in TensorFlow, tensorflow-hub, and
tf2onnx — only needed for the one-time model conversion below. Drop it if
you already have yamnet.onnx on disk and point
NORISYNC_EMBEDDER_YAMNET_ONNX at it.
uv run python -m norisync_embedder.tools.fetch_yamnet
Pulls YAMNet from tfhub.dev/google/yamnet/1
and writes yamnet.onnx into the cache directory
(~/Library/Caches/norisync-embedder on macOS,
overridable via NORISYNC_EMBEDDER_CACHE_DIR). After this you
can drop the fetch extra — the runtime server only needs
onnxruntime.
uv run norisync-embedder
Listens on 0.0.0.0:9000 by default. Verify it's up:
curl http://<companion-host>:9000/health
# {"status":"ok","model_version":"yamnet-v3+bpm1","providers":["CPUExecutionProvider"], ...}
| Variable | Default | Notes |
|---|---|---|
NORISYNC_EMBEDDER_HOST |
0.0.0.0 |
Bind address. |
NORISYNC_EMBEDDER_PORT |
9000 |
Bind port. Whatever you pick goes into the plugin's Embedder Endpoint field. |
NORISYNC_EMBEDDER_DEVICE |
auto | onnxruntime execution provider: cpu,
cuda, or coreml (alias
mps). Auto picks CUDA when available, otherwise
CPU. CoreML is opt-in — see the requirements section. |
NORISYNC_EMBEDDER_CACHE_DIR |
~/Library/Caches/norisync-embedder |
Where yamnet.onnx is read from / written to. |
NORISYNC_EMBEDDER_YAMNET_ONNX |
(blank) | Explicit path to a pre-existing ONNX file. Overrides the cache dir lookup. |
NORISYNC_EMBEDDER_LOG_LEVEL |
INFO |
Standard Python logging levels. |
To run as a long-lived service, wrap uv run norisync-embedder
in whatever supervisor your host uses — launchd on macOS,
systemd on Linux, a Docker CMD, etc.
Open Dashboard → Plugins → My Plugins → NoriSync to reach the settings page. There are two sections.
| Setting | Default | Notes |
|---|---|---|
| Retention Period (days) | 30 |
Change records older than this are purged. Also the idle threshold for registered clients — instances silent for this many days are dropped from retention gating. |
Lower this if disk usage on the change log is a concern; raise it if you have clients that go offline for extended periods and you don't want them to miss deletes.
These settings drive the NoriSync: Compute Audio Embeddings scheduled task (daily at 03:00 by default). Leave embeddings disabled if you only want the delta-sync API.
| Setting | Default | Notes |
|---|---|---|
| Enable Audio Embeddings | off | Master switch. The scheduled task is a no-op until this is on. |
| Max Tracks Per Run | 0 |
Cap on tracks processed per run. 0 = unlimited.
Useful when first enabling on a large library to spread the
initial scan across multiple nights. |
| Embedding Concurrency | 2 |
Parallel workers. Each spawns its own ffmpeg decode, so this multiplies CPU and process count. 2–3 is typical; raise carefully. |
| Embedder Endpoint | (blank) | Base URL of the norisync-embedder companion, e.g.
http://m5-mac:9000. Required when embeddings are
enabled — inference is always offloaded to this service over
HTTP, there is no in-process path. |
The model is YAMNet (Apache-2.0, 521-class AudioSet classifier). The
companion ships a one-time conversion tool —
python -m norisync_embedder.tools.fetch_yamnet — that pulls
the weights from TF Hub and writes a local yamnet.onnx served
by onnxruntime. Embedding model version is reported in /health
as yamnet-v3+bpm1.
After saving config, confirm the plugin is live without auth by hitting:
GET http://<your-jellyfin>/api/norisync/info
It returns { id, name, version }. All other endpoints
require Jellyfin authentication — see the API section of the
README for the full endpoint list.
Once the repository is added, Jellyfin's plugin catalog will surface new versions automatically. Use Dashboard → Plugins → My Plugins to update, then restart Jellyfin.