Skip to content

1337raspberry/ramus

Repository files navigation

ramus

ramus

ramus | ra·​mus | a projecting part, elongated process, or branch

CI Release License: MIT Latest release Platforms

ramus main view

About

ramus is a genre-first music client for Plex focused on discovering and exploring your existing library. Out of the box It's designed to function with the Genre and Style metadata plex already fetches for your albums to give you a rich hierarchical tree-like view of your library, while genre-obsessives and taxonomy purists can use their own curated genre tags and a custom built hierarchy to get as specific as they like.

Features

  • Hierarchical browsing - ramus features a tree-like genre browser that automatically matches your existing library. It comes with a custom and rich genre hierarchy by default, but you can build and supply your own, or even download a custom setup built by somebody else
  • Instant locally cached search - Ctrl+F > "free b" > Enter and you're listening to Free Bird. Or just "wonrederwall" and it knows you meant Wonderwall. Also features search operators and shortcuts for power users eg /Dream-Pop AND year:>2013
  • Library filters - Save a custom view and recall it later as an easy-reach bookmark, or download the results to cache for offline listening (with no file size limit). Save all your favourite albums in the dubstep genre as "workout tunes" and download the whole thing for your gym with the dodgy wifi. Or all your favourite tracks in the Showtunes genre in a "Guilty Pleasures" download for your roadtrip.
  • Album-Art focused - Browse by an album art grid instead of boring ol' text lists, and enjoy auto-extracted background and accent colours across the whole interface, making your entire music listening experience cohesive and aesthetic
  • Waveform Seeking - If you have Sonic Analysis enabled on your server, you already have all this wonderful data. Skip past the 6 minute ambient intro straight to the good stuff.
  • Track popularity data - See the top tracks in an album based on crowdsourced popularity data supplied directly via Plex and obtained via users starring their own libraries, or see a unique popularity chart over an albums track listing to get the full picture.
  • A good ol fashioned visualiser and full screen oriented "focus mode" - Watch your music bounce like it's 2003 and you just discovered visualiser plugins.
  • Lyrics courtesy of lrclib - No account needed, open source and a huge number of the lyrics are synced too. All credits to lrclib, support them if you can

Screenshots

Click for some mobile and desktop screenies of the key ramus features
Search with operators

Desktop Search View

Focus / spectrum view

Focus/Visualiser Mode

Artist view

Artist List

Mobile Now Playing

Mobile Now Playing (With Lyrics)

Popularity Charts view

Popularity Charts on Album Details

filters

Library Filters

Notes on AI assisted development

tl;dr It was used (but not exclusively) to make a solodev hobby project take months, not years
ramus (or the dream of it) has been something that i have tried to build for well over a decade. I am a sysadmin by trade so not at all unfamiliar with some scripting, programming and systems hardening, but i am not a software developer. I am not going to pretend to be. If you are and you look at this code, you'll probably very quickly see anything i have written vs what claude has. As for the history of this project, I have dabbled with trying to create this three times now in the past:
  • It first started out as a very rough hacky foobar2000 plugin that i created for myself but ultimately gave up on because it was just really quite awful in practice.

  • Then a few years ago, it was a very rough java proof of concept which worked, but I just didn't have the ability or time to get out of a "okay the genre tree works with my library and it can play music...now what" phase.

  • About a year ago, on and off with the tools and models available then, I started working on a swift based MacOS only version of ramus, and despite being pretty much feature ready and good to go, I ultimately decided to scrap it because over the course of building that, I had learned so much and I knew I could take that learning, and create something far better and multi platform.

Skip forward some more and thanks to rapid recent advancements in genAI coding and that prior learning - have let me finally take this concept, and deliver it into something that I have been using every day now on multiple platforms for a few months. It has been feature complete and "ready to go" for like 150 commits at least iirc, and all I have been doing is polish, security passes, and iterative improvements. This is open source and free, and I have no interest in ever making money for it, but I am proud of it, and I don't want to release something that sucks.

....ethically or philosophically, I think genAI is actually a very good fit for coding, and computers programming computers was probably always going to be the logical conclusion really.

I however have absolutely zero interest in its existence or use in any other creativity etc (not that software development isnt creative but you know what I mean) so all design decisions here were me and if you can't tell by my godawful rambling writing style, so were the docs (mostly, save for the dry architectural stuff). And the logo. All 8 points on that path in illustrator and that one gradient oh yeah that year of graphic design at university is paying off big time.

