- list_api_keys and delete_api_key DB functions
- API keys section at top of Settings: table of existing keys (masked),
generate new key with label, revoke button per key
- New key displayed once in a green copy box after generation with a
clipboard copy button; not shown again after leaving the page
Track the last seen event timestamp per relay in the DB. On startup,
subscribe to kind 2003 per relay using that timestamp as since instead
of always recomputing from backfill_days. Fresh relays with no stored
timestamp fall back to the full backfill window.
- Follow depth column: badges (you/direct/2nd/—) instead of raw 0/1/2
- Column tooltip explains hop distance in plain English
- Trust override form: "Local override only — nothing is broadcast to Nostr"
- publisher_count stat now counts only publishers with torrents_n > 0;
previously counted every pubkey inserted by the WoT follow-graph
builder which inflated the number with non-publishing follows
- NetworkConfig/ProxyConfig in config.rs: mode=direct|tor|i2p|socks5
with socks5_addr() helper that maps tor→9050, i2p→4446, socks5→url
- build_http_client() routes reqwest through SOCKS5 when configured
- build_nostr_opts() routes nostr-sdk WebSocket connections through
SOCKS5 using Connection::new().proxy(addr)
- Shared http_client passed to Enricher and BlossomClient so proxy
applies to TMDB and Blossom blob fetches as well
- nostr_opts passed to Reader, WotBuilder, ProfileFetcher
- Dashboard: network status card showing proxy mode, listen address,
IPv4/IPv6; relay section now shows X connected / Y configured
- Publishers: rename vouch form to "Override publisher trust", add
clear note that this is local-only (not broadcast to Nostr), explain
WoT comes from NIP-02 kind 3; rename column headers for clarity
- Example and dev configs updated with network.proxy section
relay_url was being destructured as .. and thrown away, so
update_relay_last_event was called with an empty string and
matched no rows. Capture relay_url from the notification and
pass it through so each relay row gets its last_event updated.
NIP-35:
- Accept 64-char SHA256 info hashes (BitTorrent v2) in addition to 40-char SHA1 (v1)
- Parse `size` tag as explicit total size; file-size sum is now a fallback only
- Parse URL hint from third element of `x` tag as blossom_url fallback
- Parse `magnet` tag on ingest and extract trackers from it
- Emit `magnet` tag in published NIP-35 events
NIP-56:
- Handle `e` tags in kind 1984 reports: look up the torrent event's
publisher and penalise them the same as a direct `p` tag report
- BlossomClient: unauthenticated fetch, kind 24242 signed upload
- Parser: capture `url` tag from NIP-35 events as blossom_url
- Reader: spawn background fetch + cache of blob when url tag present
- Writer: include `url` tag in published NIP-35 events when blob uploaded
- Watcher: upload .torrent file to Blossom before publishing, attach URL
- Migration 007: adds blossom_url + torrent_blob columns to torrents
- Route GET /torrent/<info_hash>.torrent serves cached blobs
- Config: blossom.enabled + blossom.server (disabled by default)
insert_torrent now upserts into publishers so torrent authors appear
in the publishers table immediately, making the name/nip05 join work
on the indexed and dashboard pages. Migration 006 backfills existing
torrent pubkeys on fresh DB opens.
Fetch kind 0 metadata events for known publishers in background
batches (150 at a time, hourly). Store name, nip05, picture, about
in new columns (migration 005). UI now shows avatar + display name
instead of raw pubkeys across indexed, dashboard, and publishers views.
Adds the full writer/publisher stack: NIP-35 event signing and relay
delivery, qBittorrent polling with publish-delay queue, lava_torrent
.torrent file parsing, TMDB inline lookup before publish, and
kindexr-cli identity/publish subcommands.
- Migration 003: add wot_level/muted/report_count to publishers;
create curation_items and reports tables
- WoT builder (wot/follows.rs): fetches operator kind-3 contact list
to build depth-1 and depth-2 trust graph; ingests kind-10000 mute
list; runs at startup and refreshes every 24h
- Trust scoring (wot/trust.rs): recomputes trust from wot_level and
report_count after each WoT build
- Reader: subscribes to kind-30004 (curation sets) from configured
pubkeys; subscribes to kind-1984 (reports) from anyone; WoT/block/
mute check gates kind-2003 ingest when wot_only=true; auto-block
publishers that hit report threshold
- Search: curated events (referenced by kind-30004) sort first in
both FTS and full-scan paths
- Publisher CLI: list, info, block, unblock, trust, mute subcommands
- Fix .gitignore: /bin/ not bin/ (was shadowing src/bin/)
- tvsearch/movie/music/book endpoints with ID filters (tvdbid, imdbid,
tmdbid), season/ep, and type-specific default category restrictions
- Title parser (enrich/parser.rs) extracts season, episode, quality,
source from scene-format names; fills DB fields not supplied by tags
- TMDB enricher (enrich/tmdb.rs) runs as background task after insert
when no TMDB ID in event; uses reqwest against TMDB v3 API directly
- Adult content exclusion at ingest via curation.exclude_categories
- Simplified server.rs routing: t= param now part of SearchQuery
- Remove unused tmdb-api alpha crate; use reqwest directly
- fix two stale nzbstr comment refs
- migration 002: drop api_keys.visibility and curation_set
- remove Visibility from APIKey struct, GetAPIKey, CreateAPIKey, CLI
- omit torznab size/seeders/peers attrs when data is absent
- reset relay backoff on successful connection (>= 30s uptime)
- use last_event from relays table as since on reconnect
- fix TestSearchWithResults to actually query the test server DB
Reader (internal/nostr):
- Connects to all configured relays via WebSocket
- Subscribes to kind 2003 (NIP-35) events since (now - backfill_days)
- Parses x/title/file/tracker/i/t tags into DB rows
- Reconnects with exponential backoff (5s → 5min) on disconnect
Torznab API (internal/torznab):
- GET /api?t=caps — XML capabilities doc (exact shape Sonarr expects)
- GET /api?t=search — FTS5 full-text search over title+description
- All other t= types (tvsearch, movie, etc.) route to the same search handler
- API key auth via ?apikey= query param; 401 XML error on missing/bad key
- Magnet links built from info_hash + event tracker tags
DB (internal/db/queries.go):
- InsertTorrent with upsert + related rows (trackers, tags, files)
- Search with FTS5 + optional category filter (parent cat expands to range)
- GetAPIKey, CreateAPIKey, UpsertRelay, UpdateRelaySync/LastEvent
CLI (cmd/kindexr-cli):
- apikey create --label <name> [--visibility all|wot|curated]
Health endpoint now reports live relays_connected count.