Architecture
High-level picture of how the app is built and why.
Here’s the shape of the whole system — SvelteKit on top, Rust under it, nhentai.net below:
flowchart TD
A[SvelteKit SPA] -->|"invoke()"| B[Rust backend]
A -->|"direct img load"| E[nhentai.net CDN]
B --> C[NhDesktopClient]
C -->|"HTTPS throttled"| D[nhentai.net API]
C -->|"proxy_image fallback"| K[ImageCache cache/images]
B --> F[SQLite database.sqlite]
S[BackgroundService service.rs] -->|"download/prefetch/maintenance/sync/refresh"| C
S --> D
S --> K
Rust owns all networking and local data; the SPA only renders. Images load straight from the
CDNs, with Rust as the proxy fallback — served from the on-disk image cache
(cache/images) when present. A background service (service.rs) runs a throttled worker
queue for gallery downloads, image prefetch, cache/image maintenance, account sync, and
periodic Popular refreshes.
🏗️ Design decisions
- ✅ Cross-platform shell = Tauri 2. Rust backend owns all networking and persistence; the SPA is presentation. Supports Windows, macOS, Linux, Android, and iOS.
- Native packaging & uninstaller. Built with Tauri’s native packaging toolchain:
NSIS (
.exe) with dual per-user and per-machine scopes, enterprise WiX MSI (.msi), DMG, deb, AppImage, APK, and portable zip. - Local-first. No server, no accounts required. Favorites/history/blacklist/settings and
the cache live on-device in an ambiguous
database.sqlitedatabase; an optional nhentai.net API key adds account sync. - Images = direct + proxy fallback, URLs derived from the API. URLs are built from the
API’s relative path fragments (
image.tspagePath/thumbPath/avatarUrl);<img>loads from the*.nhentai.netCDNs first, andproxy_image(Rust, served from the disk image cachecache/images) returns bytes →blob:URL if the CDN 404s. - Blacklist is two layers. Server-side
-tag:excludes in every query, plus client-side hide/blur in grids, plus a master toggle. See Blacklist. - Plain CSS tokens, native titlebar & floating navigation. Custom design system in
src/lib/design/tokens.css+app.cssadhering strictly to nhentai’s dark palette (#141414/#1f1f1f/#ed2553), native OS window decorations with an in-app.top-bar, and a floating Mihon-style bottom navigation bar with a 4px corner radius and Dynamic UI Scaling. - Official archive downloads & background services.
service.rsleverages nhentai API v2’s dedicated archive endpoint (POST /api/v2/galleries/{id}/download) to download pre-built ZIP/CBZ archives directly with streaming progress, falling back gracefully to page assembly if unauthenticated. The worker queue also manages image prefetch, cache/image maintenance, account sync, and periodic Popular refreshes with job persistence across restarts indatabase.sqlite(downloads:jobs). - Configurable storage budget & LRU image cache.
image_cache.rsstores fetched images undercache/images. Background service evicts oldest files down to 85% of user-configured budget (500 MB to Unlimited) and runs SQLiteVACUUMcompaction. - Dual-mode account authentication. Dedicated
LoginModal.sveltesupports both official API Keys (recommended, Cloudflare-safe) and direct credentials (POST /api/v2/auth/login), backed by reactive Svelte 5 runes getters inaccount.svelte.tsfor live username and avatar rendering.
⚡ Frontend → Backend contract
- ⚡ Frontend calls typed commands through
src/lib/client.ts(a thininvoke()wrapper) andsrc/lib/api.ts(the higher-level typed API surface). - Command names are snake_case (
fetch_new,search_galleries,proxy_image,get_storage_stats, …); the full list lives in Backend (Rust). - Background jobs use the
service_*commands (service_enqueue_download, …) and stream progress to the SPA asservice://job/service://refreshTauri events. - Errors cross the bridge as
Result<_, String>(never Rust panics) and render as friendly notice components.
🦀 Backend → nhentai.net
- 🦀 All requests go through
NhDesktopClient(reqwest,rustls, gzip). ATHROTTLEdelay between requests respects the site’s public API (seenh_desktop.rs). No hammering. Ever. - Type-accurate serde models mirror the API JSON.
💾 Persistence model
| Store | Location | Purpose |
|---|---|---|
| Favorites / history / blacklist / settings | database.sqlite (SQLite kv table) |
user state, runes-backed |
| Cache mirror + API key | database.sqlite (SQLite) |
fast startup, offline-ish lists, key at-rest |
| Download jobs | database.sqlite (downloads:jobs) |
persistent queue surviving app restarts |
| Image cache | cache/images (data dir) |
disk cache backing proxy_image, pruned by LRU maintenance |
| Downloads | downloads/ (data dir) |
ZIP/CBZ archives from background-service downloads |
🤝 Related pages
📚 Documentation Index
- Core: Home · Getting Started · Installation & Maintenance
- App Features: Search & Filters · Blacklist · Favorites & History · Reader & Galleries · Settings & API Key · Localization
- Architecture & Development: Architecture · Backend (Rust) · Frontend (SvelteKit) · Packaging & Bundling · Development & Contributing
- Reference: Security · Privacy · Troubleshooting · FAQ
NH Reader — a lightweight, modern, cross-platform client for nhentai.net.
Documentation Home · Repository · Releases · Security · Privacy · TOS · License