Download

Pre-built installers are produced by GitHub Actions and attached to each Release.

Platform Artifact Notes
macOS (Apple Silicon + Intel) ramus_<version>_universal.dmg Universal binary. libmpv + ffmpeg/codec stack bundled inside the .app.
Windows 10/11 (x64) ramus_<version>_x64-setup.exe (NSIS) or ramus_<version>_x64_en-US.msi libmpv-2.dll ships next to the executable.
Linux (x86_64) ramus_<version>_<amd64>/<x86_64>.AppImage / .deb / .rpm The AppImage bundles libmpv. The .deb / .rpm depend on the system libmpv2 / mpv-libs package.
Linux (ARM) ramus_<version>_<aarch64>/<arm64>.AppImage / .deb / .rpm The AppImage bundles libmpv. The .deb / .rpm depend on the system libmpv2 / mpv-libs package.
iOS ramus_<version>_ios-adhoc.ipa Ad-hoc signed for manual self side-loading. SideStore install also available via source https://1337raspberry.github.io/ramus.json
Android ramus_<version>_universal.apk Signed multi-ABI APK (arm64-v8a + armeabi-v7a). libmpv + ffmpeg/codec stack bundled inside the APK. Sideload via adb install or your file manager.

⚠️ Releases are currently unsigned or self-signed. As with many open source projects, macOS gatekeeper will quarantine the .app and tell you it's damaged or untrusted; Windows SmartScreen will whine that it's unrecognised, and Android Play Protect will ask to scan it first. The Releases listing will have more specifics on how to deal with these annoyances

Requirements

  • macOS - the bundle is built around a theoretical minimum of 10.13 (High Sierra), but the only versions I've actually run it on are macOS 15 (Sequoia) and newer. Anything older may work, may not - no promises.
  • Windows 10 (x64) or newer; WebView2 runtime (preinstalled on Windows 11; the installer pulls it in on Windows 10).
  • Linux with WebKitGTK 4.1 (most current distributions). The .deb / .rpm need libmpv2 (or mpv-libs) installed; the AppImage doesn't.
  • iOS 17.5 or newer.
  • Android 8.0 Oreo (API 26) or newer.
  • A Plex Media Server you can sign into that has a music library.

Building From Source

