Bit-perfect Qobuz client with a terminal UI (TUI). Linux and macOS.
Hi-res FLAC with no resampling and no DSP in the signal path — output device sample rate and bit depth matched to each track — is the core, non-negotiable requirement.
Early-stage project. qobit is functional but rough around the edges: missing features, no performance optimisations, occasional UI quirks. Expect breakage and breaking changes. Contributions and bug reports welcome.
![]() |
![]() |
![]() |
| Tracks | Artists | Artist detail |
![]() |
![]() |
![]() |
| Albums | Album detail | Queue |
This is a personal project, and there are better-established options:
- qbz by vicrodh
is a serious, mature Qobuz player with a full graphical UI — more complete and
more battle-tested than qobit. qobit borrows a lot of its ideas, especially its
bit-perfect audio strategy (ALSA
hw:/ CoreAudio exclusive mode), which maps directly onto mpv flags here. Credit for the hard-won bit-perfect groundwork goes to qbz. - qobine by SofusA is another terminal-based Qobuz client, and a much more lightweight one than qobit — worth a look if you want something leaner.
qobit exists for one reason: I wanted a Qobuz client that looks fancy on a cyberdeck build — big Kitty-protocol cover art, a rich now-playing panel, the whole thing driven from a terminal. It's a Textual-flavoured reinterpretation with a heavier, image-forward aesthetic, not a replacement for either of the above.
Unofficial client, not affiliated with or endorsed by Qobuz. It talks to the same private API the Qobuz web player uses (the app id and signing secrets are derived from the public web bundle at login, the way most third-party Qobuz clients do). You need your own valid Qobuz subscription; qobit stores nothing server-side and adds no DRM circumvention — it just plays streams your account is already entitled to. Use at your own risk and within Qobuz's terms of service.
- Python 3.11+
- mpv in
$PATH - A valid Qobuz subscription (Hi-Res tier for 24-bit content)
- A terminal that supports the Kitty graphics protocol: kitty, Ghostty, or iTerm2 3.5+
uv tool install .Or for development:
uv sync --group dev
uv run qobitAuthenticate once — this opens a browser to Qobuz and saves the session:
qobit authPick your output device (see Audio device setup for bit-perfect vs. convenience trade-offs):
qobit devices # list mpv audio device IDs
qobit set-device # interactive picker — saves to configThen launch the TUI:
qobit| Key | Action |
|---|---|
1 |
Tracks tab |
2 |
Artists tab |
3 |
Albums tab |
4 |
Playlists tab |
5 |
Search tab |
6 |
Queue tab |
Escape |
Go back / clear filter / focus tab bar |
↑ ↓ ← → |
Move cursor in grids and lists |
PageUp PageDown |
Jump the selection one page in long lists and grids (Tracks, Queue, Artists, Albums) |
Home End |
Jump the selection to the first / last item |
f |
Favourite / unfavourite the highlighted track (in any track list) |
i |
Open the context menu for the highlighted track (Play next / Add to queue / Play radio / Go to artist / Go to album; plus Remove from queue on Up Next rows) |
Enter |
Open selected item or play selected track |
| Key | Action |
|---|---|
Space |
Pause / resume |
[ |
Seek back 10 s |
] |
Seek forward 10 s |
R |
Start a song radio from the current track |
q |
Quit |
Click anywhere on the progress bar in the transport strip to seek to that position.
The Now Playing status sits on the top-left of the transport border; the
current track's audio resolution (e.g. 24-bit · 192 kHz) is shown on the
bottom-right.
On launch, qobit restores the last track you were playing into the transport
bar at the position you left off, paused. Press Space (or click the transport
bar) to resume from there.
Tracks already in your favourites show a ♥ in the Queue, album, and artist
track lists (the Tracks tab is omitted — everything there is a favourite).
Press f on the highlighted track to favourite or unfavourite it: the ♥
appears/disappears. Favouriting a track anywhere adds it to the Tracks tab;
unfavouriting removes it there.
| Key | Action |
|---|---|
s |
Cycle sort key (Date Added → Artist/Name → Title/Album → Year → …) |
r |
Reverse sort direction |
/ |
Open live filter — type to narrow results |
Escape |
Close filter / clear query / go back |
The current filter query is shown in the border subtitle: / query_ while
typing, ⌕ query when the filter is closed but results are still narrowed.
Press Escape again from the filtered view to clear the query and restore all
items.
The Queue tab is split in two. On the left is a timeline: Recently
Played (tracks you've already heard this session, oldest first, ↺) flows
into the now-playing track (accent-highlighted, with a ▶/⏸ icon) and on into
Up Next. The whole thing is one ordered timeline with a cursor on the
now-playing track, so PageUp walks back into history and PageDown down the
queue. Selecting any track just moves the cursor there — nothing is dropped.
Skip forward past a few tracks and they stay put under Recently Played; jump
back to one and the tracks in between return to Up Next and play through again.
This makes the Queue a place to explore a radio station back and forth, not just
a play-through list. Launching an album or playlist from the library still
replaces Up Next; your session's Recently Played survives across those switches.
On the right is the Now Playing panel — the focal point of the page:
large album art, title and artist, album · year, genre · label, and the
artist's biography filling the rest of the space (scroll it with the mouse
wheel). The stream resolution sits on the panel's bottom-right border. Genre,
label, year and bio load from Qobuz the moment a track starts. Playback
position and seeking live in the always-on transport bar at the bottom of every
screen, which mirrors the same track as a mini-player.
On narrow terminals (under ~100 columns) the Now Playing panel is dropped and the timeline takes the full width.
| Key | Action |
|---|---|
c |
Clear the Up Next queue |
X |
Clear Recently Played |
f |
Favourite / unfavourite the highlighted track (or the now-playing track when the Now Playing panel is focused) |
The OS previous media key is context-aware: within the first 3 seconds of a track it restarts it, otherwise it steps back to the previous track in history.
Press R while a track is playing to start a song radio — Qobuz's
similar-track recommendations, seeded from the current track plus what you've
recently heard. It fills Up Next with ~50 suggestions (replacing the current
queue). Enable Endless radio from the command palette (Ctrl+P →
Endless radio) to keep playback going forever: when the queue empties, qobit
automatically refills it with fresh suggestions based on the last track. The
setting persists across launches.
| Key | Action |
|---|---|
/ |
Focus the search input from anywhere on the Search tab |
Enter |
Submit search |
↑ ↓ |
Move through results |
Enter |
Play track / open album / open artist |
qobit play "Daft Punk Random Access Memories" # search and play first result
qobit play "Kind of Blue" --quality FLAC_24_96 # prefer specific quality
qobit auth # authenticate / refresh session
qobit devices # list output devices
qobit set-device # pick and save output device
qobit clear-cache # delete cached cover art from diskqobit's goal is that the DAC receives exactly the bits from the FLAC — no
resampling, no DSP. How you reach that depends on whether you want the DAC to
stay a normal, shareable system device with a volume slider, or to be handed to
qobit exclusively. Pick a device with qobit set-device (switch any time).
| Option | DAC stays in system device list | Volume | Sample rate | Bit-perfect |
|---|---|---|---|---|
| A. PipeWire rate-following (recommended) | ✅ always | ✅ system volume | follows each track | ✅ transparent for ≤24-bit at 100% volume |
B. Exclusive alsa/hw: / coreaudio: |
❌ vanishes while qobit plays | knob only | follows each track | ✅ guaranteed, always |
| C. Plain PipeWire/Pulse | ✅ always | ✅ system volume | resampled to a fixed clock (often 48 kHz) | ❌ |
Point qobit at the ordinary pipewire/... device for your DAC, then let
PipeWire switch its graph clock to match each track instead of resampling to one
fixed rate. By default most distros lock PipeWire to a single rate (e.g.
clock.allowed-rates = [ 48000 ]); unlock the full ladder your DAC supports:
~/.config/pipewire/pipewire.conf.d/10-allowed-rates.conf
context.properties = {
# list the rates your DAC actually supports (see: cat /proc/asound/card*/stream0)
default.clock.allowed-rates = [ 44100 48000 88200 96000 176400 192000 352800 384000 ]
}
then reload PipeWire:
systemctl --user restart pipewire pipewire-pulse wireplumberNow when qobit is the only thing playing, PipeWire reclocks the device to the
file's rate (verify with cat /proc/asound/card*/pcm0p/sub0/hw_params during
playback — rate: should match the track). The DAC stays visible to the whole
system, your normal volume keys work, and for ≤24-bit content at 100% volume the
signal is bit-transparent (PipeWire's internal float32 represents 24-bit
exactly). Caveats: it stops being bit-exact if another app mixes in audio, if
you drop volume below 100%, or for the rare 32-bit-int source — for streaming
FLAC, none of those apply.
Pick a device flagged ♪ in qobit devices / qobit set-device (sorted to the
top):
- Linux: a raw
alsa/hw:CARD=<name>,DEV=0entry. It talks straight to the hardware, bypassing PipeWire/PulseAudio, so mpv negotiates the file's native rate with the DAC. (mpv only ever lists thesysdefault/front/surround/iec958wrappers, so qobit synthesizes the rawhw:entry these don't expose.) - macOS:
coreaudio/<device-uid>— qobit enables Core Audio exclusive/hog mode automatically.
This is the strongest guarantee — nothing can touch the stream — but it's exclusive: while qobit plays, the DAC disappears from the system device list and no other app can use it. Volume comes from the DAC, not qobit: use the unit's volume knob, or your system mixer if the DAC exposes a hardware volume control (many R2R/desktop DACs are knob-only and expose none). qobit has no in-app volume keys.
A pipewire/... or pulse/... device with no rate config change: volume and
system sharing work, but everything is resampled to PipeWire's fixed clock and
converted through float32 — not bit-perfect. This is just Option A without the
allowed-rates drop-in; configure Option A instead.
Which should I pick? Dedicated DAC and you want zero compromise with the unit's knob for volume → B. Everyday desktop where the DAC is also your system output and you want a volume slider → A (audibly identical to B for streaming FLAC). C only if you can't edit PipeWire config.
| Flag | Format |
|---|---|
FLAC_24_192 |
FLAC 24-bit / 192 kHz (default, falls back if unavailable) |
FLAC_24_96 |
FLAC 24-bit / 96 kHz |
FLAC_CD |
FLAC 16-bit / 44.1 kHz |
MP3_320 |
MP3 320 kbps |
Fallback order: FLAC_24_192 → FLAC_24_96 → FLAC_CD.
After playback starts, qobit queries mpv's actual output sample rate via IPC
and compares it to the stream metadata. A ✓ 24/192 bit-perfect badge in the
CLI means the device is receiving exactly the bits from the file with no
resampling.
~/.config/qobit/config.json credentials, audio_device, theme
~/.local/share/qobit/mpv.sock IPC socket (created per playback session)
~/.local/share/qobit/player_state.json last track + position (resumed on launch)
~/.cache/qobit/images/ cached cover art (safe to delete; honours XDG_CACHE_HOME)
GNU General Public License v3.0 — see LICENSE.





