Skip to content

Development

blarns edited this page Jun 3, 2026 · 1 revision

Development

Prerequisites

  • JDK 17+
  • Android SDK (if building the Android target)
  • libvlc-dev and vlc (for desktop)
  • A Supabase project (see Configuration)

Building

git clone https://github.com/blarns/NuvioForLinux.git
cd NuvioForLinux

# Run on Linux desktop
./gradlew composeApp:run

# Compile only (no launch)
./gradlew composeApp:jvmMainClasses

# Run tests
./gradlew composeApp:jvmTest

# Build Android APK
./gradlew composeApp:assembleFullDebug

Project structure

NuvioForLinux/
├── composeApp/
│   └── src/
│       ├── commonMain/        # Shared UI, features, repositories
│       ├── androidMain/       # Android-specific implementations
│       ├── iosMain/           # iOS-specific implementations
│       ├── desktopMain/       # Linux/JVM desktop implementations
│       └── jvmMain/
│           └── resources/     # Desktop resources (app icon, etc.)
├── iosApp/                    # Native Xcode project
├── scripts/
│   └── install-desktop.sh     # App menu integration
└── nuvio.desktop              # Desktop entry file

Key desktop files

File Purpose
desktopMain/kotlin/.../Main.kt App entry point, window setup, MPRIS2 init
desktopMain/kotlin/.../PlayerEngine.desktop.kt VLCJ video player, keyboard/scroll input
desktopMain/kotlin/.../Mpris2Handler.kt MPRIS2 D-Bus interface
desktopMain/kotlin/.../DesktopWindowState.kt Fullscreen toggle singleton
desktopMain/kotlin/.../PlayerControlBridge.kt Bridge between MPRIS2 and player controller
desktopMain/kotlin/.../DesktopPrefs.kt Persistent key-value storage (wraps java.util.prefs)

Architecture notes

Video rendering

The desktop player uses VLCJ's buffer callback API. VLC decodes each frame into a ByteBuffer, which is then converted to a Skia ImageBitmap and painted onto a Compose Canvas. This avoids AWT/Swing Z-ordering issues that would prevent the controls overlay from rendering correctly on top of the video.

With VA-API enabled, VLC still copies the final decoded frame from GPU to CPU for the buffer callback (this is a known trade-off of the current approach). CPU savings still come from offloading the actual decode work to the GPU's media engine.

Settings persistence

Desktop player settings use java.util.prefs.Preferences (via DesktopPrefs). Values larger than the JVM's 8 KB preference limit automatically overflow to files in ~/.local/share/nuvio/prefs/.

MPRIS2

MPRIS2 is implemented using dbus-java-core 4.3.1. The service is started in main() and wrapped in runCatching so D-Bus unavailability never crashes the app. Playback control flows through PlayerControlBridge which holds a reference to the active VlcjPlayerController.

CI

GitHub Actions runs two jobs on every push to main and develop:

  • build-linux-desktop — compiles the JVM target
  • test — compiles and runs jvmTest

Both jobs install VLC dependencies and create a blank local.properties before building.

Contributing

Pull requests, bug reports, and feature suggestions are welcome at github.com/blarns/NuvioForLinux.

Note: The upstream NuvioMobile project is currently being rewritten by the official team and is not accepting pull requests. Changes should be targeted at this fork only.

Please read CONTRIBUTING.md before submitting.

Clone this wiki locally