rob thijssen e480ea4ea6
All checks were successful
CI / Format, lint, build, test (push) Successful in 6m1s
CI / Build SRPM (push) Successful in 1m38s
CI / Publish to COPR (push) Successful in 25m1s
fix: switch vortex dependency from fork to upstream
Replace grenade/vortex fork (fix-double-panic branch) with upstream
Nehliin/vortex pinned to rev fbb3da44, which includes PR #129 expanding
piece request validation to prevent the double-panic at its root cause.

Also suppress a11y_click_events_have_key_events warning on the overlay
div in AddTorrent.svelte (keyboard dismiss already handled via
svelte:window keydown).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:41:23 +03:00
2026-04-04 18:40:01 +03:00
2026-04-04 09:30:07 +03:00
2026-04-04 09:30:07 +03:00
2026-04-04 09:30:07 +03:00
2026-04-04 09:30:07 +03:00
2026-04-04 09:30:07 +03:00

Monsoon

Copr build status

A fast BitTorrent client for the GNOME desktop and headless servers, built on the Vortex io-uring engine.

Two interfaces:

  • Desktop app -- Tauri + Svelte GUI with GNOME integration
  • Headless server -- REST API + WebSocket + web GUI for remote/LAN deployment

Install from COPR (Fedora)

sudo dnf copr enable grenade/monsoon
sudo dnf install monsoon          # desktop app
sudo dnf install monsoon-server   # headless server

Screenshots

Torrent List

Torrent list view

Activity

Activity view with speed graph

Details

Torrent details

Files

File listing

Building from Source

Dependencies (Fedora)

sudo dnf install rust cargo gcc nodejs pnpm \
  gtk3-devel webkit2gtk4.1-devel libsoup3-devel \
  pango-devel gdk-pixbuf2-devel glib2-devel libappindicator-gtk3-devel

The GTK dependencies are only needed for the desktop app. The headless server only requires rust, cargo, and gcc.

Desktop App

pnpm install && pnpm build                                # build frontend
cargo build --release -p monsoon --features custom-protocol  # build desktop binary (embeds frontend)

The custom-protocol feature is required for release builds -- it tells Tauri to embed the frontend assets into the binary. Without it, the app expects a local Vite dev server.

For development with hot-reload: cargo install tauri-cli && cargo tauri dev

Headless Server

cd monsoon-web && pnpm install && pnpm build && cd ..
cargo build --release -p monsoon-server

Manual Install

sudo install -Dm755 target/release/monsoon /usr/local/bin/monsoon
sudo install -Dm755 target/release/monsoon-server /usr/local/bin/monsoon-server
sudo install -Dm644 data/cafe.lair.monsoon.desktop /usr/share/applications/cafe.lair.monsoon.desktop
sudo install -Dm644 data/cafe.lair.monsoon.metainfo.xml /usr/share/metainfo/cafe.lair.monsoon.metainfo.xml
sudo install -Dm644 src-tauri/icons/icon.png /usr/share/icons/hicolor/256x256/apps/cafe.lair.monsoon.png
sudo install -Dm644 src-tauri/icons/128x128.png /usr/share/icons/hicolor/128x128/apps/cafe.lair.monsoon.png
sudo install -Dm644 src-tauri/icons/32x32.png /usr/share/icons/hicolor/32x32/apps/cafe.lair.monsoon.png
sudo gtk-update-icon-cache /usr/share/icons/hicolor/

Headless Server

Running

# With web GUI (run from the repo root, or set MONSOON_WEB_DIR)
monsoon-server

# Or with explicit web asset path
MONSOON_WEB_DIR=/path/to/monsoon-web/dist monsoon-server

The server listens on 0.0.0.0:3000 by default. Open http://server-ip:3000 in a browser for the web GUI.

Systemd

sudo install -Dm644 data/monsoon-server.service /usr/lib/systemd/system/monsoon-server.service
sudo systemctl enable --now monsoon-server

REST API

Method Endpoint Description
GET /api/torrents List all torrents
GET /api/torrents/:id Get torrent details
POST /api/torrents Add torrent (JSON: magnet or file path)
POST /api/torrents/upload Upload a .torrent file (multipart)
DELETE /api/torrents/:id Remove torrent
POST /api/torrents/:id/pause Pause torrent
POST /api/torrents/:id/resume Resume torrent
GET /api/config Get server configuration
PUT /api/config Update server configuration

Examples

# Add a magnet link
curl -X POST http://localhost:3000/api/torrents \
  -H "Content-Type: application/json" \
  -d '{"type": "magnet", "magnet": "magnet:?xt=urn:btih:..."}'

# Upload a .torrent file
curl -X POST http://localhost:3000/api/torrents/upload \
  -F "file=@/path/to/file.torrent"

# List torrents
curl http://localhost:3000/api/torrents | jq

# Pause a torrent
curl -X POST http://localhost:3000/api/torrents/TORRENT_ID/pause

WebSocket

Connect to ws://server-ip:3000/ws for real-time event streaming. Events are JSON:

{"type": "metrics", "id": "...", "downloadSpeed": 1234, "uploadSpeed": 56, "numPeers": 12, "piecesCompleted": 42}
{"type": "stateChanged", "id": "...", "newState": "seeding", "name": "..."}
{"type": "metadataComplete", "id": "...", "name": "...", "totalPieces": 100, "totalSize": 1073741824}

Queue Management

Configure in ~/.config/monsoon/config.toml:

[server]
listen_addr = "0.0.0.0:3000"
max_concurrent_downloads = 3
min_peers_before_queue = 2
seed_completed_by_default = true
webhook_url = "http://localhost:8080/hook"
  • listen_addr -- HTTP API and web GUI listen address (default 0.0.0.0:3000)
  • max_concurrent_downloads -- new torrents are queued when all slots are full; the next queued torrent auto-starts when a slot frees up
  • min_peers_before_queue -- if a torrent has fewer peers than this and download speed is below 1 KiB/s for 30 consecutive seconds, it rotates to the back of the queue
  • seed_completed_by_default -- when false, completed torrents are paused instead of seeding
  • webhook_url -- POST a JSON payload to this URL when a torrent completes (for automation: Jellyfin scans, file movers, etc.)

Configuration

Monsoon follows XDG directory conventions:

Purpose Path
Config ~/.config/monsoon/config.toml
Downloads ~/.local/share/monsoon/downloads/
Torrent registry ~/.local/share/monsoon/torrents.json
Logs ~/.local/state/monsoon/monsoon.log
DHT cache ~/.cache/monsoon/dht_bootstrap_nodes

License

GPL-3.0-or-later

Description
No description provided
Readme GPL-3.0 1.3 MiB
Languages
Rust 50.6%
Svelte 38.5%
TypeScript 7.3%
CSS 2.4%
Shell 0.5%
Other 0.6%