Skip to content

Repository files navigation

Refrain

Discord Rich Presence for Apple Music on Linux.

tests codeql security python license

Refrain shows what you're listening to on Apple Music as your Discord status — whether the audio is playing in a browser tab on music.apple.com or streaming from your phone over Bluetooth.

Refrain on Discord

What it does

  • Reads playback metadata from MPRIS (Apple Music in any major Linux browser) and BlueZ AVRCP (any AVRCP-capable Bluetooth source). Firefox and its relatives report the page they play; Chromium-based browsers need KDE's Plasma Browser Integration, which works outside KDE too — see troubleshooting.
  • Forwards track + cover art to Discord via the local IPC socket.
  • Optionally scrobbles to Last.fm alongside Discord (opt-in, with a crash-safe offline queue).
  • Lives in your system tray with Play/Pause/Next/Previous controls.
  • Keeps a recently played list — cover, time, source — of the last 30 songs by default, on your machine only.
  • Provides a settings window (PySide6) for everything users typically want to tweak — privacy mode, sources, autostart, Bluetooth device picker.

Requirements

  • Linux with D-Bus
  • Python ≥ 3.11
  • Discord desktop client running (Refrain talks to its IPC socket)
  • For Bluetooth: BlueZ with AVRCP enabled

Install

Channel Install
PyPI (any distro with Python ≥ 3.11) pipx install --system-site-packages refrain — see below
AUR (Arch / CachyOS / Manjaro / EndeavourOS) yay -S refrain (stable) or yay -S refrain-git (latest main)
AppImage (portable single-file, any glibc-based distro) Download from the latest release, chmod +x, run it
From source See below

The AppImage needs FUSE 2, which current distros no longer install by default: libfuse2t64 on Debian and Ubuntu, fuse-libs on Fedora, libfuse2 on openSUSE, fuse2 on Arch. Without it, start the AppImage with --appimage-extract-and-run.

A Flatpak manifest exists under packaging/flatpak/ for users who want to build it themselves; a Flathub submission is on the roadmap but not currently active. Build files for the live channels live under packaging/. See packaging/README.md for build instructions. Which versions can still be downloaded, and why the others were taken down: docs/releases.md.

From PyPI

Current distros no longer let pip install into the system Python, so install with pipx. dbus-python and PyGObject come from your distro; --system-site-packages lets Refrain use them instead of compiling its own. On Debian and Ubuntu:

sudo apt update && sudo apt install pipx python3-dbus python3-gi libxcb-cursor0
pipx install --system-site-packages refrain
pipx ensurepath   # once, if ~/.local/bin isn't on your PATH yet
refrain --install-desktop

Commands for Fedora and openSUSE, the source build, where the files land and how to remove them again: docs/install.md.

Tested on

See docs/test-matrix.md for the full Tier-1 / Tier-2 list, the per-row smoke checks, and which distros are explicitly out-of-scope.

  • Tier 1 (must pass every release): CachyOS, Arch Linux, Fedora 42, Ubuntu 24.04 LTS, Ubuntu 25.04, Ubuntu 26.04 LTS, Debian 13 (Plasma and GNOME), openSUSE Tumbleweed, Linux Mint 22, Manjaro Stable.
  • Desktops: KDE Plasma 6 (Wayland is the primary target, X11 also covered), GNOME with the AppIndicator and KStatusNotifierItem extension, XFCE / Cinnamon / LXQt / Budgie via their native or AppIndicator-bridged tray, MATE with mate-applet-statusnotifier, tiling WMs (Hyprland / Sway / i3 / river) via a SNI-capable status bar.

First-time setup

Refrain needs a Discord Application ID to push status updates. Each user registers their own (free, takes 30 seconds):

  1. Open https://discord.com/developers/applications and click New Application.
  2. Give it a name you're entitled to use — that name is what shows up under "Listening to ..." in your Discord status. You can also upload a square image as the application icon; Discord uses it as the fallback when there's no album cover.
  3. Copy the Application ID from the General Information page.
  4. Launch Refrain → Settings → General → Application ID → paste, OK.
  5. In Discord: Settings → Activity privacy → Share your detected activities with others. A fresh Discord install has this switch off, and with it off nobody sees your status — Refrain looks connected either way. The Discord desktop app is required; Discord in a browser can't receive a status.

The first time you launch Refrain without a configured ID, the welcome wizard pops up with the setup steps + a live diagnostics panel that probes your D-Bus session and Discord IPC socket so you know up front whether your environment can host the RPC at all.

Welcome wizard

After the wizard, the Status window says You're all set. Play a song and it shows up in Discord within a few seconds.

Last.fm scrobbling

Refrain can scrobble to Last.fm alongside the Discord status — a second, independent channel, never a replacement. It's opt-in and off by default. Register your own free API account, then fill in Settings → Last.fm. The shared secret and session token are stored in your OS keyring, never in config.toml.

Full walkthrough, the scrobble rules and troubleshooting: docs/lastfm.md.

Privacy

Refrain is local-first: no Refrain server, no account, no telemetry, and the author receives nothing. Two lookups are on by default and can be switched off — cover art at Apple and the update check at GitHub. Everything else only runs once you set it up: Discord needs an Application ID, Last.fm is opt-in. Data always goes directly to that provider, never through anything of ours.

Privacy → Off is the global kill switch (no Discord status, no scrobbling) while keeping the tray + controls running. The Recently played list never leaves your machine.

Every data flow, what is kept and for how long, and how to erase it — written to GDPR transparency expectations — is in PRIVACY.md.

Documentation

Using Refrain

When something is wrong

About the project

Contributing

See CONTRIBUTING.md for dev setup, testing, and the source/UI architecture. PRs welcome — especially for distribution packaging (Flatpak, AUR, AppImage) and for additional Bluetooth device shapes.

Contact

License

Refrain License (Use-Only) — see LICENSE.

Refrain is source-available but not open source. In short:

  • Anyone may use, copy, and redistribute the unmodified Software.
  • Anyone may read, study, and reference the source code.
  • Modifications and derivative works may not be redistributed. Forks on GitHub are fine only for preparing a pull request.
  • The "Refrain" name and logo may not be used to imply endorsement of or affiliation with modified versions.

Third-party dependencies (PySide6, pypresence, dbus-python) retain their original licenses (LGPL / MIT).

Legal

Refrain is an independent project. It is not affiliated with, sponsored by, or endorsed by Apple, Discord, Last.fm or KDE, and "Refrain" is not a registered trademark. All product names and trademarks belong to their respective owners and are used only to describe what Refrain interoperates with.

Full notice — trademarks, licence, third-party components, and what data leaves your machine — in LEGAL.md. The same text is reachable inside the app under Settings → Legal.

Stats

Stat Value
Lines of code 13,038
Lines in the repository 87,382
Words in the repository 306,980
Words of documentation 46,967
Automated tests 2,133
Test coverage 100 %
Days since the first release 138
Versions released 24
Downloads 2,676
Commits 213
Languages 16
Runtime dependencies 3
Browsers tested 6 (Chrome, Chromium, Brave, Vivaldi, Firefox, Zen)
Ways to install 3 (PyPI, AUR, AppImage)

As of v0.5.3.

About

Discord Rich Presence and Last.fm scrobbling for Apple Music on Linux – from the browser or your phone over Bluetooth

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages