Skip to main content

Discord Rich Presence for Apple Music on Linux

Project description

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 iPhone 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).
  • Forwards track + cover art to Discord via the local IPC socket.
  • Lives in your system tray with Play/Pause/Next/Previous controls.
  • Provides a settings window (PySide6) for everything users typically want to tweak — privacy mode, sources, autostart, Bluetooth device picker.
        ┌─────────────────────────────────────────────────────────┐
        │   Refrain                                               │
        │                                                         │
        │   ┌──────────┐    ┌──────────┐    ┌────────────────┐    │
        │   │  MPRIS   │    │  BlueZ   │    │     Tray +     │    │
        │   │  source  │    │  AVRCP   │    │  Settings UI   │    │
        │   └────┬─────┘    └────┬─────┘    └───────┬────────┘    │
        │        │               │                  │             │
        │        ▼               ▼                  ▼             │
        │   ┌─────────────────────────────────────────────┐       │
        │   │             Background daemon               │       │
        │   └────────────────────┬────────────────────────┘       │
        │                        │                                │
        │                        ▼                                │
        │           Discord Rich Presence (IPC)                   │
        └─────────────────────────────────────────────────────────┘

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) pip install refrain
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 Releases page
From source See below

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.

From source (development)

git clone https://github.com/Rockykln/refrain.git
cd refrain

# On distros that already package Qt-for-Python and dbus-python (Arch, Fedora,
# openSUSE …) a venv with --system-site-packages avoids re-downloading them.
python -m venv --system-site-packages .venv
source .venv/bin/activate

pip install -e .
refrain

If your distro doesn't ship PySide6 or dbus-python, plain python -m venv .venv works too — pip will pull PySide6 from PyPI and build dbus-python against your system's D-Bus headers (libdbus-1-dev on Debian/Ubuntu, dbus-devel on Fedora).

Pip-installed users: get a launcher

When installed via pip rather than a distro package, Refrain doesn't register itself with your application menu. Run once after install:

refrain --install-desktop

This copies the .desktop file and icon to ~/.local/share/applications/ and ~/.local/share/icons/. To undo: refrain --uninstall-desktop.

Tested on

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. Name it whatever you want — 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 → Discord Client ID → paste, Apply.

That's it. The status will appear in Discord on the next track change.

Configuration

Settings live at $XDG_CONFIG_HOME/refrain/config.toml (typically ~/.config/refrain/config.toml). The settings window edits the same file; you almost never need to touch it by hand.

[discord]
client_id = ""                     # paste your own Application ID here

[sources]
mpris_enabled = true
bluetooth_enabled = true
bluetooth_device = ""              # empty = auto-detect, or "AA:BB:CC:DD:EE:FF"

[privacy]
mode = "full"                      # "full" | "minimal" | "off"

[behavior]
autostart = false
notifications = true
cover_art = true
show_buttons = true

[advanced]
poll_interval_ms = 1000
log_level = "INFO"

Tray

Tray menu

Item What it does
♪ Title Currently playing track (read-only)
Artist • Album Currently playing artist + album (read-only)
⏱ X:XX / Y:YY Elapsed time / track length (and remaining)
⏮ Previous Skip backward on the active source
⏵ Play / ⏸ Pause Toggle on the active source (label follows playback state)
⏭ Next Skip forward on the active source
⬆ Update available Only visible when a newer release exists
Settings… Open the settings window
Live log… Open the live-log window
⟳ Restart Refrain Cleanly stop and re-launch (release D-Bus name + RPC, exec the same binary)
Quit Refrain Stop the daemon and exit

Settings

The settings window opens on first launch, and again any time you click Settings… from the tray. Hitting Apply writes the change to config.toml, hides the window, and keeps the daemon + tray running in the background.

General
Settings — General
Discord client ID, privacy, autostart, notifications, cover art
Sources
Settings — Sources
MPRIS / Bluetooth toggles + paired-device picker
Updates
Settings — Updates
Auto-check, last-checked, manual Check for updates now
Advanced
Settings — Advanced
Poll interval, notification delay, cover cache size, log level, live-log, restart

Notifications

When a track changes, Refrain fires a desktop notification with the album cover, song title, artist and album — the same data that's going to your Discord status. Toggle off in Settings → General if you don't want them.

Track-change notification

Updates

Refrain checks the GitHub Releases API once per day on startup. When a newer version exists, the tray menu shows an Update available item that opens this dialog:

Update-available dialog

Behavior is install-type-aware:

  • AppImage — Refrain downloads the new .AppImage from the release assets and replaces the running binary in place (atomic rename), then prompts a restart.
  • pip / venv — runs pip install --upgrade refrain for you.
  • Flatpak / AUR — never modifies system files; surfaces the distro's own upgrade command (flatpak update … / yay -Syu refrain) so the package manager stays in charge.

File locations

What Where
Config $XDG_CONFIG_HOME/refrain/config.toml
Logs $XDG_STATE_HOME/refrain/refrain.log (rotates)
Cover cache $XDG_CACHE_HOME/refrain/covers/*.txt
Autostart $XDG_CONFIG_HOME/autostart/refrain.desktop (when enabled)

Diagnostics — live log

Tray menu → Live log… (or launch with refrain --debug) opens a streaming view of every log line as it happens, color-coded by level and filterable. Same content as ~/.local/state/refrain/refrain.log, but without tailing it from a terminal.

Live-log window

Privacy

The cover-art lookup hits Apple's public iTunes Search API over HTTPS with just the artist + track name. Nothing else leaves your machine — track metadata goes to Discord's local IPC socket, not over the network.

Off privacy mode disables the Discord status entirely while keeping the tray + controls running.

Documentation

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 (including forks) may not be redistributed.
  • ❌ 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).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

refrain-0.2.0.tar.gz (965.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

refrain-0.2.0-py3-none-any.whl (87.2 kB view details)

Uploaded Python 3

File details

Details for the file refrain-0.2.0.tar.gz.

File metadata

  • Download URL: refrain-0.2.0.tar.gz
  • Upload date:
  • Size: 965.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for refrain-0.2.0.tar.gz
Algorithm Hash digest
SHA256 cb1d985db4da2ac9b8a92daa60d262349c3ef22148bd4cc68f9e4941dda5f5fa
MD5 ead6dd051cdfb7d75d05df4749da5e40
BLAKE2b-256 661d2ccccc15c277bea9225e54cb2ddc5a65db3c5b02cc43ac47633061630c50

See more details on using hashes here.

Provenance

The following attestation bundles were made for refrain-0.2.0.tar.gz:

Publisher: release.yml on Rockykln/refrain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file refrain-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: refrain-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 87.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for refrain-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9e8f1a3772c97104e6c2af5b8a4c0474a6b9e04a1032b8eaed7747bd23a2531c
MD5 b75049fe1814e0b7e709471e119596eb
BLAKE2b-256 6da1266012a306bdf1218a38b9e43249d5b47b25d60712bc9127b4dbf517b4bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for refrain-0.2.0-py3-none-any.whl:

Publisher: release.yml on Rockykln/refrain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page