Documentation
¶
Overview ¶
Package newznab implements core.Indexer against Newznab-compatible Usenet indexers, with per-indexer daily budgets and a result cache.
Index ¶
- func DiscoverProwlarr(ctx context.Context, cfg config.Prowlarr, opts Options) ([]config.Indexer, error)
- func InfoHashFromMagnet(magnet string) string
- func MagnetFor(infoHash, name string, trackers []string) string
- func NormalizeInfoHash(s string) string
- func Test(ctx context.Context, cfg config.Indexer) error
- func TestWithOptions(ctx context.Context, cfg config.Indexer, opts Options) error
- type APIError
- type Backend
- type Caps
- type Client
- func (c *Client) Caps(ctx context.Context) (*Caps, error)
- func (c *Client) Config() config.Indexer
- func (c *Client) Exhausted(ctx context.Context) bool
- func (c *Client) FetchNZB(ctx context.Context, r core.Release) ([]byte, error)
- func (c *Client) Name() string
- func (c *Client) Remaining(ctx context.Context) (Remaining, error)
- func (c *Client) ResolveTorrent(ctx context.Context, r core.Release) (core.Release, error)
- func (c *Client) Search(ctx context.Context, req core.SearchRequest) ([]core.Release, error)
- func (c *Client) SetCacheTTL(d time.Duration)
- func (c *Client) UpdateConfig(cfg config.Indexer)
- type Event
- type Manager
- func (m *Manager) ApplyConfig(cfg config.Config)
- func (m *Manager) Clients() []*Client
- func (m *Manager) FetchNZB(ctx context.Context, r core.Release) ([]byte, error)
- func (m *Manager) Indexers() []core.Indexer
- func (m *Manager) Name() string
- func (m *Manager) Prune(ctx context.Context) (int64, error)
- func (m *Manager) Reload(cfgs []config.Indexer)
- func (m *Manager) Remaining(ctx context.Context) ([]Remaining, error)
- func (m *Manager) ResolveTorrent(ctx context.Context, r core.Release) (core.Release, error)
- func (m *Manager) Search(ctx context.Context, req core.SearchRequest) ([]core.Release, error)
- func (m *Manager) SearchTimings() []SearchTiming
- func (m *Manager) Subscribe(fn func(Event)) func()
- type Options
- type Remaining
- type SearchTiming
- type TorrentMeta
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DiscoverProwlarr ¶
func DiscoverProwlarr(ctx context.Context, cfg config.Prowlarr, opts Options) ([]config.Indexer, error)
DiscoverProwlarr imports enabled Usenet (Newznab) and torrent (Torznab) indexers; torrent indexers get Protocol "torrent" and stream through a debrid provider. Each receives a stable source-scoped ID and its own Ether hit/grab budget, cache and reputation. Prowlarr's /{id}/api alias is intentionally used so ordinary Newznab URL construction and all existing budget enforcement apply unchanged.
func InfoHashFromMagnet ¶
InfoHashFromMagnet extracts the v1 info hash from a magnet URI's xt=urn:btih: parameter; "" when absent.
func NormalizeInfoHash ¶
NormalizeInfoHash returns a lower-case 40-character hex BitTorrent v1 info hash, converting a 32-character base32 hash; "" when s is neither.
Types ¶
type APIError ¶
type APIError struct {
Code int
Description string
Budget bool // daily limit / rate limited; unwraps to core.ErrBudgetExhausted
}
APIError is a typed Newznab error document (<error code=".." description=".."/>) or an HTTP-level failure translated into the same shape.
type Backend ¶
type Backend interface {
Search(ctx context.Context, req core.SearchRequest, reserve func(context.Context, string) error) ([]core.Release, error)
FetchNZB(ctx context.Context, r core.Release, reserve func(context.Context, string) error) ([]byte, error)
ResolveTorrent(ctx context.Context, r core.Release, reserve func(context.Context, string) error) (core.Release, error)
}
Backend searches a site that is not a Newznab API, such as a built-in site run from an owner-installed definition. The Client keeps budgets, the result cache and events around it: a backend calls reserve with "hit" or "grab" before each request that counts against a daily budget.
type Caps ¶
type Caps struct {
ServerTitle string `json:"serverTitle,omitempty"`
ServerType string `json:"serverType,omitempty"`
LimitDefault int `json:"limitDefault,omitempty"`
LimitMax int `json:"limitMax,omitempty"`
SearchAvail bool `json:"searchAvailable"`
SearchParams []string `json:"searchParams,omitempty"`
MovieAvail bool `json:"movieSearchAvailable"`
MovieParams []string `json:"movieParams,omitempty"`
TVAvail bool `json:"tvSearchAvailable"`
TVParams []string `json:"tvParams,omitempty"`
Categories []int `json:"categories,omitempty"`
}
Caps is a parsed Newznab capabilities document.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is one configured Newznab indexer. It implements core.Indexer.
func New ¶
New builds a Client for one indexer. db may be nil (budgets and cache then live in memory).
func (*Client) ResolveTorrent ¶
ResolveTorrent fills a torrent release's InfoHash and MagnetURL by downloading its .torrent link (counting as a grab) when the indexer only supplied a download URL. Releases that already carry both are returned unchanged without a request.
func (*Client) SetCacheTTL ¶
SetCacheTTL changes the result-cache TTL (called on config reload). A negative value disables the cache.
func (*Client) UpdateConfig ¶
UpdateConfig swaps the indexer config (called on config reload).
type Event ¶
type Event struct {
Indexer string
Kind string
Success bool
BudgetExhausted bool
Results int
Duration time.Duration
AverageAge time.Duration
At time.Time
}
Event records one indexer's observed operation; no URLs or keys are exposed.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager holds all configured indexers and spreads searches across them within their budgets. It implements core.Indexer so the resolver can treat the fleet as one indexer; FetchNZB routes by the release's Indexer name.
func NewManager ¶
NewManager builds a Manager from indexer configs.
func (*Manager) ApplyConfig ¶
ApplyConfig reloads indexers and the search-cache TTL from a full config snapshot; subscribe it to config.Store changes.
func (*Manager) Prune ¶
Prune deletes budget rows older than budgetRetentionDays and any expired search-cache rows (normally removed on write, but an idle indexer never writes). It is meant to be called periodically.
func (*Manager) Reload ¶
Reload replaces the indexer set (call on config change). Existing clients with an unchanged ID keep their in-memory caches.
func (*Manager) ResolveTorrent ¶
ResolveTorrent implements the debrid indexer's torrent resolution by routing to the release's originating indexer.
func (*Manager) Search ¶
Search implements core.Indexer: it queries enabled indexers in parallel (up to MaxParallel), letting each client check its cache before budgets, merges by priority order and de-duplicates by normalised name + size.
func (*Manager) SearchTimings ¶
func (m *Manager) SearchTimings() []SearchTiming
SearchTimings returns a copy of the most recent per-indexer search timings.
type Options ¶
type Options struct {
HTTPClient *http.Client
Logger *slog.Logger
SearchCacheTTL time.Duration // <0 disables cache, 0 = default 6h
NZBDir string // directory for downloaded NZBs; "" keeps them in memory only
MaxNZBBytes int64
Now func() time.Time // injected clock (tests)
MaxParallel int // Manager fan-out; 0 = 4
// Backend builds the search backend for an indexer whose Kind is not
// Newznab (built-in sites, internal/cardigann). Nil disables them.
Backend func(config.Indexer) (Backend, error)
}
Options tunes a Client or Manager. Zero values get sensible defaults.
type Remaining ¶
type Remaining struct {
Indexer string `json:"indexer"`
Day string `json:"day"`
HitsUsed int `json:"hitsUsed"`
HitsLimit int `json:"hitsLimit"`
HitsRemaining int `json:"hitsRemaining"`
GrabsUsed int `json:"grabsUsed"`
GrabsLimit int `json:"grabsLimit"`
GrabsRemaining int `json:"grabsRemaining"`
RetryAt int64 `json:"retryAt,omitempty"` // service-reported throttling; automatic retry (Unix seconds)
}
Remaining reports one indexer's budget state for today (UTC). A remaining value of -1 means there is no personal cap; service limits still apply.
type SearchTiming ¶
SearchTiming records the most recent aggregate search's per-indexer cost.
type TorrentMeta ¶
TorrentMeta is what a .torrent file contributes to a release.
func ParseTorrent ¶
func ParseTorrent(data []byte) (TorrentMeta, error)
ParseTorrent computes the info hash (SHA-1 of the bencoded info dictionary) and reads the name and trackers of a .torrent file.