# music-player: a Rust music server that borrows Rockbox's playback engine

> music-player is a single binary music daemon, server and client written in Rust, in the same family as mpd and Mopidy, but with the audio decoding and playback handled by the Rockbox firmware's engine. The result is a wide format support, a local SQLite index with full text search, and three interfaces over the same library.

**tsirysndr/music-player** —  An extensible music server written in Rust , single binary, zero dependency  🚀🎵✨

- Repository: https://github.com/tsirysndr/music-player
- Stars: 527 · Forks: 34
- Language: Rust
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/tsirysndr-music-player

## A daemon in the mpd and Mopidy family, with a different audio core

The project's own description is precise about the category. It is an extensible music player daemon, server and client, written in Rust, like mpd or Mopidy.

Those two names set the expectation correctly. This is a background service that owns a music library, indexes it, and exposes it to clients. It is not a desktop player that happens to have a server mode, and it is not a browser front end. The daemon is the product, and the interfaces are clients of it.

What separates it from mpd and Mopidy is the audio engine. Decoding and playback are powered by the Rockbox firmware's engine, through three crates published by the same author: rockbox-playback, rockbox-dsp and rockbox-metadata. The readme lists what that buys: more than 40 audio formats, gapless grade buffering, EQ, crossfade and ReplayGain DSP, and native HTTP streaming.

That is an unusual choice and it is the most interesting decision in the project. Rockbox is a portable media player firmware, so its decoding code has been exercised against essentially every codec anyone has ever put on a microSD card, in a context where the hardware was weak enough that any inefficiency showed. Reusing that engine means the format coverage and the DSP behaviour are inherited rather than reimplemented.

The format list in the feature list is worth reading closely: MP3, FLAC, Vorbis, Opus, MP4 with AAC and ALAC, WavPack, APE, WMA and chiptunes. That last category is the tell. A music server for a Raspberry Pi or a small home box is not usually where you would expect chiptune playback to matter, which tells you the engine came from a player for music enthusiasts rather than from a streaming service.

The release cadence is fast and the version is still low. The listed releases are v0.4.4 from 2026-09-15, v0.4.3 from the same day and v0.4.2 from 2026-09-14, and the last push was on 2026-10-20. The package manifest names the version 0.4.4 and the author is Tsiry Sandratraina.

## One workspace of twenty crates, all versioned together

The Cargo.toml is where the scope of the project becomes obvious, and it is a workspace of twenty members.

The list covers analysis, analytics, client, desktop, discovery, entity, extensions, graphql, migration, playback, rsql, scanner, server, settings, mcp, provider, renderer, storage, tracklist, types and webui.

Each of those becomes a published crate rather than a private module, and the manifest shows the pattern: music-player-provider, music-player-analytics, music-player-server, music-player-playback, music-player-scanner, music-player-entity, music-player-migration, music-player-settings, music-player-storage, music-player-renderer, music-player-tracklist, music-player-mcp and music-player-client, each with a path, a version of 0.4.4 and a name prefixed with music-player.

Two details in that arrangement are worth noting. The version is identical across all of them, so the crates are released as a set and cannot drift apart, and the namespacing means they can be added to a Cargo.toml without colliding with anything else in the dependency graph.

The binary itself is thin. The manifest declares a single bin target named music-player with a path of src/main.rs, and the description is An extensible music player daemon written in Rust. The categories list is command-line-utilities, and the keywords are tokio, music, daemon, streaming and player.

The other names in the workspace tell you what the project does beyond playing audio. mcp is the Model Context Protocol server, so an AI agent can drive the player. analytics is the DuckDB based listening history analysis. rsql is a query language crate. discovery, provider and scanner are the parts that find music, whether on disk or on a remote server. extensions is where the extension system lives. The repository root backs this up with an extensions/ directory, an mcp/ directory, a skills/ directory, a graphql/ directory, a webui/ directory, a desktop/ directory and a mobile/ directory.

There is also a Bazel build alongside Cargo, with a WORKSPACE file, a BUILD file, a .bazelrc and a .bazelversion, plus a Nix flake, a devcontainer and a Flutter-free mobile directory, which is a lot of build systems for one project. The Cargo.lock and cargo-bazel-lock.json both exist, so both toolchains are meant to work.

## Installing a prebuilt binary, and pinning the version

The install paths all fetch a prebuilt binary rather than compiling, and the first one is a script over HTTPS.

```bash
curl -fsSL https://raw.githubusercontent.com/tsirysndr/music-player/master/install.sh | sh
# pin a specific release:
curl -fsSL https://raw.githubusercontent.com/tsirysndr/music-player/master/install.sh | MUSIC_PLAYER_VERSION=v0.4.4 sh
# also install the Slint desktop app (music-player-desktop):
curl -fsSL https://raw.githubusercontent.com/tsirysndr/music-player/master/install.sh | MUSIC_PLAYER_DESKTOP=1 sh
```

Two environment variables control the outcome, and the second one is a nice touch. MUSIC_PLAYER_VERSION pins the release, and MUSIC_PLAYER_DESKTOP=1 also installs the Slint desktop app alongside the daemon. The first URL is the master branch, so the script itself always tracks the tip of the repository, and pinning the version is what stops your install from changing underneath you on a Tuesday.

The npm route downloads the same prebuilt binary from GitHub releases.

```bash
npm install -g @tsiry/music-player   # or: npx @tsiry/music-player
# pin a specific release: MUSIC_PLAYER_VERSION=v0.4.4 npx @tsiry/music-player
```

An npm package that is really a downloader for a GitHub release is a slightly odd arrangement, but it means the package manager resolves the platform binary, and for a Node based deployment it fits the existing toolchain. The readme also documents a Homebrew route for macOS and Linux, and there is a FlakeHub badge at the top of the readme, so the Nix route is a first class option rather than an afterthought.

That the whole project is distributed as a single binary is the point of the description. Zero dependency, one file to run, no runtime to install.

The project also links a sibling, rockboxd, described as a music player daemon built on the Rockbox Open Source Firmware that brings advanced audio playback features to modern platforms with the power of Zig and Rust. If you want a Rockbox daemon without the server, index and API layers, that is the one to look at.

## Three interfaces over the same library

The feature list describes three ways to drive the daemon, and they are not skins over each other.

The terminal interface is built with ratatui, and the description is unusually specific: an fzf-style fuzzy finder, a neovim-inspired status line and a help overlay on the question mark key. The web interface is React 18 with Tailwind v4 and HeroUI, and it uses the same skins, fonts and components as the Slint desktop app, responsive down to a phone. The desktop app is a skinnable Slint application with an embedded daemon.

That last point is worth pausing on. An embedded daemon means the desktop app does not need a separate server process, which is what makes it a self contained player rather than a remote control, and it is why the same visual assets can be shared between the browser and desktop builds.

Underneath, the APIs are gRPC with tonic 0.14 and grpc-web enabled, and GraphQL, so you can write your own client. The readme links a buf.build documentation site for the music.v1alpha1 package, so the protobuf service is versioned as an API rather than treated as an internal detail.

The library behind them is indexed into SQLite with FTS5 full text search, and the readme says the index is kept in sync automatically by database triggers rather than by a reindex step. For a music library that means searching across tens of thousands of tracks is a query rather than a scan.

Beyond playing your own files, the project talks to other things. It can browse and stream from Subsonic and Navidrome servers and from Jellyfin. It can cast to Chromecast and UPnP and DLNA renderers, or control another music-player daemon. It can search internet radio through Radio Browser and TuneIn, bookmark stations, and play them in a fullscreen now-playing view. It scrobbles to Rocksky over the AT Protocol, and it syncs radio bookmarks and liked songs to an atproto repository, writing them back to your PDS and keeping them live over Jetstream.

The audio output side is deliberately open. The system device through cpal, stdout, a FIFO, a Unix socket or a TCP socket are all options, which is what makes the thing usable on a headless box piping audio into another program.

## Fingerprinting, analytics and the AI agent surface

Three features in the readme go beyond playing files, and they are the ones that make this more than a server.

Acoustic fingerprinting uses Chromaprint to identify every file by its audio rather than its tags, and badly tagged files are named from AcoustID and MusicBrainz the way Picard does it. That is a genuinely useful thing for a self hosted library, because the tags people rip from somewhere are often wrong or absent, and a server that indexes on tags will show you a library full of Track 01.

Listening analytics uses DuckDB and, in the readme's phrasing, lets you import years of Spotify, Last.fm and Rocksky history, deduplicate it across sources, and then ask it about sessions, skips, taste drift and what actually follows what. Deduplicating across three services that each use different identifiers for the same artist is not trivial, and the fact that the project tries to answer what comes after what rather than only what you played is a different question from the usual play count.

The AI agents feature is an MCP server, and the mcp/ crate and mcp/ directory are both in the tree. The dependency list includes the Anthropic SDK, the OpenAI SDK, the AWS Bedrock runtime client and the Google GenAI client, and a Qdrant client, which is the vector search piece. The goals of the sibling project and the tools/ and skills/ directories suggest the MCP surface is meant to be extended rather than merely exposed.

