A desktop music player for Linux that plays your Deezer music and your own music files side by side, in one library and one queue.
  • Rust 73.9%
  • Svelte 13.1%
  • TypeScript 9.5%
  • Python 1.5%
  • Kotlin 1%
  • Other 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
SBDeveloper 463f37afe4
Some checks failed
Check / android (push) Has been cancelled
Check / rust (push) Has been cancelled
Check / ui (push) Has been cancelled
Publish plugins / publish (push) Successful in 1m1s
Deezer 0.2.1: radio and recommendations from the track mix
The public API has no /track/{id}/radio: Deezer answers it with a schema
placeholder, so every seed failed and recommendations came back empty
(the section showed while loading, then vanished). Autoplay radio used
the same endpoint. Both now use gw-light song.getSearchTrackMix over the
logged-in session; a stale session still reopens and retries.

The stand-in Deezer answers the track mix instead of the invented radio
fixture, and a test covers Deezer recommendations.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 20:24:03 +02:00
.cargo Initial commit 2026-10-09 20:19:56 +02:00
.forgejo Spotify release: optional client ID, unofficial librespot build channel, README risks 2026-10-16 20:37:24 +02:00
.github/workflows Bump 2026-10-19 20:25:55 +02:00
crates Deezer 0.2.1: radio and recommendations from the track mix 2026-10-24 20:24:03 +02:00
docs Docs: AutoEq on GitHub in the privacy policy, per-headset offer in ADR 0023 2026-10-24 19:24:40 +02:00
plugins Deezer 0.2.1: radio and recommendations from the track mix 2026-10-24 20:24:03 +02:00
scripts Spotify release: optional client ID, unofficial librespot build channel, README risks 2026-10-16 20:37:24 +02:00
src-tauri Tidy the Automatic Handoff code from review 2026-10-24 19:24:40 +02:00
ui Tidy the Automatic Handoff code from review 2026-10-24 19:24:40 +02:00
.gitignore Android fixes 2026-10-12 22:22:24 +02:00
AGENTS.md Bridge plugin over a serial-port capability (#105) 2026-10-24 13:10:43 +02:00
Cargo.lock Bridge plugin over a serial-port capability (#105) 2026-10-24 13:10:43 +02:00
Cargo.toml IOS / Android updates 2026-10-16 15:17:42 +02:00
GLOSSARY.md Docs 2026-10-24 13:10:56 +02:00
LICENSE Initial commit 2026-10-09 20:19:56 +02:00
package-lock.json IOS / Android updates 2026-10-16 15:17:42 +02:00
package.json IOS / Android updates 2026-10-16 15:17:42 +02:00
README.md Docs: accurate Spotify README, Soloist offline, glossary, ADR notes 2026-10-16 21:16:43 +02:00
svelte.config.js Initial commit 2026-10-09 20:19:56 +02:00
tsconfig.json Initial commit 2026-10-09 20:19:56 +02:00
vite.config.ts Initial commit 2026-10-09 20:19:56 +02:00

Medley

A music player for your own music files, with support for external sources like Deezer.

Medley is an open-source music player for Linux, Android, macOS, Windows and iOS. It plays your local music files out of the box, and adds external sources like Deezer as optional plugins you install yourself. Their tracks and your files then live in one library and one queue, with gapless playback, offline tracks, handoff between your devices, and a sandboxed plugin system for everything else. The backend is Rust, the interface is Svelte, and plugins are WebAssembly.

Medley is independent software. It is not made, endorsed or supported by any service an external source connects to. Read External sources: legal and risks before you install one.

Status: early (0.x). It works day to day on Linux and Android. macOS, Windows and iOS builds are experimental. Expect rough edges and breaking changes.

Contents

Features

Library and playback

  • One library for your music folders (MP3, FLAC, WAV, Ogg Vorbis, M4A/AAC/ALAC, AIFF) and, with a streaming plugin installed, that service's favourites, saved albums, followed artists and playlists. It is remembered, so it shows at once and while offline.
  • Search and browse your library, and any streaming service's catalogue: tracks, albums and artists.
  • Playlists of your own, and streaming playlists kept in sync with their service. Sort and filter any playlist page without changing its stored order.
  • A queue with play next, add to queue, shuffle, repeat, gapless playback, optional crossfade (up to 12 seconds) and radio when it runs out.
  • Track matching (optional): the same song from a streaming service and from your files becomes one entry, and you choose which source plays first.
  • Offline tracks: keep streamed tracks in an encrypted cache that only Medley can play. Work offline (or a dropped connection) skips external sources and keeps playing offline tracks and local files.

Everywhere you listen

  • Several devices: pair your computer and phone once, then hand playback over from one to the other (queue, track and position carry on), or control one from the other. No account or server in between.
  • Network players: send audio to Music Assistant players, optionally in low-delay mode.
  • Linux desktop integration: media keys and system media controls (MPRIS), track-change notifications, a system tray (close to tray, launch at login), and content links from installed streaming plugins opening in Medley.
  • Android: the layout adapts to phones and tablets, and music keeps playing in the background with controls in the notification.
  • Themes: light, dark or follow the system, with a choice of accent colours.

Extensible

  • Plugins install from inside the app and work at once, with no restart: external sources, time-synced lyrics, ListenBrainz scrobbling, Discord Rich Presence, internet radio and Music Assistant players. Even local files are a plugin.
  • Automatic updates (Linux): Medley tells you when a new version is out and installs it with one click. Updates are signed.

Medley itself plays your own files. External sources are optional plugins you install from Settings → Sources, and they connect Medley to third-party services. Be aware of what that means:

  • Medley is independent software. It is not made, endorsed or supported by any service a plugin connects to, and their names are trademarks of their owners.
  • A source may use an unofficial interface, the one the service's own apps use. That can go against the service's terms of use, and the service may suspend or close an account that uses it, without notice or refund. You use external sources at your own risk. Read the plugin's description and the service's terms first.
  • It can stop working at any time, whenever the service changes its interface.
  • A paid subscription may be needed. Medley works fully for your own music files without any plugin.
  • Personal use only. A service's music is licensed for you to listen to. Medley does not export or convert tracks, and its offline cache plays only inside Medley. Do not use Medley to copy or share music.
  • Your login stays on your device. A source plugin keeps it in its own private storage and sends it only to its service.
  • Some sources need a key that is not in this repository. See Building and contributing.

Spotify follows the same rules, with the extra notes in Spotify below: the unofficial interface, the account risk and the offline cache are the bullets above, and they apply to it too.

The decision to support such sources, and its tradeoffs, are recorded in ADR 0001; for Spotify, in ADR 0020 and ADR 0021.

Spotify

The optional Spotify plugin is not made, endorsed or approved by Spotify. Please read this before you install it.

  • Spotify Premium only. Without Premium there is no playback.
  • Your library needs your own client ID. Spotify's Web API in developer mode allows only a handful of users per client ID, so a shared one cannot work for everyone. You create an app on Spotify for Developers and enter its client ID in the plugin. A release may embed a default one, but do not count on it.
  • Playback. Spotify has no public stream API. Nothing from Spotify is bundled in any Medley download. The official Linux build can play through Soloist (see below), which includes its pairing screen. The librespot-based playback, which talks to Spotify's private protocol, is only in the unofficial build.
  • The unofficial build is a separate download with a clearly different name (medley-librespot_...), on its own pre-release. It adds librespot. That is unofficial and not sanctioned by Spotify, it can stop working whenever Spotify changes something, and it does not update itself.
  • On Linux Medley can use Soloist, Spotify's official headless client. You download it from Spotify and create your own API key; Medley never bundles it. Soloist builds expire after 90 days, after which you download a new one.
  • Not approved by Spotify. Soloist being Spotify's client does not mean Spotify approves of this integration. Whether using Medley this way is compatible with Spotify's terms is undecided, and this README does not claim either way.
  • You take the risk. Spotify may suspend or close an account that uses it. Offline tracks add to that risk: they are kept in Medley's encrypted cache, which plays only inside Medley.
  • No Radio yet. Spotify closed the recommendations it would need to newer apps.

Medley uses the name "Spotify" only to say which service a plugin connects to, and shows no Spotify logo or colours.

Install

Download the latest version from the releases page.

Platform Download Notes
Linux, any distribution .AppImage Make it executable and run it. Updates itself.
Debian, Ubuntu, Mint, etc. .deb Adds Medley to your applications menu. Asks for a password to update.
Android 7.0 or newer .apk Does not update itself. See below.
macOS, Windows .dmg, -setup.exe Not code-signed. See below.
iOS 15 or newer .ipa Unsigned and untested: you re-sign it yourself. See below.

Linux

# AppImage
chmod +x medley_*_amd64.AppImage
./medley_*_amd64.AppImage

# .deb
sudo apt install ./medley_*_amd64.deb

Android: open medley_*_android.apk on your device. Android asks you to allow installing apps from your browser or file manager the first time. To update, install the newer APK over the old one, or follow the releases with an app like Obtainium.

macOS and Windows: builds are attached to each release. They are not code-signed, so macOS needs right-click → Open the first time, and Windows SmartScreen shows "More info → Run anyway".

iOS: medley_*_ios_unsigned.ipa is not signed, so iOS will not install it as is. Sign and install it with your own Apple ID using a tool such as AltStore or Sideloadly. It is experimental: plugins run in an interpreter there, so they are slower.

Updates (Linux): Medley checks for a new version when it starts and offers to install it. You can also check in Settings → Updates, or turn the check off there. Medley refuses an update that is not signed.

Getting started

  1. Open Settings.
  2. Under Music folders, add the folders with your music. Medley reads their tags and artwork and never changes the files. On Android, Add Music folder adds your device's Music folder; allow access to audio when asked.
  3. Use Search or Library in the sidebar to find something to play.
  4. Optional: to also play from an external source, install it under Settings → Sources (read the legal notes first), then log in under Accounts. Follow the source's instructions there.

Other settings worth a look: the theme under Appearance, the streaming quality, crossfade and output device under Playback, offline storage and Work offline under Offline, and track matching and which source wins when you have the same song twice under Track matching.

Devices

Medley devices on the same network find each other directly, with no account or server in between.

  1. On both devices, open the devices button in the top bar (or Settings → Devices).
  2. On one device, start pairing: it shows a QR code and a short code. Scan the QR code on the other (Android), or type the code. Pairing is the one-time step that makes two devices trust each other.
  3. Paired devices show each other's playback. Use continue here to take over the other device's queue, or hand your own playback to it. You can also play, pause, skip, seek and change the volume of a paired device without moving the audio.

Each device plays with its own accounts and library: tracks it cannot play are matched by ISRC or by title, artist and duration, and skipped when nothing matches. A device only hears handoffs while Medley is running, so open Medley on the phone first. On Android, allow local network access when asked.

Design: ADR 0009, ADR 0010.

Plugins

Settings → Plugins lists the plugins you can install. Before installing, Medley shows what a plugin wants to access (a website, your files) and installs only if you allow that. Plugins run in a sandbox and can reach nothing else.

Plugin What it does
Deezer Your Deezer library, search, playlists and streaming. Needs a Deezer account. See the legal notes.
Spotify Your Spotify library, search, playlists and Liked Songs, and playback in the unofficial build. Premium only. Needs your own client ID. Read Spotify first.
Lyrics Time-synced (or plain) lyrics from LRCLIB in the big player.
Visualizer Bars or a waveform of the music in the big player.
ListenBrainz Scrobbles what you play to ListenBrainz.
Discord Rich Presence Shows what you are playing on your Discord profile.
Internet radio Radio stations from radio-browser.info or a URL.
Music Assistant Plays on your Music Assistant players.

Installing, updating, turning on or off, and uninstalling a plugin take effect straight away, with no restart:

  • Turning off a music Source hides its tracks from your library and stops its track if it is playing. The queue keeps its entries, shown as unavailable. Uninstalling it removes its tracks from your library.
  • Check for updates on the Installed card looks at the registry, and plugins with a newer version show Update to x.y. An update that asks for more access asks you first, and the old version keeps running until you agree. If a new version does not load, the previous one stays.
  • A plugin that cannot load is reported there, and only then does Medley ask you to restart. Plugins that send audio to a network player load at the next start.

Want to write one? A plugin is a WebAssembly module plus a plugin.toml. It can be a Source (a catalogue and audio streams), an Output (a network player) or an extension (lyrics, scrobbling, presence). See docs/plugin-manifest.md, and the plugins in plugins/optional for working examples.

Keyboard shortcuts

Desktop only.

Key Action
Space Play / pause
Ctrl+→ / Ctrl+← Next / previous track
/ or Ctrl+K Search

While you type in a text field, keys it uses are left to it; Ctrl+K works everywhere.

Your data

Medley keeps its library, settings, plugins and offline cache in ~/.local/share/tech.sbdevelopment.medley on Linux. Delete that folder to start over. On Android they are in the app's own storage: clear it under Settings → Apps → Medley → Storage.

Medley has no accounts, ads or analytics. What it sends over the network, and to whom, is in the privacy policy.

How it works

Medley is a Tauri app: a Rust core with a Svelte 5 interface in the system webview.

ui/            Svelte 5 interface
src-tauri/     desktop, Android and iOS shell: commands, MPRIS, updater, system audio, deep links
crates/core/   all app logic: library, queue, player, DSP, offline cache, plugin host
crates/plugin-api/   the contract shared by the host and WebAssembly plugins
plugins/       local files (bundled) and the optional plugins and sources

A few ideas worth knowing:

  • Sources are plugins. Local files and every other Source go through the same contract as a third-party plugin. A Source hands the host an encoded byte stream; the host owns decoding, DSP, output and the offline cache. (ADR 0002)
  • Matching groups, it does not merge. The same song from two Sources is one Recording that holds both Tracks, so you can always un-group it. (ADR 0003)
  • Plugin UI is declarative. Plugins describe a view and Medley renders it natively, so plugins match the app's theme and cannot run script in the interface. (ADR 0005)
  • Devices trust each other directly. Handoff and remote control ride on one-time pairing over the local network.

Domain terms are defined in GLOSSARY.md, and every significant design decision has an ADR in docs/adr.

Building and contributing

You need Rust, Node.js 22.12 or newer, Python 3.11 or newer, the Tauri system dependencies, and both WebAssembly targets (rustup target add wasm32-unknown-unknown wasm32-wasip1):

npm ci
npm run tauri dev        # builds the plugins, then runs the app
npm run tauri build      # Linux .deb and AppImage
cargo test               # core and plugin API tests
npm test                 # UI unit tests
npm run check            # Svelte and TypeScript checks

Some source plugins need a stream secret at build or run time. It is not in this repository (ADR 0008). Without it, everything else works. The Spotify plugin can take a default client ID the same way, but needs none: users enter their own.

Full setup, Android builds, the release process and the repository layout are in docs/development.md.

Contributing: bug reports, ideas and pull requests are welcome in the issue tracker. For anything larger than a small fix, open an issue first so we can agree on the approach. Please use the terms in the glossary, and read the relevant ADR before changing a decision it records.

License

MIT. The license covers Medley's code only, not any music or any streaming service.