1b7b70426c
- 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
112 lines
3.5 KiB
Markdown
112 lines
3.5 KiB
Markdown
# Publishing (Writer side)
|
|
|
|
nzbstr's writer side (Phase 4+) watches a download client for completed downloads and publishes them as NIP-35 kind 2003 events to configured Nostr relays.
|
|
|
|
## Overview
|
|
|
|
```
|
|
qBittorrent / Transmission / watch_dir
|
|
|
|
|
v (poll completed downloads in tagged category)
|
|
nzbstr publisher
|
|
|
|
|
v (build kind 2003 event)
|
|
NIP-46 bunker signer OR local nsec
|
|
|
|
|
v (WebSocket publish)
|
|
outbox_relays (e.g. wss://sovbit.host)
|
|
|
|
|
v (also stored locally)
|
|
local SQLite DB
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Enable the publisher in `config.yaml`:
|
|
|
|
```yaml
|
|
publisher:
|
|
enabled: true
|
|
signer:
|
|
mode: "bunker"
|
|
bunker_uri: "bunker://..."
|
|
outbox_relays:
|
|
- "wss://sovbit.host"
|
|
- "wss://relay.damus.io"
|
|
client:
|
|
type: "qbittorrent"
|
|
qbittorrent:
|
|
url: "http://127.0.0.1:8080"
|
|
username: "admin"
|
|
password: "${QBIT_PASSWORD}"
|
|
category: "publish-nostr"
|
|
enrich_before_publish: true
|
|
```
|
|
|
|
## Signing modes
|
|
|
|
### NIP-46 bunker (recommended)
|
|
|
|
Run a self-hosted NIP-46 bunker (e.g. [nsecbunker](https://github.com/kind-0/nsecbunker)) on a trusted machine. nzbstr connects as a client and requests signatures. Your nsec never touches the publishing machine.
|
|
|
|
```yaml
|
|
signer:
|
|
mode: "bunker"
|
|
bunker_uri: "bunker://<pubkey>?relay=wss://relay.example.com&secret=<secret>"
|
|
```
|
|
|
|
### ncryptsec (NIP-49)
|
|
|
|
Encrypted private key stored on disk. nzbstr prompts for the passphrase at startup.
|
|
|
|
```yaml
|
|
signer:
|
|
mode: "ncryptsec"
|
|
ncryptsec: "ncryptsec1..."
|
|
```
|
|
|
|
### Local nsec (not recommended)
|
|
|
|
Unencrypted private key. Only use on air-gapped or fully trusted machines.
|
|
|
|
```yaml
|
|
signer:
|
|
mode: "local"
|
|
nsec: "nsec1..."
|
|
```
|
|
|
|
Set the `nsec` value via environment variable instead of writing it to the config file:
|
|
|
|
```sh
|
|
NZBSTR_PUBLISHER_SIGNER_NSEC=nsec1... nzbstr --config /etc/nzbstr/config.yaml
|
|
```
|
|
|
|
## Download clients
|
|
|
|
### qBittorrent
|
|
|
|
nzbstr polls the qBittorrent Web API for torrents in the configured category (`publish-nostr` by default). Only torrents whose state is `pausedUP` (seeding completed) or `uploading` are considered.
|
|
|
|
Tag your torrents in qBittorrent with the publish category to opt them in. This prevents accidentally publishing everything in your client.
|
|
|
|
### watch_dir (Phase 4+)
|
|
|
|
Drop `.torrent` files into the configured watch directory. nzbstr picks them up, parses the metainfo, builds the event, and publishes. Useful for scripted workflows.
|
|
|
|
## Event construction
|
|
|
|
For each completed download:
|
|
|
|
1. Parse `.torrent` metainfo: extract info-hash, title, file list, tracker list, total size.
|
|
2. If `enrich_before_publish: true`, run the title through the title parser and optionally TMDB lookup to backfill `imdb_id`, `tmdb_id`, `tvdb_id`, season, episode, quality, source.
|
|
3. Build a kind 2003 event with the appropriate `x`, `title`, `file`, `tracker`, `i`, and `t` tags.
|
|
4. Sign via the configured signer.
|
|
5. Publish to all `outbox_relays`.
|
|
6. Store in local SQLite as if ingested (so it appears in your own Torznab results immediately).
|
|
|
|
## Security notes
|
|
|
|
- **NIP-46 bunker on a public-facing seedbox** is the right answer security-wise. Run a self-hosted bunker on a trusted internal machine with nzbstr as a client. Your nsec never leaves the bunker.
|
|
- If you use `local` mode, use `ProtectSystem=strict` in the systemd unit (already set) and ensure the config file has mode 0640 and is owned by the `nzbstr` user.
|
|
- The `category` filter in qBittorrent config is important — do not set it to a category that contains torrents you didn't deliberately choose to publish.
|