There is also a casting feature for Chromecast and UPnP and DLNA renderers, and a Config section in the table of contents covering audio output, track cache, Subsonic and Navidrome and Jellyfin, Rocksky scrobbling and AT Protocol sync, plus sections on audio analysis and auto-DJ, acoustic fingerprints and missing tags, AI agents, listening analytics and casting. So the feature surface is wide, and the readme's own table of contents is the honest index of it.

## Where music-player is the wrong tool

There are four cases where this is the wrong choice, and one where nothing else will do.

The first is a local player with no server. If you want to play your own files and nothing else, the desktop app alone is enough, or any of the many conventional players will do. A daemon that indexes a library, keeps a database in sync, serves an API and runs as a background service is a lot of architecture for a laptop with a folder of music.

The second is a multi-user home with a shared library that must be reliable. This is a fast moving 0.4 series with a release cadence of several builds in a day in the listed history. That is a good sign of activity and a bad sign for stability, and a shared household server that needs to be up when four people want music is not a good place to run something that moves this fast.

The third is a deployment where you cannot run a long lived native process. It is a binary with a SQLite library and a network listener, and the readme does not describe a read only or stateless mode. Anyone who wants the search index but not the server is not served by this project.

The fourth is a protocol requirement. The project speaks gRPC, GraphQL and a web UI, and it can read from Subsonic style servers. It does not present itself as a Subsonic compatible server, so if your requirement is that Jellyfin or a client app can connect to it over Subsonic, that is not what this is.

The case where it is the right tool is a self hoster with a large local library, multiple clients, and a preference for one binary. The combination of Rockbox's format coverage, a trigger kept search index, three interfaces and an API for your own clients is a specific and unusual package, and for a Raspberry Pi or a small home server it is a plausible alternative to running a heavier media stack.

On the alternative, the difference in approach against mpd is the audio engine and the interface set. mpd is a small C daemon with a text protocol and a small ecosystem of clients, and it is still the reference point for this category. music-player trades the tiny footprint for the Rockbox engine, the FTS5 index and the web and desktop clients, and adds the gRPC and GraphQL surfaces and the MCP server. The trade against Mopidy, which is a Python daemon with a large extension ecosystem of web apps and backends, is similar in shape: a more capable core in exchange for a heavier dependency set, though the Rust implementation means a single binary rather than a Python environment.

The licence is MIT, which is the permissive end, and the repository carries a LICENSE file. The Cargo.toml records the same. The project is published on crates.io as music-player, and the crates are published individually so you can depend on the storage or scanner crate without pulling the whole server.

## Conclusion

music-player suits a self hoster who wants one binary that indexes a large local library, exposes it over an API and a browser interface, and plays it through a maintained DSP chain, and it does not suit someone who only wants a local player with no server component, since the daemon and the library index are the point of the project. Before you adopt it, pin a version rather than taking the moving one, since the install script accepts MUSIC_PLAYER_VERSION for exactly that reason, and check the codec set your library actually uses against the 40 or more formats the readme lists.

## FAQ

### What is the music-player project?

It is an extensible music player daemon, server and client written in Rust, in the same family as mpd and Mopidy. It ships as a single binary, indexes your library into SQLite with FTS5 search, and exposes it over gRPC, GraphQL and a web UI.

### Which audio formats does music-player support?

Playback is powered by the Rockbox firmware engine through the rockbox-playback, rockbox-dsp and rockbox-metadata crates, covering 40 or more formats including MP3, FLAC, Vorbis, Opus, MP4 with AAC and ALAC, WavPack, APE, WMA and chiptunes, with EQ, crossfade and ReplayGain in the DSP chain.

### How do I install music-player?

The install script downloads a prebuilt binary from GitHub releases and can be pinned with MUSIC_PLAYER_VERSION, or the desktop app can be included with MUSIC_PLAYER_DESKTOP=1. There is also an npm route with the @tsiry/music-player package and a Homebrew route.

### Can music-player browse and stream from other servers?

Yes. The readme lists support for browsing and streaming from Subsonic and Navidrome servers and from Jellyfin, plus casting to Chromecast and UPnP and DLNA renderers, and internet radio through Radio Browser and TuneIn.

### What licence is music-player released under?

It is released under the MIT License, recorded in the Cargo.toml and in the LICENSE file at the repository root.

## Sources

- [Issues](https://github.com/tsirysndr/music-player/issues)
- [License: MIT](https://github.com/tsirysndr/music-player/blob/master/LICENSE)
- [README](https://github.com/tsirysndr/music-player/blob/master/README.md)
- [Releases](https://github.com/tsirysndr/music-player/releases)
- [tsirysndr/music-player on GitHub](https://github.com/tsirysndr/music-player)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tsirysndr-music-player
