f.date/f.ago assumed JS milliseconds, but the backend emits Unix epoch seconds everywhere (created_at, feed lastUpdate, rule lastMatch, …), so every real timestamp rendered as ~20607 days ago (now - ~1.78e9 ms). Treat the formatter input as seconds. Search results show the indexer's pubDate string directly rather than mis-parsing it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| public | ||
| server | ||
| .gitignore | ||
| package.json | ||
| README.md | ||
NAUT — Torrent Console
Naut — short for nautical; a nod to the sea (and "psychonaut"-style explorer of the swarm).
An advanced, power-user-focused web UI for a torrent client, with a fully stubbed server so you can run it and click around immediately. No build step, no npm dependencies — just Node.
node server/index.js # → http://localhost:8088
# or
npm start
PORT=9000 npm start # custom port
The UI requires a login. If you do not configure one, the server prints a
generated password at startup for the default admin user. For a stable public
deployment, set credentials explicitly:
NAUT_AUTH_USER=admin NAUT_AUTH_PASSWORD='change-me' npm start
You can also set NAUT_AUTH_PASSWORD_HASH to a pbkdf2-sha256$... hash emitted
by the same password hashing format used by the server.
The server ships 24 mock torrents in varied states and runs a 1-second simulator that fluctuates speeds, advances downloads, fills the piece map, drifts the swarm, and accumulates session/ratio stats — so the UI is genuinely live, not static.
Design rationale (researched against qBittorrent, Flood, Deluge, Tixati)
Advanced users want information density + fast bulk control. The layout is the classic three-pane "fleet console":
┌──────────────────────────────────────────────────────────────┐
│ Toolbar: add · resume/pause/recheck/delete · queue · filter · ▼▲ rates · 🐢 │
├────────────┬─────────────────────────────────────────────────┤
│ Sidebar │ View tabs: Torrents · RSS · Search · Engine │
│ • Status │ ┌─────────────────────────────────────────────┐ │
│ • Categories│ │ Sortable, multi-select torrent grid │ │
│ • Tags │ │ (progress bars, state dots, tags, columns) │ │
│ • Trackers │ ├─────────────────────────────────────────────┤ │
│ │ │ Detail: General·Trackers·Peers·Content·Pieces│ │
├────────────┴─┴─────────────────────────────────────────────┴─┤
│ Status bar: DHT · port · active · session ▼▲ · ratio · cache · disk │
└──────────────────────────────────────────────────────────────┘
Feature set built for advanced users
- Dense sortable grid — click any header to sort; columns include seeds/peers (connected vs swarm total), availability, ratio, ETA, category, tags, queue #.
- Multi-select + bulk ops — click / Ctrl-click / Shift-click; toolbar and right-click context menu act on the whole selection.
- Detail panel with the five tabs power users live in:
- General — transfer + torrent metadata (pieces, hash, privacy, save/content paths, sequential/super-seed/auto-TMM flags, session totals, time active).
- Trackers — tier, status, seeds/peers/leeches, announce message, plus the DHT/PeX/LSD pseudo-trackers.
- Peers — IP:port, country, client, connection type, BT flag string, progress, per-peer up/down, relevance.
- Content — file tree with per-file priority selector (Skip/Normal/High/Max) and per-file progress/availability.
- Pieces — live piece map (have / downloading / missing).
- Sidebar filters — status (downloading, seeding, completed, active, stalled, paused, errored…), categories, tags, and tracker hosts, each with live counts.
- RSS & automation — feeds, unread articles, and auto-download rules (must/must-not contain, regex, target category + save path, add-paused).
- Integrated search — multi-indexer search with seeds/leeches, one-click add.
- Engine view — bandwidth, connection, queueing, and privacy/BitTorrent (DHT/PeX/LSD, encryption mode, µTP) preferences.
- Alt-speed (🐢) toggle, global rate display vs. limits, resizable detail pane.
- Keyboard shortcuts:
/filter ·Nadd ·Spacepause/resume ·Enterproperties ·Delremove ·Ctrl/⌘-Aselect all ·Escclose.
Architecture
server/
index.js Zero-dependency http server: static + JSON API + SSE stream
data.js Mock fleet generator (torrents, trackers, peers, files, pieces,
categories, tags, RSS feeds/rules, search, preferences)
simulator.js 1 Hz mutation of the fleet + derived global stats
public/
index.html App shell
css/styles.css Dark, dense theme
js/
app.js Controller: state, sidebar, grid, selection, context menu,
views (RSS/Search/Engine), modals, hotkeys, status bar
detail.js Detail panel tabs + live refresh + resize
api.js fetch wrappers + EventSource live stream
format.js bytes/rate/eta/ratio/date/state formatters
plugins.js Frontend plugin registry and extension-point loader
plugins/
plugins.json Plugin manifest
health.js Example plugin
Plugin system
Frontend plugins are ES modules listed in public/plugins/plugins.json. Each
module calls window.Naut.registerPlugin() and can contribute:
views— new top-level tabs in the main tab bar.sidebarSections— new sections in the left sidebar, with optional mount code.detailTabs— new tabs in the selected torrent detail panel.detailPanels— additional information panels appended to the General detail tab.
Minimal plugin:
window.Naut.registerPlugin({
id: 'example',
name: 'Example',
views: [{
id: 'example',
label: 'Example',
render(host, { state, f }) {
host.innerHTML = `<div class="pane">Loaded ${state.snapshot.torrents.length} torrents</div>`;
},
}],
});
Add the module path to public/plugins/plugins.json:
{ "modules": ["/plugins/example.js"] }
API (stub)
| Method | Path | Purpose |
|---|---|---|
| GET | /api/auth/status |
Session state and login metadata |
| POST | /api/login, /api/logout |
Create or clear a session |
| GET | /api/plugins |
Authenticated plugin manifest |
| GET | /api/stream |
SSE — pushes a compact snapshot (~1/s) |
| GET | /api/snapshot |
One-shot snapshot (grid + server stats) |
| GET | /api/meta |
Categories, tags, tracker hosts, prefs, search plugins |
| GET | /api/torrents/:hash |
Full general properties |
| GET | /api/torrents/:hash/{trackers,peers,files,pieces} |
Tab data |
| POST | /api/action |
{action, hashes, params} — pause/resume/recheck/queue/category/limits… |
| POST | /api/delete |
{hashes, deleteFiles} |
| POST | /api/add |
{magnet, name, category, savePath, paused, seqDl, skipCheck} |
| POST | /api/altspeed |
Toggle alternative speed limits |
| GET | /api/rss, /api/rss/rules |
Feeds + auto-download rules |
| GET | /api/search?q= |
Indexer search |
Wiring to a real client
The stub mirrors common client semantics. To go live, replace the handlers in
server/index.js with adapters to a real backend — the shapes map closely to:
- qBittorrent Web API v2 (
/api/v2/torrents/info,/sync/maindata, …) - Transmission RPC (
torrent-get/torrent-set) - Deluge JSON-RPC
Keep the SSE snapshot contract and the frontend needs no changes.