docs(readme): document distro install path and demote NixOS to optional aside

This commit is contained in:
beefcarver committed 2026-10-30 04:24:53 +00:00
1 parent 3866f0277c
commit 44cc36a470
1 file changed
+86 -62
+86 -62
View File
@@ -9,33 +9,6 @@ No existing SomaFM client is used: the station list, playlists, song history,
audio control, spectrum visualiser and MPRIS service are all implemented here from audio control, spectrum visualiser and MPRIS service are all implemented here from
the public SomaFM endpoints and open protocols. the public SomaFM endpoints and open protocols.
```
▄▀▀▀ ▄▀▀▄ █▄ ▄█ ▄▀▀▄ SOMA FM RADIO 14:32:07
▀▀▀▄ █ █ █ █ █ █▀▀█ LISTENER SUPPORTED Sat 15 Nov
▄▄▄▀ ▀▄▄▀ █ █ █ █ SAN FRANCISCO vol 70%
● PLAYING Groove Salad · Jens Buchert — Rauschebart
┌ STATIONS ───────────────┐┌ ON AIR ────────────────────────────────────┐
│ ★ ▶ Groove Salad 1.9k ││ ▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄ GROOVE SALAD ● PLAYING│
│ ▶ Drone Zone 812 ││ ▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀ A nicely chilled plate│
│ Secret Agent 420 ││ │
│ Indie Pop Rocks 901 ││ NOW PLAYING 12s ago │
│ … ││ Jens Buchert │
│ ││ Rauschebart │
│ ││ Gravity dj Rusty Hodge │
│ ││ ♪ 1.9k listeners · mp3 · 128k │
│ ││ │
│ ││ LAST PLAYED │
│ ││ 14:29 Alex Cortiz — Room 505 │
│ ││ 14:24 Tosca — Amber November │
└─────────────────────────┘└────────────────────────────────────────────┘
┌ SPECTRUM · MIRROR · SYNC ─────────────────────────────────────────────┐
│ ▁▃▅▇█▇▅▃▁ ▂▄▆█▆▄▂ │
│ ▁▂▄▆██████████████████▆▄▂▁▂▄▆█████████▆▄▂▁ │
│ ▀▄▂▁▂▄▆██████████████████▆▄▂▁▂▄▆█████████▆▄▂▁ │
└───────────────────────────────────────────────────────────────────────┘
space pause · ↑↓ station · enter tune · +/- vol · f ★ · / filter · ? help
```
## Features ## Features
- **Live spectrum analyser** — 72 log-spaced bands with peak caps, a moving - **Live spectrum analyser** — 72 log-spaced bands with peak caps, a moving
@@ -71,41 +44,77 @@ space pause · ↑↓ station · enter tune · +/- vol · f ★ · / filter · ?
## Requirements ## Requirements
Python **3.10+**, plus the tools below. This is a minimum, not a pin: there `somafm-tui` is a normal Python application: there is nothing to compile and
is no `.python-version`, and `uv` can install a compatible interpreter if your no distro-specific packaging. It runs on any Linux distribution with Python
distro ships something older. `shell.nix` provides everything inside an **3.10+** and a few command-line audio tools on `$PATH`.
**FHS environment** (needed because uv installs manylinux wheels such as
NumPy, which expect `libstdc++.so.6` in the standard FHS paths):
| tool | why | | tool | why |
| -------- | ------------------------------------------------------- | | ---- | --- |
| python3 | runtime (CPython 3.10 or newer; no exact version pin) | | `python3` | runtime (3.10 or newer; no exact version pin) |
| uv | installs **all** Python dependencies (see `pyproject.toml`) | | [`uv`](https://docs.astral.sh/uv/) | creates the venv and installs every Python dependency from `uv.lock` |
| mpv | playback + JSON IPC control | | `mpv` | playback and JSON IPC control |
| ffmpeg | muted stream decode (fallback analyser) | | `ffmpeg` | muted stream decode for the fallback analyser |
| pulseaudio | `parec`/`pactl` for the synced monitor capture (works with PipeWire) | | `parec` / `pactl` | synced monitor capture for the spectrum (`pulseaudio-utils`; works with PipeWire) |
| dbus | session bus for MPRIS (`playerctl` included for testing) | | D-Bus session bus | MPRIS desktop media integration (`playerctl` is handy for testing) |
Install these with your package manager. Names are usually:
```bash
# Debian / Ubuntu
sudo apt install python3 mpv ffmpeg pulseaudio-utils dbus playerctl
# Fedora (enable RPM Fusion for ffmpeg if needed)
sudo dnf install python3 mpv ffmpeg pulseaudio-utils dbus-tools playerctl
# Arch / Manjaro
sudo pacman -S python mpv ffmpeg libpulse dbus playerctl
# openSUSE
sudo zypper install python3 mpv ffmpeg pulseaudio-utils dbus-1-tools playerctl
```
For other distributions, install the equivalents. On a headless machine you
can skip the audio/D-Bus tools and use `--no-audio` for a UI-only demo, though
the synced spectrum needs `parec`/`pactl`.
Install `uv` once with the official installer:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
`pipx install uv`, `brew install uv`, or a distro package also work. If your
distro's Python is older than 3.10, let uv manage one: `uv python install 3.12`.
Terminal image rendering uses [Pillow](https://python-pillow.org/) and is Terminal image rendering uses [Pillow](https://python-pillow.org/) and is
implemented directly (Kitty TGP + iTerm2 OSC 1337) — no terminal probing. implemented directly (Kitty TGP + iTerm2 OSC 1337) — no terminal probing.
## Run ## Run
```bash From the repository root, sync the environment and start the app:
nix-shell # enters the FHS dev shell
uv sync
uv run somafm-tui
```
If you used an older `shell.nix` before, recreate the venv once so it picks up
the Nix-provided Python:
```bash ```bash
rm -rf .venv && uv sync uv sync # create .venv and install exactly what uv.lock pins
uv run somafm-tui # run inside that environment
``` ```
> FHS shell.nix files do not support `nix-shell --run "..."`. Enter the shell You do **not** need to activate the venv. `uv run` uses `.venv` automatically,
> interactively and run commands there. and re-syncs it first if `pyproject.toml` or `uv.lock` changed. If you prefer a
traditional shell, run `source .venv/bin/activate` and then `somafm-tui`.
### Keeping the uv environment in sync
`uv sync` is the command to remember. It is incremental, safe to re-run, and
should be run after pulling changes, switching branches, or editing
`pyproject.toml`:
```bash
uv sync # make .venv match uv.lock
uv sync --frozen # strict: fail if uv.lock is out of date, never rewrite it
uv lock --upgrade # refresh uv.lock to the newest allowed versions
uv sync --upgrade # upgrade dependencies and sync .venv in one step
rm -rf .venv && uv sync # last resort if the venv was built by an older Python
```
Useful flags: Useful flags:
@@ -195,14 +204,6 @@ containers, …) MPRIS is skipped and the status bar shows `mpris off`.
## Notes / troubleshooting ## Notes / troubleshooting
- **NixOS: `libstdc++.so.6: cannot open shared object file`** — this is NumPy's
manylinux wheel looking for the C++ runtime. `shell.nix` now uses
`pkgs.buildFHSEnv` and installs `stdenv.cc.cc.lib`, so `nix-shell` puts you in
an FHS root where the wheel loads. If the error persists, your `.venv` was
built against a different Python: `rm -rf .venv && uv sync`.
- **`bwrap: No permissions to create a new namespace`** — FHS shells need
unprivileged user namespaces. They are enabled by default on NixOS; inside a
locked-down container you may need to run the app on the host instead.
- **Artwork shows the mosaic?** Real images are auto-enabled for Kitty, - **Artwork shows the mosaic?** Real images are auto-enabled for Kitty,
iTerm2 and WezTerm. Force a protocol with `SOMAFM_IMAGES=tgp` (Kitty/TGP) or iTerm2 and WezTerm. Force a protocol with `SOMAFM_IMAGES=tgp` (Kitty/TGP) or
`SOMAFM_IMAGES=iterm2` (iTerm2/WezTerm); `SOMAFM_IMAGES=0` forces the ANSI `SOMAFM_IMAGES=iterm2` (iTerm2/WezTerm); `SOMAFM_IMAGES=0` forces the ANSI
@@ -210,9 +211,10 @@ containers, …) MPRIS is skipped and the status bar shows `mpris off`.
`set -g allow-passthrough on`); iTerm2/WezTerm inside tmux default to the `set -g allow-passthrough on`); iTerm2/WezTerm inside tmux default to the
mosaic. Images are cached under `~/.cache/somafm-tui/artwork`. mosaic. Images are cached under `~/.cache/somafm-tui/artwork`.
- **Clock shows UTC?** The clock and song history use the system zone from - **Clock shows UTC?** The clock and song history use the system zone from
`/etc/localtime`; a non-UTC `TZ` overrides it. `nix-shell` can inherit a `/etc/localtime`; a non-UTC `TZ` overrides it. A container or dev shell can
build-time `TZ=UTC`, which the app deliberately ignores. In a container, bind inherit a build-time `TZ=UTC`, which the app deliberately ignores; bind the
the host's `/etc/localtime` or set e.g. `TZ=Europe/Berlin`. host's `/etc/localtime` or set e.g. `TZ=Europe/Berlin` in the shell that
launches the app.
- **MPRIS says off/error?** No session bus. Run from your desktop session - **MPRIS says off/error?** No session bus. Run from your desktop session
(the shell profile picks up `$XDG_RUNTIME_DIR/bus`). `dbus-run-session -- uv (the shell profile picks up `$XDG_RUNTIME_DIR/bus`). `dbus-run-session -- uv
run somafm-tui` starts a private bus for testing, but desktop widgets won't run somafm-tui` starts a private bus for testing, but desktop widgets won't
@@ -238,6 +240,28 @@ containers, …) MPRIS is skipped and the status bar shows `mpris off`.
demo). demo).
- SomaFM is listener-supported: if you enjoy it, [donate](https://somafm.com/support/). - SomaFM is listener-supported: if you enjoy it, [donate](https://somafm.com/support/).
## NixOS (optional aside)
None of the above needs Nix. If you *are* on NixOS, `shell.nix` wraps the same
`uv sync` / `uv run` workflow in an FHS environment, because uv installs
manylinux wheels such as NumPy that expect `libstdc++.so.6` in the usual
`/usr/lib` paths:
```bash
nix-shell # enter the FHS dev shell
uv sync
uv run somafm-tui
```
- If you see `libstdc++.so.6: cannot open shared object file`, make sure you
are inside `nix-shell`, then recreate the venv once with
`rm -rf .venv && uv sync`.
- `nix-shell --run "..."` does not work with FHS `shell.nix` files; enter the
shell interactively and run commands there.
- FHS shells need unprivileged user namespaces. `bwrap: No permissions to
create a new namespace` means they are disabled (for example in a locked-down
container); run the app on the host instead.
## Licence ## Licence
WTFPL — Do What The Fuck You Want To Public License, Version 2. See WTFPL — Do What The Fuck You Want To Public License, Version 2. See