# psysonic-nix Unofficial NixOS packaging for [Psysonic](https://github.com/Psychotoxical/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 ```bash # 1. Clone this repo git clone 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: ```nix nixpkgs.config.allowUnfree = true; ``` --- ## NixOS system installation Add to your `configuration.nix`: ```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](#flake-usage) section below. --- ## Flake usage (optional) Create a `flake.nix` alongside `package.nix`: ```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: ```bash 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-utils** — `xdg-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: ```bash 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: ```bash 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: ```bash 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: ```bash PSYSONIC_AUDIO_BACKEND=pulse psysonic ``` (or configure in Settings → Audio once the app opens). ### Hash mismatch on `fetchurl` Re-fetch the hash: ```bash 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](https://github.com/Psychotoxical/psysonic).