torrenter gui
| android apk | ios app | torrenter cli |
|---|---|---|
|
|
|
No arguments opens the interactive menu (magnet, HTTP, auto-update, seed, download folder). Subcommands:
torrenter magnet "magnet:?xt=urn:btih:…"
torrenter http "https://example.com/large-file.iso"
torrenter magnet "magnet:?xt=urn:btih:…" --dir /tmp/out # one-shot, not saved
torrenter --auto-update # persist: check GitHub Releases on startup (TTY only)
torrenter --no-auto-update
torrenter update # install the latest matching CLI asset now
torrenter mcp # stdio MCP (any host that can spawn a command)While a download runs, type 1 then Enter to pause/resume, or 2 then Enter to stop.
Downloader with two engines, two desktop fronts, an Android sideload APK, an iOS sideload app you build on a Mac, and stdio MCP. Each GitHub Release ships a CLI binary, a native GUI binary (egui), and torrenter-android.apk. There is no iOS IPA on Releases, no App Store listing, and no in-app updater.
- Magnet / torrent — BitTorrent via librqbit
- Direct HTTP(S) — 4-part parallel download with byte-range resume
Output goes to <OS Downloads>/torrenter until you pick another folder. Both fronts show danted4/torrenter vX.Y.Z. Auto-update is off by default.
Pick your OS below. Magnet vs HTTP is in Two download modes.
-
Open the latest GitHub Release.
-
Download the CLI and/or GUI asset:
- CLI:
torrenter-x86_64-unknown-linux-gnu - GUI:
torrenter-gui-x86_64-unknown-linux-gnu
- CLI:
-
Make it executable and put it on your
PATHif you want:chmod +x torrenter-x86_64-unknown-linux-gnu torrenter-gui-x86_64-unknown-linux-gnu
-
GUI only: install GTK 3 and xcb at run time. On Debian/Ubuntu:
sudo apt install libgtk-3-0 libxkbcommon0 libxcb-render0 libxcb-shape0 libxcb-xfixes0
The CLI does not need these.
-
Run:
./torrenter-x86_64-unknown-linux-gnu ./torrenter-gui-x86_64-unknown-linux-gnu
Linux does not show SmartScreen or Gatekeeper. Outbound network is allowed by default on most desktops, so there is usually no popup. If a firewall GUI (ufw, firewalld, a VPN client) asks, click Allow. Share-mode magnets listen on a random high TCP port; a deny-incoming firewall can block seeding even when downloads still work.
No Rust/Cargo is needed at runtime. Building from source is in the Development section.
- Open the latest GitHub Release.
- Download the CLI and/or GUI asset:
- CLI:
torrenter-x86_64-pc-windows-msvc.exe - GUI:
torrenter-gui-x86_64-pc-windows-msvc.exe
- CLI:
- Double-click the
.exe(or run it from PowerShell / Command Prompt).
Important
🚨 Windows SmartScreen will often show Windows protected your PC because the binary is not a Microsoft-signed installer. If you skip the second click below, the app never starts. The .exe did not fail — SmartScreen blocked it.
| Do this or the app never starts | |
|---|---|
| 1️⃣ | Click More options |
| 2️⃣ | Click Run anyway |
Releases are unsigned. If Explorer still blocks the file, right-click it → Properties → check Unblock → OK, then run it again and use More options → Run anyway if SmartScreen appears. Microsoft Defender may scan the first run. Pin-to-taskbar uses the icon baked into the .exe (v3.2.1+).
Note
Windows Defender Firewall often asks for network access on first launch, the first share-mode magnet, and again after an update (the new .exe looks like a different app).
| Do this or peers / share mode stay blocked | |
|---|---|
| 1️⃣ | When Windows asks Allow torrenter to communicate on these networks? (or similar) |
| 2️⃣ | Click Allow (Private networks is enough for most home PCs) |
Do not click Cancel or Don’t allow if you want magnet share mode or incoming peers.
-
Open the latest GitHub Release.
-
Download the asset for your Mac (Apple Silicon
aarch64, Intelx86_64):- CLI:
torrenter-<arch>-apple-darwin - GUI for Launchpad:
torrenter-gui-<arch>-apple-darwin.app.zip - GUI as a naked Mach-O (optional):
torrenter-gui-<arch>-apple-darwin
Releases are unsigned. The GUI updater still downloads the naked
torrenter-gui-*Mach-O (CLI usestorrenter-*). The.app.zipis extra packaging for Launchpad; it is not the updater asset. - CLI:
-
GUI (Launchpad): download the
.app.zip, double-click to unziptorrenter.app, drag it to Applications. GitHub setscom.apple.quarantine:xattr -dr com.apple.quarantine /Applications/torrenter.app open /Applications/torrenter.app
If macOS still blocks it (“Apple cannot check it for malicious software”): right-click torrenter → Open → Open, or System Settings → Privacy & Security → Open Anyway. Spotlight and Launchpad list it after it sits in Applications.
-
CLI / naked GUI:
chmod +x torrenter-aarch64-apple-darwin torrenter-gui-aarch64-apple-darwin xattr -d com.apple.quarantine torrenter-aarch64-apple-darwin xattr -d com.apple.quarantine torrenter-gui-aarch64-apple-darwin ./torrenter-aarch64-apple-darwin ./torrenter-gui-aarch64-apple-darwin
Note
macOS often shows a network access popup on first open and again after an update (a replaced binary is a new app to the OS). Wording varies: would like to find and connect to devices on the local network, or accept incoming network connections.
| Do this or magnet / share traffic is blocked | |
|---|---|
| 1️⃣ | When the network popup appears |
| 2️⃣ | Click Allow |
If you clicked Don’t Allow, open System Settings → Network → Firewall (or Privacy & Security → Local Network) and enable torrenter, then relaunch. Gatekeeper can also return after an update — clear quarantine again if macOS refuses to open the new file.
No Rust/Cargo is needed at runtime. Building from source is in the Development section.
Sideload only — not on Google Play. minSdk 30, ABIs arm64-v8a + x86_64. Same engines and chrome as the desktop GUI: magnet launcher icon, phosphor / amber / ice / scarlet / violet, MAGNET ⇄ HTTP, share/leech (seed ON/OFF), verifying then downloading, queue of four. There is no in-app updater (the APK is not a desktop torrenter-* / torrenter-gui-* asset).
-
Open the latest GitHub Release and download
torrenter-android.apk(debug-signed sideload, arm64 + x86_64). Or build it from this tree (see Development):cargo run --features android-ndk --bin android-ndk cd android && gradle assembleDebug
A local build lands at
android/app/build/outputs/apk/debug/. Copy the APK to the phone (USB, Nearby Share, or a file you trust). -
On the phone: allow Install unknown apps for that source, then open the APK. Play Protect / unknown-source warnings are expected — the build is debug-signed sideload.
-
Grant All files access (required). Output is public
Download/torrenter, same layout as desktop (<name>/for magnets,.resume/for HTTP). -
Allow notifications so the foreground service can keep jobs alive when you leave the app.
-
If Android asks to ignore battery optimizations, allow it. Denying that does not block jobs; OEMs may still freeze seeding.
Leaving the app (Back) keeps live jobs in a foreground service until they finish or you Stop. Reopen the app to restore incomplete jobs (jobs.json in app private storage). A reboot or process kill does not autostart torrenter. Share mode asks the LAN gateway to forward the listen port (UPnP); phones behind CGNAT can still finish at U 0.00 with no inbound peers. Theme and seed live in app preferences, not desktop config.json.
No Rust/Cargo is needed on the phone. Building the APK is in the Development section.
Sideload from this tree onto your iPhone — not the App Store, not a GitHub IPA. min iOS 16, arm64 device + simulator slice. Same engines and chrome as Android (magnet icon, phosphor / amber / ice / scarlet / violet, MAGNET ⇄ HTTP, verifying then downloading, queue of four) with three product cuts: leech only (no share toggle), foreground only (Home stops live jobs; reopen hydrates; tap restart), dest is On My iPhone → torrenter (Documents/torrenter). There is no in-app updater.
You need a Mac, full Xcode from the App Store (Command Line Tools are not enough), Rust 1.85+, and the iPhone on USB. A free Apple ID can sign to that device (the cert expires about every 7 days). Linux and Windows cannot produce an installable iOS app.
-
Install Xcode, open it once, accept the license. Then:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer sudo xcodebuild -license accept sudo xcodebuild -runFirstLaunch cargo run --features ios-xcframework --bin ios-xcframework open ios/torrenter.xcodeproj
-
Unlock the iPhone, tap Trust This Computer if asked. In Xcode’s destination bar pick the real iPhone, not a Simulator.
-
If Xcode says iOS X.Y is not installed with a Get button: click Get and wait (this can be several GB). Play will not work until that finishes. Ignore a yellow Update to recommended settings warning.
-
Left sidebar: click the top blue torrenter project → TARGETS → torrenter → Signing & Capabilities. Check Automatically manage signing. Team: Add Account…, sign in with your Apple ID, then pick Personal Team. You do not need a paid developer program.
-
Click Play. The Keychain dialog wants the Mac login password (not Apple ID, not the iPhone passcode). Prefer Always Allow.
-
First Run often fails with Developer Mode disabled. On the phone: Settings → Privacy & Security, scroll to the bottom (under Security / Lockdown Mode), tap Developer Mode, turn it on, Restart. After unlock, tap Enable / Turn On and enter the phone passcode. iOS search for “Developer” often finds nothing — do not look under General. Then Play again.
-
If the icon is on the home screen but will not open (Untrusted Developer): Settings → General → VPN & Device Management (sometimes Device Management) → the Apple Development / your name entry → Trust. Then open torrenter.
Downloads: Files → Browse → On My iPhone → torrenter. If On My iPhone is missing, enable it under Browse locations. Idle job rows have share for Open In / VLC.
Leaving the app stops live jobs (no Android-style background service). Reopen and tap restart. jobs.json is in Application Support (not in Files). Theme is UserDefaults. Incomplete work resumes from dest / .resume/. Local network permission may appear for magnet/DHT.
torrenter mcp speaks stdio MCP (rmcp). Any host that can spawn a local command can use it (Cursor, Claude Desktop, Cline, Pi, and others). Not an HTTP /mcp URL. Leech-only; same jobs.json as the GUI — do not run both at once. Hydrate forces seed off so a GUI share-mode torrent does not start uploading.
Put torrenter on PATH, then:
{
"mcpServers": {
"torrenter": {
"command": "torrenter",
"args": ["mcp"]
}
}
}Stdout is the protocol; logs go to stderr. There is no install token and no extra binary.
| Magnet / torrent | Direct HTTP(S) | |
|---|---|---|
| Use when | magnet P2P | CDN, mirror, or any direct file URL |
| Input | magnet:?xt=urn:btih:… |
https://example.com/file.iso |
| Engine | librqbit | reqwest + Range: bytes= |
| Parallelism | piece picker | 4 byte-range parts |
| Resume | librqbit on disk under <dest>/<torrent-name>/ |
<dest>/.resume/ part files |
| Peers | live count in the bar | Peers: 0 |
| Upload | Share (default): upload while downloading and keep seeding until Stop. Leech: never upload; stop at 100% | — |
| Fallback | — | single stream if the server ignores ranges |
Magnet links need a 32-character base32 or 40-character hex info hash. .torrent files are not accepted. HTTP names come from Content-Disposition or the URL path (one path component only; . / .. become download.bin).
Single-stream HTTP does not resume. It truncates the destination and starts over.
HTTP pause aborts the live Range body and continues from <dest>/.resume/ on resume. Pause on a single-stream (no Range) download starts that GET over. Stop is honored during HEAD, range probe, part copy, and merge.
Torrent mode uses DHT in memory only. Share (default, seed: on) uploads while downloading, opens an incoming TCP listen on a random high port, and stays connected after 100% until you press 2 or quit — torrenter magnet will not return when the file is complete. Leech (seed: off) never uploads and calls session.stop() at 100%. Each magnet writes into <dest>/<torrent-name>/ (whitespace becomes _). If the magnet has no name, or that folder belongs to a different info-hash, the folder is the hash (or name_hash). Overwrite is allowed only inside that folder so a retry can resume. Closing the CLI drops every seed. Closing the GUI drops live sessions too, then restores the job list on the next launch (share rows that were seeding start seeding again if their files are still in that row’s dest).
The GUI uses the same engines: phosphor / amber / ice / scarlet / violet (last pick saved), magnet/HTTP swap on the URL row, share/leech glyphs, dest path, pause / stop / clear per row. Stop immediately shows clear (and restart). Click a job title to open that row’s folder (the dest saved on the job, not the folder used for new START jobs). The copy icon after the title puts that job’s magnet or HTTP URL on the clipboard. Idle rows use restart (confirm popup with mode, dest, and share/leech). Search filters jobs (Esc clears). At most four downloads run at once; the same magnet or HTTP URL cannot start twice while it is already active. The job list is saved across launches (jobs.json). Live rows continue after a dest check (paused rows start paused and still count toward the 4-run cap). A >0% magnet whose files were moved/deleted, or a live HTTP job without .resume parts, comes back stopped. Seeding still needs the window open; it resumes on the next launch if that row was left seeding.
Opt-in. The updater downloads only https://github.com/danted4/torrenter/releases/download/<tag>/<name> (tag in the path must match the release), checks SHA256SUMS, caps size, and times out. GitHub then 302s to objects.githubusercontent.com; that redirect is followed because the first hop is pinned. The binary uses the same Range transfer as HTTP jobs (gzip/brotli off, exact 206 bodies, merge through a .merge.tmp then rename) but stages beside the running exe — not dest/.resume, and it does not resume a partial install. If the CDN ignores Range, it is a single GET. The GUI install toast shows the job-row progress bar until install finishes; torrenter update uses the CLI bar.
SHA256SUMS is same-publisher integrity, not a signature. A stolen GitHub token can still ship a binary and a matching sums file.
Startup auto-update is skipped when stdin is not a TTY (scripts, pipes). torrenter update always runs when you ask. The GUI binary only replaces itself with torrenter-gui-* assets; the CLI binary only replaces itself with torrenter-* assets. The binary directory must be writable. Auto and manual install are the same: the new Mach-O overwrites this executable (Windows first renames the running file to *.old). Startup deletes leftover *.old, .*.update, .*.update.part-*, merge temps, and .*.sha256sums next to it. If you launched from torrenter.app, that bundle stays; only Contents/MacOS/torrenter-gui is swapped, then Info.plist is restamped and the app is ad-hoc signed again. Other copies (Downloads, an old zip) are not searched or deleted.
[████████████████░░░░] 75% | Peers: 12 | D: 750.45 MB @ 2.5 MB/s | T: 1.0 GB | ETA: 2 minutes
[████████████████████] 100% | Peers: 8 | U: 120.00 MB @ 1.1 MB/s | T: 1.0 GB
flowchart TD
start[torrenter] --> entry{Args?}
entry -->|none| menu{Menu}
entry -->|magnet| torrent
entry -->|http| httpStart
entry -->|update| updater
menu -->|1 Magnet| torrent
menu -->|2 Direct URL| httpStart
menu -->|3 Toggle auto-update| menu
menu -->|4 Update now| updater
menu -->|5 Toggle seed| menu
menu -->|6 Change download folder| menu
subgraph magnetFlow [Magnet]
torrent[librqbit session]
torrent --> dht[DHT in memory no persistence]
dht --> upload{share?}
upload -->|no| leech[disable upload]
upload -->|yes| listen[listen TCP]
leech --> waitComplete[wait_until_completed]
listen --> waitComplete
waitComplete --> after{share?}
after -->|no| stopSession[session.stop]
after -->|yes| seedUntilStop[seed until Stop]
seedUntilStop --> stopSession
stopSession --> magnetDir
end
subgraph httpFlow [Direct HTTP]
httpStart[HEAD plus Range bytes 0-0]
httpStart --> sized{Known size?}
sized -->|no| single[Single GET stream]
sized -->|yes| parts[4 parallel Range parts]
parts --> resumeDir["dest/.resume hashed-url parts"]
resumeDir --> honor{"HTTP 206?"}
honor -->|no| wipe[Wipe parts] --> single
honor -->|short body| fail[Fail incomplete no zero pad]
honor -->|yes| merge[Copy exact bytes to temp then rename]
merge --> httpDir
single --> httpDir
end
magnetDir["dest/torrent-name"]
httpDir["dest"]
updater[GitHub Releases plus SHA256SUMS]
HTTP resume keeps {sha256(url)[0..16]}.part-N plus a small JSON manifest under <dest>/.resume/. Oversized parts are truncated before append; a short 206 is an error, not a zero-filled hole. Merge writes .{filename}.merge.tmp then replaces the final file.
- Download folder:
<OS Downloads>/torrenteruntildownload_diris set (src/paths.rs) - Parallel HTTP parts:
PART_COUNT = 4insrc/http.rs - GUI concurrent jobs: 4
- Progress format:
BAR_TEMPLATEinsrc/progress.rs - HTTP and updater timeouts: 20s connect, 60s between reads
- Auto-update, magnet seed, GUI
theme, GUIglass_tint(macOS only), and optionaldownload_dir:~/.config/torrenter/config.json(macOS:~/Library/Application Support/torrenter/config.json, Windows:%APPDATA%\torrenter\config.json).seeddefaults to on.themeisphosphor,amber,ice,scarlet, orviolet(default phosphor). On macOS,glass_tintis 40–210 (default 60% of that range) and tints the frosted window; native fullscreen locks the wash at 100% without writing that override. Labels and the settings cog keep a light brush-stroke wash behind the glyphs so 0% tint stays readable on a light wallpaper. Windows and Linux stay opaque (no tint slider). On Windows, an existingglass_tintin config is rewritten to 100%. Missingdownload_dirkeeps following the live OS Downloads path. Auto-update stays on the GUI header; theme sits in the cog (tint too, on macOS). - GUI job list:
jobs.jsonin that same folder. Each row keeps its own dest and share/leech. Corrupt files are moved tojobs.json.bak.torrenter mcpuses that same file — see MCP. - Android: dest is always public
Download/torrenter. Job list isjobs.jsonunder the app files dir. Theme and seed are SharedPreferences (theme,seed). Noconfig.json, no glass tint, no updater. - iOS: dest is always
Documents/torrenter(Files: On My iPhone / torrenter). Job list isjobs.jsonunder Application Support. Theme is UserDefaults (theme). Leech only, no seed preference, noconfig.json, no glass tint, no updater.
Rust 1.85+. No tag is required for doc-only changes on main.
git clone https://github.com/danted4/torrenter.git
cd torrenter
cargo build --release
cargo build --release --features gui --bin torrenter-gui
./target/release/torrenter # Windows: .\target\release\torrenter.exe
./target/release/torrenter-gui # Windows: .\target\release\torrenter-gui.exe
# Android (needs rustup Android targets, NDK, cargo-ndk, Android SDK, JDK 17)
cargo run --features android-ndk --bin android-ndk
# AGP 8.7 needs JDK 17 (Java 21+ / 27 fails). Then:
cd android && gradle assembleDebug
# iOS (macOS + full Xcode, rustup iOS targets)
cargo run --features ios-xcframework --bin ios-xcframework
open ios/torrenter.xcodeprojcargo test --all-features
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warningsCI on every push and pull request to main: fmt, clippy (-D warnings), tests on Linux, macOS, and Windows (--all-features so the GUI compiles), the Android ffi cdylib, and on macOS the iOS xcframework plus unsigned Simulator XCTest (FormatTests). Linux CI (and local --all-features builds) need GTK 3 + xcb dev packages: libgtk-3-dev libxkbcommon-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev pkg-config.
Release: git tag vX.Y.Z && git push origin vX.Y.Z (commit must already be on main). That publishes CLI + GUI binaries, macOS torrenter-gui-*.app.zip, torrenter-android.apk, and SHA256SUMS. Doc-only changes on main do not need a tag.
| Problem | Fix |
|---|---|
Invalid magnet URL |
Must start with magnet:?xt=urn: and a 32-char base32 or 40-char hex hash |
| No peers / slow torrent | Wait for DHT; try a seeded magnet; check firewall/UDP |
| Share magnet, no upload | Keep the app open; allow the firewall prompt; leech mode never uploads and does not listen |
Too many open files |
torrenter raises the process limit when it can; otherwise ulimit -n 10240 and retry |
Invalid HTTP(S) URL |
Full http:// or https:// URL required |
| Multipart not used | Server did not return HTTP 206 — single stream is used instead |
| Resume not working (HTTP) | Same URL and same dest folder; state is in <dest>/.resume/ |
| Incomplete part | Server closed a Range early; retry the same URL |
| Linux GUI missing GTK/xcb | Install GTK 3 and xcb (see Linux) |
| GUI list empty after restart | Jobs live in jobs.json next to config.json; a corrupt file is renamed jobs.json.bak |
| Saved row says files missing | Payload is gone from that row’s dest; Restart starts over there, or Clear drops the row |
| GUI says already downloading | Same magnet info-hash or HTTP URL is already active |
| Auto-update did nothing in a script | Startup check is TTY-only; use torrenter update |
| Update hash / URL refused | Asset must be this repo’s release for that tag, with a matching SHA256SUMS line |
| Rust version error | Recent stable toolchain if building from source (rustup update) |
| Windows: “Windows protected your PC” | Click More options, then Run anyway (see Windows). Builds are unsigned; this is expected |
| Windows: firewall / network prompt | Click Allow (see Windows); repeats after updates |
| macOS: cannot be opened / unidentified developer | xattr -dr com.apple.quarantine on torrenter.app or the Mach-O, then right-click Open or Privacy & Security → Open Anyway (see macOS) |
| macOS: local network / incoming connections | Click Allow (see macOS); repeats after updates |
| Linux: no permission popup | Normal — Linux usually allows outbound with no prompt (see Linux) |
| Android: blocked install / Play Protect | Allow install from that source, then open the APK (see Android). Unsigned sideload is expected |
| Android: cannot write downloads | Grant All files access; dest is Download/torrenter |
| Android: jobs die in the background | Allow notifications and ignore battery optimizations; a reboot does not autostart the app |
Android: share magnet, U 0.00 |
Keep the app open; allow UPnP on the LAN; CGNAT still blocks inbound peers |
| iOS: helper fails, no iphoneos SDK | Install full Xcode (not CLT), then sudo xcode-select -s /Applications/Xcode.app/Contents/Developer (see iOS) |
| iOS: Xcode license / first launch | sudo xcodebuild -license accept then sudo xcodebuild -runFirstLaunch |
| iOS: destination says iOS X.Y is not installed | Click Get in Xcode and wait for the platform download |
| iOS: Keychain password rejected | Use the Mac login password, not Apple ID / iPhone passcode; Always Allow |
| iOS: Developer Mode missing in search | Settings → Privacy & Security, scroll to the bottom; not under General |
| iOS: app icon will not open | Settings → General → VPN & Device Management → Trust the developer (see iOS) |
| iOS: cannot install from GitHub | There is no IPA on Releases; build on a Mac (see iOS) |
| iOS: jobs stop when you leave | Expected — v1 is foreground-only; reopen and tap restart |
| iOS: VLC cannot see files | Open Files → On My iPhone → torrenter, or share on the idle row |
Download only content you have the legal right to access. Generic tool — not affiliated with rqbit beyond using their OSS library.