Details You'll need:
  • Rust stable (rustup install stable).
  • Node.js 20+ and pnpm.
  • Tauri 2 prerequisites for your platform — follow tauri.app/start/prerequisites.
  • CMake (and ideally Ninja). The focus mode visualiser includes an Opus decoder via the symphonia-adapter-libopus crate, which compiles a vendored libopus C source through cmake at build time. Without it, cargo build will error out partway through opusic-sys.
    • macOS: brew install cmake ninja.
    • Linux (Debian/Ubuntu): sudo apt-get install cmake ninja-build.
    • Linux (Fedora): sudo dnf install cmake ninja-build.
    • Windows: install CMake (or winget install Kitware.CMake / choco install cmake) and make sure it's on PATH. The MSVC build tools you already need for Tauri provide the rest of the C toolchain — Ninja is optional on Windows; CMake will fall back to MSBuild.
  • libmpv in the dev loop:
    • macOS: brew install mpv (provides libmpv.dylib).
    • Linux (Debian/Ubuntu): libmpv-dev libwebkit2gtk-4.1-dev libgtk-3-dev (and build-essential pkg-config if you don't have them already).
    • Linux (Fedora): mpv-devel webkit2gtk4.1-devel gtk3-devel.
    • Windows: the build script downloads a prebuilt LGPL DLL; nothing to install manually.
  • For mobile:
    • iOS — building: Xcode + xcodegen + cocoapods. That's enough for cargo tauri ios build.
    • iOS — deploying to a tethered device (cargo tauri ios dev): also libimobiledevice + ios-deploy (brew install libimobiledevice ios-deploy).
    • Android: Android Studio + the NDK installed via SDK Manager.
git clone https://github.com/1337raspberry/ramus
cd ramus

# Frontend deps (pnpm — install via `brew install pnpm` if you don't have it)
( cd ui && pnpm install )

# Run the desktop app (Rust + React hot-reload)
cargo tauri dev

# Build a release artifact for your current platform
cargo tauri build

Mobile:

# iOS
./scripts/regen-ios-project.sh
cargo tauri ios build

You'll need to sideload this yourself. If demand is there I may put this on the App Store, but I'm not in a rush to pay Apple for the privilege of releasing an open-source, ad-free, zero cost app.

# Android — emulator or connected device
cargo tauri android dev

# Android - apk build to transfer to your device
cargo tauri android build

Pre-flight checks (CI runs the same):

cargo clippy --workspace --all-targets -- -D warnings
cargo test -p ramus-core
( cd ui && pnpm exec tsc --noEmit )

Architecture & Tech Stack

ramus-core/    Rust library — all business logic.
               Plex client, cache (rusqlite + FTS5), sync engine,
               search, genre tree, playback core.
ramus-tauri/   Tauri 2 app shell.
               IPC commands, libmpv FFI, media controls,
               iOS Swift bridge, Android Kotlin bridge.
ui/            React + Vite + Zustand + TypeScript.
plugins/       Tauri plugin: iOS Swift bridge (MPVKit) and
               Android Kotlin bridge (libmpv via Media3 SimpleBasePlayer).
scripts/       Build helpers (libmpv bundling, codesigning,
               license regeneration).

Most behaviour lives in ramus-core and is unit-tested. The Tauri layer is intentionally thin - IPC plumbing on top of the core, plus the platform-specific glue (FFI on desktop, Swift/Kotlin bridges on mobile).


Privacy & Security

  • Plex auth tokens are encrypted at rest with AES-256-GCM, using a key derived (SHA-256) from a stable per-machine identifier:

    • macOS - IOPlatformUUID (read via IOKit).
    • Windows - HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid.
    • Linux - /etc/machine-id.
    • Android - a random UUID generated on first run and stored in the app's sandboxed config dir.
    • iOS is the exception: tokens go directly into the system Keychain (no file, no AES layer), via a Swift KeychainBridge.

    The encrypted blob (tokens.enc) lives in the platform's standard app-data directory and is written atomically (tmp + fsync + rename) with 0o600 permissions on Unix. The threat defense model is "render the file inert if arbitrarily exfiltrated to another machine" - not protection against a local attacker who already has root on the same device. This is the same model (or in some cases, being encrypted is one step better) that most plex clients or even the official plex clients, operate on.

  • No telemetry, no analytics, no crash reporters, no auto-updaters. Not ever. ramus only talks to your Plex Media Server and plex.tv (for OAuth + server discovery). No other connections anywhere.

  • Server auth tokens are kept out of logs and UI. Plex authenticates by query string (?X-Plex-Token=…), and reqwest's error formatter includes the failing URL. ramus redacts both: track URLs are never logged in full (only ratingKey / part-key), and prefetch.rs::redact_reqwest_err() peels the underlying error so download failures don't leak the token in logs. The mobile debug panel (long-press the EQ button) masks X-Plex-Token= and X-Plex-Headers= before rendering anything.

  • Local databases (cache, image cache, audio cache, downloads) live in your platform's standard app-data directory:

    • macOS: ~/Library/Application Support/com.raspsoft.ramus/ (desktop). On iOS, everything lives inside the app's sandboxed container.
    • Windows: %APPDATA%\raspsoft\ramus\.
    • Linux: ~/.local/share/ramus/ (XDG-respecting $XDG_DATA_HOME).
    • Android: app-private storage. network_security_config.xml is setup to permit cleartext HTTP (against android defaults) for LAN addresses only (so you can reach http://192.168.x.x:32400 on your home LAN.)

Contributing

Bug reports, feature requests, and PRs are welcome. Read CONTRIBUTING.md before sending a non-trivial PR - it covers the project layout, the pre-push checks, and a few of the load-bearing constraints around playback timing and the mobile bridges.

Security Reporting

If you've found a vulnerability, please don't open a public issue. See SECURITY.md for the disclosure process and scope. In short: report through GitHub Security Advisories.


Limitations, Known Issues & Planned Improvements

Details
  • The focus mode visualiser does not run/intercept our audio data "live", we need to compute the spectrum data separately. This leads to a slight delay on first song load for it to appear, and a negigible but not-nothing cpu hit. This is a limitation of our broad one-size-fits-all mpv based audio engine. Hooking into the audio stream to do it live would require an entirely new audio engine I believe, and on each front, how we do that depends on per platform so it gets a lot messier. For a feature that's off by default and I imagine most people will ignore, this is an okay compromise for me for now.

  • Because Plex only exposes minimal genre and style data on a standard broad api call, we need to maintain a local db with an initial cache/sync setup phase and deep sync on all albums. Without this we'd lack the data to make the app do the cool stuff it was built to do! This gives us the ability to do our super fast locally cached search as well which is great, and even on massive libraries, connected remotely, the initial sync is only a few minutes. Worth the trade off I think. Incremental syncs after that are genuinely incremental and if nothing changes in your library, are essentially a no-op. If plex ever changes what they serve out by default, we can reconsider this.

  • No playlist support - currently on the fence about if i even want to add this. Depends on demand i suppose.

  • I wouldn't mind improving some of the more hidden/unintuitive ux. I've spent a lot of time making it as obvious and, what i think is as user friendly as possible. But this is still very much a myopic one person project. What is obvious to me might not be obvious to everybody else. I haven't written anything in the way of usage guides because I hope it's all self evident but if people aren't finding features then I'll revisit accordingly.

  • The colour extraction and accent colours still aren't as perfect as I'd like, and there are some edge cases where things aren't as readable as I'd want, but I've done loads of tweaking to try and get to a happy medium, on many different displays, SDR and HDR too. So I might just have to accept that perfect is the enemy of good, or whatever it is they say.

  • Speaking of colour, because we're using tauri, each individual platform uses it's own native webview/kit/etc and each one treats the 4 way background gradient (and dithering/banding reduction of it) differently. Looks great on apple, pretty good on windows, but Webkitgtk on linux is particularly poor tbh. We've got a manual dither pattern only on linux to try and cover that up a bit but its not perfect. How much it bothers you may vary.

  • I want to implement the new JWT short-lived token auth system that plex has recently rolled out, but as far as I can tell it only applies to plex.tv auth, not PMS server auth, so that token is always going to be perma and long standing. Mixing the two isn't ideal and is only really half a solution and requires different approaches to auth depending on what token we are talking about, so when that is fully baked into PMS, i would like to roll that out. No harm in extra hardening.

Trademarks & affiliation

ramus is an independent third-party client. It is not affiliated with, endorsed by, or sponsored by Plex or any of the upstream projects it builds on.


Custom Hierarchy Tool

ramus ships with a small local web UI based tool in tools/genre-editor/ for working on genre trees outside the app. It's standard Python with no extra dependencies needed, just run python3 tools/genre-editor/server.py from the project root and open the link it prints in your web browser.

With it you can::

  • Edit the bundled tree - tweak the default open.json (rename, add AKAs, drag genres around, add/remove children). Useful if you're building from source or forking. Or if you wanna suggest improvements/changes to our built in genre tree - very open to that.
  • Build your own from scratch - start empty and grow a hierarchy that matches how you think about music. Before i started tagging all my music "properly", this is how I did things. I put things into conceptual high level buckets that made sense to me and then drilled down from there. Even if yknow, strictly speaking it was in entirely the wrong place.
  • Share with other people - export the current tree as a plain .txt file in the same format ramus's in-app importer accepts (Settings > Genres > Import). Anyone you send it to can import it, edit it, and export their own version back out. Round-trip preserves AKAs and descriptions. Useful if you maybe wanted to share a specific hierarchy that you've made with a community or tool that has a set genre list, that you and others tag from (eg metal-archives)

See tools/genre-editor/README.md for the full feature list, keyboard shortcuts, and the .txt format spec.


License

ramus is licensed under the MIT License.

Third-party software

ramus links — at runtime, dynamically — against libmpv (LGPL-2.1-or-later) on desktop. libmpv source is available at github.com/mpv-player/mpv; a copy is shipped under licenses/ in every release artifact. You may substitute your own libmpv build by placing it on the dynamic library search path — the search paths are documented in ramus-tauri/src/mpv_ffi.rs.

A handful of bundled Rust crates (notably the symphonia audio decoder family) are distributed under MPL-2.0. MPL-2.0 is file-scope copyleft and does not affect the rest of ramus.

The bundled music genre tree (ramus-tauri/data/open.json) is derived from the beets project's genres-tree.yaml (MIT, © Adrian Sampson) and has been substantially extended. See NOTICE.md.

The full list of third-party Rust crates and npm packages — together with their license texts — is in THIRD_PARTY_LICENSES.md, regenerated from Cargo.lock and ui/pnpm-lock.yaml by scripts/generate-third-party-licenses.py.

Acknowledgements

ramus is proudly built on the open source wonders that are:

About

A genre-first hierarchical music client for Plex.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Contributors