- config: koanf-based loading (defaults → YAML → KINDEXR_ env vars) - db: embedded SQLite migrations with BEGIN/END-aware statement splitter - server: chi router, GET /health returns JSON stats - cmd/kindexr: graceful SIGTERM shutdown - cmd/kindexr-cli: stub - deploy: systemd unit, example config, nginx snippet - all packages covered by race-clean tests
3.3 KiB
Architecture
nzbstr is a two-halves daemon:
- Reader (Phase 1+): subscribes to Nostr relays for kind 2003 (torrent) and kind 2004 (torrent comment) events, indexes them locally in SQLite, and exposes a Torznab-compatible HTTP API.
- Writer (Phase 4+): watches a download client (qBittorrent / Transmission / Deluge) for completed downloads, builds NIP-35 events signed by your npub, and publishes them to configured outbox relays.
Data flow
Sonarr / Radarr / Lidarr / Readarr / Prowlarr
|
v Torznab HTTP/XML
|
+-----------+
| nzbstr |
| reader | <-- subscribes to relays via WebSocket
| writer | --> publishes via WebSocket
+-----------+
^ ^
| |
v v
Nostr relays qBittorrent / Transmission / Deluge
(NIP-35 events) (download client)
Components
cmd/nzbstr — main daemon
Entry point. Loads config, opens the SQLite database (applying any pending migrations), starts the HTTP server, and installs signal handlers for graceful shutdown.
internal/config
koanf-based configuration loading. Load order: compiled-in defaults → YAML file → environment variables (NZBSTR_ prefix). Missing files are silently skipped so the daemon can start with all defaults.
internal/db
SQLite access via modernc.org/sqlite (pure Go, no CGO). Includes an embedded migration runner that applies numbered SQL files from internal/db/migrations/ on startup. Uses WAL journal mode and a single writer connection for safe concurrent reads.
internal/server
chi-based HTTP server. Phase 0 exposes only /health. Phase 1 adds /api?t=caps, /api?t=search, etc.
internal/nostr (Phase 1+)
Relay subscription loop using github.com/nbd-wtf/go-nostr. NIP-77 negentropy bootstrap for efficient historical sync. Parses kind 2003 events into the internal Torrent struct and writes them to SQLite.
internal/torznab (Phase 1+)
chi routes for the Torznab API. Auth middleware validates API keys. Returns XML in Torznab RSS format. Categories mapped from NIP-35 i tags to newznab integer codes.
internal/enrich (Phase 2+)
Title parser (extracts season/episode/quality/source from release names) and TMDB client for backfilling IMDB/TMDB/TVDB IDs on events that lack them.
internal/wot (Phase 3+)
Web-of-Trust filter. Fetches the operator's kind 3 follow list and optionally follows-of-follows to build an allowed-pubkey set. Integrates with NIP-51 curation sets.
internal/publisher (Phase 4+)
qBittorrent / Transmission / watch-dir integration. Polls for completed downloads in the configured category, builds kind 2003 events, signs them via NIP-46 bunker or local key, and publishes to outbox relays.
Storage
Single SQLite file at /var/lib/nzbstr/nzbstr.db. Schema managed by embedded SQL migrations in internal/db/migrations/. FTS5 virtual table on (title, description) with triggers to keep it in sync.
Deployment
Single static binary + systemd unit. No external services required. Sits behind nginx for TLS termination. See deploy/nzbstr.service and deploy/nginx.conf.example.