Skip to content

Repository files navigation

Neiro Desktop icon

Neiro Desktop (音色)

A Compose Multiplatform desktop music client for OpenSubsonic / Navidrome — companion to the Neiro Android app.
Dynamic album-art color theming, Last.fm scrobbling, and one-click sync to Rockbox DAPs.

Platforms Compose Multiplatform JDK 23 Kotlin 2.2


✨ Features

🎨 Dynamic Color Theming

  • Color palette extracted from the current album art and applied across the whole UI
  • Animated transitions between palettes on track change
  • Full light / dark mode toggle in settings
  • When browsing an album or artist, the sidebar and chrome pick up that artwork's colors
  • Or pin a fixed accent color instead — preset swatches or any hex value, in Settings → Appearance

🎵 Playback

  • Streams directly from your OpenSubsonic/Navidrome server — no downloads, no local library
  • VLC-backed player (vlcj) for broad format support
  • Seek bar with real-time position, volume control, shuffle, and repeat (one/all)
  • Queue panel in the fullscreen Now Playing view
  • Auto-advance to next track; previous track restarts within 3 s

🪟 Now Playing

  • Fullscreen immersive player: blurred album art background + dark/light overlay
  • Queue sidebar with currently playing indicator
  • Love track directly to Last.fm from the player

🏠 Home Screen

  • Configurable sections: Recently Added, Random, Highest Rated, Frequent, Most Recently Played
  • Last.fm Top Albums, Top Artists, Top Tracks — all cross-referenced with your Subsonic library
  • Configurable time range (7 days / 1 month / 3 months / 6 months / 1 year / all time)
  • Scrobble counts shown on album cards
  • Click any Last.fm item to navigate directly to the matching album or artist

📊 Last.fm Integration

  • Automatic "Now Playing" update on every track start
  • Scrobbles at the standard threshold: ≥ 30 s played and ≥ 50 % of track length (or 4 min)
  • Personal scrobble counts per artist's top tracks (your history, not global charts)
  • Love / unlove tracks from the Now Playing screen
  • Full OAuth login from the desktop settings screen

📚 Library

  • Albums, Artists, Playlists — all paginated and searchable
  • Artist detail: biography, top tracks with your personal scrobble counts, album grid
  • Album detail: full track list, total duration, play count, scrobbles badge
  • Browser: iTunes-style artist/album browser with keyboard typeahead jump-to-artist and inline expandable tracklists, grouped by year
  • Collapsible sidebar with search built in, and a dedicated queue panel next to the player showing the current track's format/bitrate/genre

📱 QR Sync with Mobile

  • Generate a QR code in settings → scan with the Neiro Android app
  • Transfers server URL + credentials to the phone in one step; no manual typing

🎸 Device Sync (Rockbox / DAP)

The desktop app includes a full sync engine for Rockbox DAPs (and any mounted folder).

Sidebar → Device Sync

Setting Options
Device path Any mount point, e.g. /media/user/ROCKBOX
Folder template Configurable with {artist}, {album}, {track:02d}, {title}, {year}
Format Original · MP3 · OGG Vorbis · Opus
Bitrate 128 / 192 / 256 / 320 kbps
Lossless-only conversion Convert only FLAC/WAV/ALAC; copy lossy sources as-is
Playlists Sync all Subsonic playlists as M3U files to {device}/Playlists/
Cover art Save as folder.jpg per album directory

How it works:

  1. The engine pages through your entire Subsonic library (all albums → all tracks), fetching album metadata with bounded concurrency for speed
  2. {albumArtist} is resolved once per album from the album's own artist field — never per track — so a record can't scatter across multiple artist folders because of inconsistent tags
  3. Each track's destination path is computed from the folder template and file extension; downloads run with bounded concurrency too
  4. A sync manifest tracks which format/bitrate each file was last synced with, so changing your conversion settings correctly re-syncs the affected files instead of silently skipping them — or force a full re-sync with one checkbox
  5. Transcoding is handled server-side by Subsonic's stream?format=ogg&maxBitRate=192 — no local FFmpeg required
  6. After music sync, all Subsonic playlists are written as M3U with relative paths (directly playable by Rockbox)
  7. A live progress bar shows: current track · N/total · ✓synced · ⤳skipped · ✗errors

Tip for Rockbox devices with limited/uncertain codec support (e.g. Innioasis Y1): OGG Vorbis is the safest universally-compatible lossy format — Opus isn't reliably supported by every stock DAP firmware, even where Rockbox itself would play it fine.

📻 Rockbox Scrobble Import

Rockbox writes offline plays to a .scrobbler.log file at the device root. Neiro can import it directly:

  • Auto-detects the log path from your configured device path
  • Parses the standard AUDIOSCROBBLER format, skipping tracks Rockbox marked as skipped (rating S)
  • Submits in batches of 50 to Last.fm
  • Only clears/archives the log once every entry is confirmed submitted — a partial failure leaves it untouched so nothing is lost on retry

🛠 Tech Stack

Language Kotlin 2.2
UI Jetpack Compose (Compose Multiplatform Desktop 1.8)
Audio vlcj 4.8 (VLC bindings for JVM)
HTTP Ktor Client 3.0 (CIO engine)
Serialization kotlinx.serialization JSON
Image loading Coil 3 + Ktor network backend
Color extraction Coil + Palette (Swing/AWT fallback)
Preferences JSON file at ~/.config/neiro/prefs.json
Build Gradle 9, compose.desktop plugin, AppImage + Deb packaging

🚀 Getting Started

Prerequisites

  • JDK 23+
  • VLC installed on the system (vlcj requires native VLC libraries)
  • A running Navidrome or any OpenSubsonic-compatible server

Run from source

git clone https://github.com/FabianZettl/NeiroDesktop.git
cd NeiroDesktop
./gradlew run

Build distributable (Linux AppImage + .deb)

./gradlew createDistributable   # → build/compose/binaries/main/app/neiro/
./gradlew packageAppImage       # → build/compose/binaries/main/appimage/
./gradlew packageDeb            # → build/compose/binaries/main/deb/

Last.fm API credentials (optional)

Last.fm integration (scrobbling, top charts, love/unlove) needs your own free API key — the project doesn't ship one. Create one at last.fm/api/account/create, then either:

  • set env vars NEIRO_LASTFM_API_KEY / NEIRO_LASTFM_API_SECRET, or
  • create ~/.config/neiro/lastfm.properties:
    apiKey=your-api-key
    apiSecret=your-api-secret

Without this, the app runs fine — Last.fm features are just unavailable.

First launch

On first launch the setup screen prompts for server URL, username, and password. Credentials are stored locally at ~/.config/neiro/prefs.json. Last.fm login is optional and configured separately in Settings.


📱 Mobile Companion

The Neiro Android app is the mobile counterpart — same server, same Last.fm account, same playlists. Use the QR sync feature to pair them instantly.


🤖 AI Transparency

This project was built with significant assistance from Claude (Anthropic) as a coding collaborator — architecture decisions, UI layout, and feature implementation were developed interactively. All code is reviewed and owned by the maintainer.


📄 License

MIT

About

Desktop music client for OpenSubsonic/Navidrome — Compose Multiplatform companion to the Neiro Android app. Dynamic theming, Last.fm scrobbling, Rockbox device sync.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages