Files
psysonic-nix/README.md
2026-05-02 10:49:42 -04:00

5.6 KiB

psysonic-nix

Unofficial NixOS packaging for Psysonic — a Navidrome / Subsonic desktop client built with Tauri (Rust + WebKitGTK).

Files

File Purpose
package.nix Main derivation (stdenv.mkDerivation with finalAttrs)
default.nix Local build/test entry-point (nix-build / nix-shell)

Quick start

# 1. Clone this repo
git clone <your-repo-url>
cd psysonic-nix

# 2. Build
nix-build        # produces ./result

# 3. Run
./result/bin/psysonic

allowUnfree = true is set automatically by default.nix. If you build via NixOS configuration.nix you may need:

nixpkgs.config.allowUnfree = true;

NixOS system installation

Add to your configuration.nix:

{ config, pkgs, ... }:
let
  psysonic = pkgs.callPackage /path/to/psysonic-nix/package.nix { };
in
{
  nixpkgs.config.allowUnfree = true;
  environment.systemPackages = [ psysonic ];
}

Or with a flake overlay — see the Flake usage section below.


Flake usage (optional)

Create a flake.nix alongside package.nix:

{
  description = "Psysonic Navidrome client";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";

  outputs = { self, nixpkgs }: let
    system = "x86_64-linux";
    pkgs   = import nixpkgs { inherit system; config.allowUnfree = true; };
  in {
    packages.${system}.psysonic = pkgs.callPackage ./package.nix { };
    packages.${system}.default  = self.packages.${system}.psysonic;
  };
}

Then:

nix build .#psysonic
nix run   .#psysonic

AppImage internals & patching strategy

AppImage type

Psysonic ships a type-2 SquashFS AppImage (the standard format used by Tauri's bundler). No DwarFS or custom offsets are needed — appimageTools.extractType2 in nixpkgs handles extraction with unsquashfs automatically.

Why not appimageTools.wrapType2?

wrapType2 mounts the AppImage at runtime via FUSE, which requires the fusermount setuid binary. On NixOS that works but adds friction. Extracting the binary and patching its ELF headers is cleaner and more hermetic.

What gets patched

What How
ELF interpreter (ld-linux) patchelf --set-interpreter
Library search path (rpath) patchelf --set-rpath with all runtime deps
GIO / TLS modules GIO_MODULE_DIR env var via makeWrapper
Desktop entry Exec= line substituteInPlace

Runtime dependencies (Tauri-specific)

Because Psysonic is a Tauri v2 app it links against:

  • WebKitGTK 4.1 (webkitgtk_4_1) — renders the UI
  • GTK 3 — window chrome, file dialogs
  • libsoup 3 — HTTP client used by WebKit
  • glib-networking — TLS support for GIO (critical for HTTPS to your Navidrome)
  • PipeWire / PulseAudio / ALSA — audio output (the release notes confirm Psysonic prefers PipeWire, then PulseAudio)
  • libGL / Mesa — WebKitGTK's WebGL compositor; needed even if the app itself doesn't do 3D
  • xdg-utilsxdg-open for external links
  • libxkbcommon + wayland libs — Wayland input/display (Tauri supports both X11 and Wayland natively)

Does the app download additional binaries?

Based on the release notes, Psysonic does not download additional native binaries at runtime. LUFS analysis is done by the bundled Rust binary itself. If a future release bundles a helper binary (e.g. ffmpeg), you will need to patchelf that too — check ${appimageContents}/usr/bin/ after extraction.

OpenGL / Vulkan

WebKitGTK uses libGL for its accelerated compositor. The libGL and mesa entries in buildInputs cover this. You do not need Vulkan for a Navidrome client.

AMD GPU (RX 580)

Your RX 580 uses the open-source amdgpu kernel driver + Mesa radeonsi. NixOS 25.11 enables this by default. No extra configuration should be needed.

Wayland vs X11

Tauri 2 detects WAYLAND_DISPLAY / DISPLAY at startup and chooses accordingly. The wrapper does not force either session type, so the app will work in both.


Troubleshooting

error while loading shared libraries: libwebkit2gtk-4.1.so.0

The rpath patch didn't find the library. Run:

ldd result/lib/psysonic/psysonic | grep "not found"

and add the missing package to buildInputs in package.nix.

App launches but shows a blank white screen

WebKitGTK sandbox issue. Try:

WEBKIT_DISABLE_COMPOSITING_MODE=1 psysonic

or add --set WEBKIT_DISABLE_COMPOSITING_MODE 1 to the makeWrapper call.

TLS / HTTPS errors connecting to Navidrome

glib-networking may not be picked up. Verify:

echo $GIO_MODULE_DIR
ls $GIO_MODULE_DIR   # should contain libgiognutls.so or libgiotls.so

Audio device not found

Psysonic prefers PipeWire. Make sure services.pipewire.enable = true in your NixOS config. If you use PulseAudio only, set:

PSYSONIC_AUDIO_BACKEND=pulse psysonic

(or configure in Settings → Audio once the app opens).

Hash mismatch on fetchurl

Re-fetch the hash:

nix-prefetch-url --type sha256 \
  https://github.com/Psychotoxical/psysonic/releases/download/app-v1.44.0/Psysonic_1.44.0_amd64.AppImage

Paste the result as sha256 = "..."; in package.nix.


Updating to a new version

  1. Change version in package.nix.
  2. Update the hash using nix-prefetch-url (see above).
  3. Re-run nix-build and verify the app starts.

License

The packaging files in this repository are released under the MIT License. Psysonic itself has its own license — check the upstream repository.