251 lines
9.0 KiB
Markdown
251 lines
9.0 KiB
Markdown
# furumi
|
|
|
|

|
|
|
|
**Your music. Your devices. Your network.**
|
|
|
|
Furumi is a federated P2P player for your personal music library. Every
|
|
running player is a complete, self-sufficient music library: it can import,
|
|
organize, search, and play your collection without an account, a cloud
|
|
backend, or a central service.
|
|
|
|
Connect Furumi on your desktop, laptop, or another device and they become one
|
|
personal music network. Playback, likes, playlists, and library state can move
|
|
between your devices, while missing tracks can be requested directly from
|
|
another player.
|
|
|
|
Furumi runs on **Linux, macOS, and Windows**.
|
|
|
|
## Why Furumi?
|
|
|
|
Music you own should not disappear because a subscription ended, a catalog
|
|
changed, a service was censored, or a server went offline.
|
|
|
|
Furumi is built around a different model:
|
|
|
|
- your library remains under your control;
|
|
- every player works independently;
|
|
- there is no central account or single point of failure;
|
|
- connecting more players improves availability instead of creating a new
|
|
dependency;
|
|
- federation is optional and simple to configure.
|
|
|
|
A single Furumi instance is already useful. A group of instances becomes a
|
|
resilient network for your music.
|
|
|
|
## How it works
|
|
|
|
Each player maintains its own local library and publishes a searchable view of
|
|
it into Furumi's DHT network. Discovery does not depend on a central index.
|
|
|
|
Clients connect directly over P2P transport built on
|
|
[iroh](https://www.iroh.computer/). Furumi adds a synchronization protocol on
|
|
top of that transport to keep trusted devices consistent even when they are
|
|
not always online.
|
|
|
|
In practice:
|
|
|
|
1. Import music into any Furumi player.
|
|
2. Pair your other players or join a federation network.
|
|
3. Devices discover available libraries through the DHT.
|
|
4. Likes, playlists, playback state, and library metadata synchronize between
|
|
trusted clients.
|
|
5. If a track is missing locally, Furumi can fetch it directly from another
|
|
client.
|
|
|
|
There is no coordination server in the middle. Local players remain usable
|
|
when peers are offline, and the network becomes more capable as peers appear.
|
|
|
|
## The player
|
|
|
|
Furumi includes a full-featured terminal interface for browsing artists and
|
|
releases, searching, managing playlists and the queue, controlling playback,
|
|
inspecting connected devices, and configuring federation.
|
|
|
|
The interface supports keyboard-driven navigation, multi-key combinations,
|
|
context-aware bindings, and user-defined rebinding through TOML. Built-in
|
|
audio visualizations, OS media controls, gapless queue playback, and local
|
|
library management are included. Visualizations are runtime-loadable Rhai
|
|
scripts executed in a resource-limited sandbox, so they can be added or edited
|
|
without rebuilding the player.
|
|
|
|
Optional similarity search calculates versioned embeddings for local tracks
|
|
in the background and keeps them in SQLite. It works offline; after a separate
|
|
privacy consent it can also ask a bounded set of federation peers for matches.
|
|
Compatible peers are selected through signed, anonymous LSH summaries in a
|
|
decentralized DHT; no central recommendation index or shared calibration file
|
|
is required.
|
|
The first selectable model is downloaded on demand and is licensed separately
|
|
by MTG under CC BY-NC-SA 4.0 (a proprietary license is also available from
|
|
MTG); Furumi itself remains WTFPL.
|
|
|
|
## Install
|
|
|
|
### macOS
|
|
|
|
On Apple Silicon Macs, install Furumi from the Homebrew tap:
|
|
|
|
```bash
|
|
brew install house-of-vanity/tap/furumi
|
|
```
|
|
|
|
Run it with:
|
|
|
|
```bash
|
|
furumi
|
|
```
|
|
|
|
### Linux, Windows, and other platforms
|
|
|
|
Download a prebuilt archive from the
|
|
[GitHub releases](https://github.com/house-of-vanity/furumi_tui/releases), or
|
|
build Furumi from source with Rust 1.97 or newer:
|
|
|
|
```bash
|
|
cargo build --release --locked
|
|
./target/release/furumi
|
|
```
|
|
|
|
On Debian or Ubuntu, install the Linux audio build dependencies first:
|
|
|
|
```bash
|
|
sudo apt install libasound2-dev pkg-config
|
|
```
|
|
|
|
Equivalent ALSA development packages are required on other Linux
|
|
distributions. macOS and Windows require no additional system packages.
|
|
|
|
Import a music directory from Furumi's command line:
|
|
|
|
```text
|
|
:import /path/to/music
|
|
```
|
|
|
|
Federation, trusted-device pairing, and key bindings are configured directly
|
|
inside the player.
|
|
|
|
### Manual updates
|
|
|
|
In **Settings → Additional settings → Updates**, select **Check for updates**, then **Install update**
|
|
when a newer stable GitHub release is available. Downloads run in the background.
|
|
After installation, restart `furumi` to use the new version; playback is not
|
|
restarted automatically. Wait for an active update operation to finish before
|
|
quitting.
|
|
|
|
Updates replace the running executable in its installation directory, which
|
|
must be writable by your user. Release archives must include a matching entry
|
|
in the release's `SHA256SUMS` asset. Older releases without it cannot be installed
|
|
through this feature. The updater checks SHA-256 and the executable's format
|
|
and architecture before replacing it. Checksums provide integrity checking,
|
|
not publisher signatures. Settings and the local library are preserved.
|
|
|
|
There are no automatic startup checks. Only the existing release asset naming
|
|
scheme is supported; missing or incompatible platform builds are rejected.
|
|
|
|
The **Additional settings** window also contains the music save directory and
|
|
visualization controls. Use Up/Down (or j/k) to navigate, Enter to select, and
|
|
Esc to return to Settings. Long lists scroll with the selection.
|
|
|
|
### Now playing in tmux
|
|
|
|
While Furumi is running, a second invocation can print a cheap, single-line
|
|
playback snapshot without opening the TUI or library:
|
|
|
|
```bash
|
|
furumi --status
|
|
# ▶ Artist — Track 1:23/4:05
|
|
```
|
|
|
|
For example, add this to `.tmux.conf`:
|
|
|
|
```tmux
|
|
set -g status-interval 1
|
|
set -g status-right '#(furumi --status) | %H:%M'
|
|
```
|
|
|
|
`furumi --status-json` returns the same snapshot as JSON, including playback
|
|
state, title, artist, album, position, duration, and volume. Both commands
|
|
print nothing when Furumi is stopped or no track is loaded. On Linux, Furumi
|
|
also exposes the existing MPRIS player `cy.hexor.furumi`, which can be queried
|
|
with tools such as `playerctl`.
|
|
|
|
## Architecture
|
|
|
|
Furumi is a Rust application built with:
|
|
|
|
- `ratatui` and `crossterm` for the cross-platform TUI;
|
|
- `rodio` for local audio playback;
|
|
- SQLite for the personal library and synchronization state;
|
|
- tract ONNX inference for optional local music embeddings;
|
|
- a dedicated DHT for decentralized discovery;
|
|
- iroh-based P2P streams for client-to-client communication;
|
|
- an offline-tolerant operation log for trusted-device synchronization;
|
|
- Rhai for programmable audio visualizations.
|
|
|
|
More detail is available in [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
|
|
## Contributing
|
|
|
|
Bug reports, design discussions, and patches are welcome. Before submitting a
|
|
change, run:
|
|
|
|
```bash
|
|
cargo fmt --all -- --check
|
|
cargo check --all-targets
|
|
cargo test --all-targets
|
|
```
|
|
|
|
## Playback coordination
|
|
|
|
Connected Devices uses the shared `music_dht::playback` engine from frid.
|
|
Newly started players take an idle/paused output after discovery and become
|
|
controllers when another device is playing. Missing output reports trigger
|
|
automatic failover; concurrent claims converge to one owner. The web gateway
|
|
uses a passive server profile and reports actual browser activity.
|
|
|
|
Only one TUI process may use a device identity. Installed and locally built
|
|
binaries use the same user data directory: close the installed player before
|
|
starting a development build. An OS file lock prevents duplicate coordinators
|
|
and is released automatically on exit or a crash. Older builds do not take
|
|
this lock, so close those explicitly when upgrading.
|
|
|
|
Connected-device polling runs independently per peer, so an offline or stalled
|
|
device does not postpone updates to live players.
|
|
|
|
The existing device menu handles manual transfers. Advanced policy can be set
|
|
in `settings.toml` without changing the UI:
|
|
|
|
```toml
|
|
[playback]
|
|
claim_on_startup = true
|
|
automatic_failover = true
|
|
take_paused_on_startup = true
|
|
discovery_ms = 3000
|
|
owner_timeout_ms = 120000
|
|
```
|
|
|
|
All clients must support the new coordination envelope for eventual single
|
|
output ownership. frid's `PLAYBACK_PROTOCOL.md` describes the protocol, adapter
|
|
contract and rollout. Local Cargo patches are only for development; publish
|
|
frid and bump the client dependency versions before releasing these changes.
|
|
|
|
Run the local protocol checks from the TUI repository:
|
|
|
|
```bash
|
|
cargo test localhost_devices_exchange_state_and_handoff
|
|
python scripts/test_device_interop.py ../furumusic
|
|
```
|
|
|
|
The first test uses real iroh streams, isolated SQLite databases, ownership
|
|
handoff, and a stalled peer. The second builds both player test binaries and
|
|
exchanges their actual JSON messages over `127.0.0.1`: queue metadata,
|
|
bidirectional handoff, pause/seek and duplicate command fencing. It exercises
|
|
the TUI command adapter and web player hub, but does not start a browser or
|
|
PostgreSQL and does not cover web database migrations. Both tests use temporary
|
|
identities and data; no running player or user library is used.
|
|
|
|
## License
|
|
|
|
Furumi is released under the
|
|
[Do What The Fuck You Want To Public License, Version 2](LICENSE).
|