Files
soulseek-rs-modded/soulseek-rs
Michel de Graaf 18b53aa4ba fix(tui): keep the login screen responsive while connecting
The login screen ignored every key while a connect+login attempt ran, so
against an unreachable server it sat on a static "Connecting…" for 20s or
more, with a hint promising that Esc would quit.

While connecting it now shows a spinner: Enter or r restarts the attempt,
Esc stops it and returns to the form, q or Ctrl-C quits. Ctrl-C quits from
every state of the screen instead of typing a "c" into a field.

A failure that got no verdict (unreachable, timed out) keeps the password,
so Enter or r retries it; only a rejection, Ok(false) or
AuthenticationFailed, clears it. Because a retry can now reuse a password
that came from the CLI, env or keychain, entered_via_form compares the
credentials with the ones the flow started with instead of trusting any
submit, so a retried stored password is never written to the keychain.

A restart of an attempt younger than a second is ignored: each attempt
rescans the shares and opens a listener, and a held Enter would otherwise
start one per key repeat. The attempt result is read before drawing, so a
key is never handled against a phase the screen did not show.

A stopped or restarted attempt is abandoned, not cancelled: the server
actor blocks its own mailbox in connect_timeout, so a stop could not reach
it sooner. Its thread runs out its timeouts and drops the client, which
disconnects. Until then it holds the listener port, so a restarted session
can fall back to an ephemeral port, and should a slow server accept the
abandoned login after its replacement got in, the late login displaces the
new session. Fixing either needs a cancellable connect, or a bind after the
login verdict, in the library.
2026-09-13 10:13:38 +02:00
..
2026-09-10 12:16:13 +02:00

soulseek-rs

A Soulseek client for the terminal: a full-screen TUI, and a one-shot command surface built for scripts and agents.

Website: https://re-invention.nl/soulseek-rs/

Installation

brew install michel/tap/soulseek-rs   # macOS and Linux, prebuilt
cargo install soulseek-rs             # anywhere with a Rust toolchain

Usage

Run it with no subcommand for the interactive TUI:

soulseek-rs

Anything else is a one-shot command that runs headless. stdout carries records only, stderr carries progress, and the exit code carries the verdict:

soulseek-rs search <QUERY>                # print matching files
soulseek-rs get <QUERY>                   # search, pick the best, download
soulseek-rs download <USER> <PATH>        # fetch one known file
soulseek-rs download --stdin              # fetch files listed on stdin
soulseek-rs browse <USER>                 # list a user's shared files
soulseek-rs serve [--follow]              # stay online sharing, stream uploads
soulseek-rs whoami                        # confirm credentials and connection
soulseek-rs user <NAME>                   # a peer's status and share counts
soulseek-rs room list|say|users|listen
soulseek-rs message send|read
soulseek-rs shares list|add|remove|status|reindex
soulseek-rs config path|list|get|set
soulseek-rs portmap                       # test automatic port mapping
soulseek-rs completions install           # tab completion for bash/zsh/fish

Add --json for newline-delimited JSON instead of tab-separated text, so commands compose:

soulseek-rs search "rjd2" --json \
  | jq -c 'select(.size > 5000000 and .free_slot)' \
  | soulseek-rs download --stdin

Exit codes: 0 success, 2 usage or config, 3 connect or login, 4 nothing found, 5 timed out, 6 transfer failed, 7 session lost mid-command, 1 unexpected error.

The full README documents every command, record shape, flag, environment variable and config.toml key.

Building from Source

git clone https://github.com/michel/soulseek-rs.git
cd soulseek-rs
cargo build --release

Library

To build your own Soulseek client, use the soulseek-rs-lib crate: the protocol implementation this client is built on.