Help us shape the future of Go! Take the 2026 Go Developer Survey

cardigann

package
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: GPL-3.0 Imports: 44 Imported by: 0

Documentation

Overview

Package cardigann runs owner-supplied indexer definitions written in the Cardigann YAML format (the format Prowlarr and Jackett use for their built-in sites). Ether ships the engine only: no site definitions are bundled. Definitions are installed by the owner, either uploaded or fetched from a definitions source the owner configures, and stored in the database.

A configured indexer of kind "cardigann" is searched through newznab.Client's pluggable backend, so built-in sites share Ether's daily budgets, result cache, reputation events and manager fan-out with Newznab and Torznab indexers.

Index

Constants

This section is empty.

Variables

View Source
var ErrCaptcha = errors.New("the site's sign-in requires a captcha, which Ether cannot solve")

ErrCaptcha reports a login that needs a captcha.

View Source
var ErrCloudflare = errors.New("site is protected by a browser challenge")

ErrCloudflare reports a site behind a Cloudflare (or similar) browser challenge that could not be passed.

View Source
var ErrLogin = errors.New("sign-in failed")

ErrLogin reports credentials or a session the site rejected.

View Source
var ErrNoSource = errors.New("no definitions source is set")

ErrNoSource reports that no definitions source is configured.

View Source
var ErrUnknownDefinition = errors.New("definition is not installed")

ErrUnknownDefinition reports a definition id that is not installed.

Functions

This section is empty.

Types

type Caps

type Caps struct {
	// CategoryMappings maps a site category id to a Newznab category.
	CategoryMappings []CategoryMapping
	Modes            map[string][]string
	AllowRawSearch   bool
}

Caps is the definition's capabilities block.

type CatalogEntry

type CatalogEntry struct {
	ID        string `json:"id"`
	File      string `json:"file"`
	Installed bool   `json:"installed"`
	// UpdateAvailable is set when the installed copy came from this source
	// at a different revision.
	UpdateAvailable bool   `json:"updateAvailable,omitempty"`
	URL             string `json:"-"`
	SHA             string `json:"-"`
}

CatalogEntry is one definition a source offers.

type CategoryMapping

type CategoryMapping struct {
	ID      string
	Cat     string // Newznab category name, e.g. "Movies/HD"
	Desc    string
	Default bool
	Newznab int // resolved Newznab category id; 0 when Cat is unknown
}

CategoryMapping is one caps.categorymappings (or legacy caps.categories) entry.

type Definition

type Definition struct {
	ID              string
	Name            string
	Description     string
	Language        string
	Type            string // public, semi-private, private
	Encoding        string
	Links           []string
	LegacyLinks     []string
	FollowRedirect  bool
	TestLinkTorrent bool
	RequestDelay    float64 // seconds between requests
	// Protocol is "torrent" (the Cardigann default) or "usenet" for a site
	// whose downloads are NZB documents. Definitions may declare
	// `protocol: usenet`; anything else is a torrent site.
	Protocol string
	Caps     Caps
	Settings []Setting
	Login    *Login
	Search   Search
	Download *Download
}

Definition is a parsed Cardigann indexer definition.

func Parse

func Parse(data []byte) (*Definition, []string, error)

Parse decodes and validates a definition. Problems that make the definition unusable are returned as an error; unsupported optional features are returned as warnings.

func (d *Definition) SiteLink(override string) string

SiteLink returns the base URL requests resolve against: the owner's choice when set, else the definition's first link. Always ends in "/".

func (*Definition) SupportsMovies

func (d *Definition) SupportsMovies() bool

SupportsMovies reports whether the definition maps any movie category (or maps no categories at all).

func (*Definition) SupportsTV

func (d *Definition) SupportsTV() bool

SupportsTV reports whether the definition maps any TV category (or maps no categories at all).

type Download

type Download struct {
	Selectors []Selector
	Method    string
	Before    *Request
	InfoHash  *InfoHashBlock
}

Download is the definition's download block.

type ErrorBlock

type ErrorBlock struct {
	Path     string
	Selector string
	Message  *Selector
}

ErrorBlock detects an error page: when Selector matches, the request failed with Message (or the matched element's text).

type Field

type Field struct {
	Name      string
	Modifiers []string
	Selector  Selector
}

Field is one search.fields entry; Name may carry "|modifier" suffixes.

type Filter

type Filter struct {
	Name string
	Args []string
}

Filter is one filter step.

type HandlerDeps

type HandlerDeps struct {
	// Indexers returns the configured indexers (to refuse removing a
	// definition that is in use).
	Indexers func() []config.Indexer
	// Unredact restores secrets the UI sent back as placeholders.
	Unredact func(config.Indexer) config.Indexer
}

HandlerDeps are the owner API's links to configuration.

type HeaderKV

type HeaderKV struct {
	Name   string
	Values []string
}

HeaderKV is one header with its (templated) values.

type InfoHashBlock

type InfoHashBlock struct {
	Hash              Selector
	Title             Selector
	UseBeforeResponse bool
}

InfoHashBlock builds a magnet from a page's hash and title.

type KV

type KV struct {
	Key   string
	Value string
}

KV is an ordered key/value pair.

type Login

type Login struct {
	Path              string
	SubmitPath        string
	Method            string // post, form, cookie, get, oneurl
	Form              string
	Inputs            []KV
	SelectorInputs    []NamedSelector
	GetSelectorInputs []NamedSelector
	Cookies           []string
	Headers           []HeaderKV
	Error             []ErrorBlock
	Test              *LoginTest
	Captcha           bool
}

Login describes how to establish a session with the site.

type LoginLock

type LoginLock func(ctx context.Context, key string) (unlock func(), err error)

LoginLock serialises logins for one key across every Ether node sharing the database. unlock must be called once the login state is saved.

type LoginTest

type LoginTest struct {
	Path     string
	Selector string
}

LoginTest verifies an established session.

type NamedSelector

type NamedSelector struct {
	Name     string
	Selector Selector
}

NamedSelector is a selector bound to an input name.

type Option

type Option struct {
	Value string `json:"value"`
	Label string `json:"label"`
}

Option is one value of a select setting.

type Options

type Options struct {
	DB *sql.DB // nil keeps definitions and sessions in memory
	// HTTPClient supplies the transport and timeout for site, definitions
	// source and FlareSolverr requests (tests inject fakes).
	HTTPClient *http.Client
	Logger     *slog.Logger
	Now        func() time.Time
	// LoginLock serialises logins per indexer across nodes; nil uses an
	// in-process lock.
	LoginLock LoginLock
	Sites     config.IndexerSites
	// Sealer protects stored login cookies; nil stores them as given.
	Sealer config.FieldSealer
}

Options configures a Service.

type Request

type Request struct {
	Path   string
	Method string
	Inputs []KV
}

Request is a templated HTTP request (download.before).

type Reserver

type Reserver func(ctx context.Context, kind string) error

Reserver reserves one unit of an indexer's daily budget ("hit" or "grab") before a request that counts against it.

type Response

type Response struct {
	Type             string // html (default), json, xml
	NoResultsMessage string
}

Response describes how to parse a search response.

type Rows

type Rows struct {
	Selector                        string
	After                           int
	Remove                          string
	DateHeaders                     *Selector
	Count                           *Selector
	Multiple                        bool
	MissingAttributeEqualsNoResults bool
	Attribute                       string
	Filters                         []Filter
}

Rows selects result rows from a response.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner executes one configured indexer's definition. It is safe for concurrent use.

func (*Runner) Definition

func (r *Runner) Definition() *Definition

Definition returns the runner's definition.

func (*Runner) FetchNZB

func (r *Runner) FetchNZB(ctx context.Context, rel core.Release, reserve Reserver) ([]byte, error)

FetchNZB downloads a Usenet site's NZB (one grab).

func (*Runner) ResolveTorrent

func (r *Runner) ResolveTorrent(ctx context.Context, rel core.Release, reserve Reserver) (core.Release, error)

ResolveTorrent fills a torrent release's info hash and magnet, downloading its .torrent (one grab) when the result had only a link.

func (*Runner) Search

func (r *Runner) Search(ctx context.Context, req core.SearchRequest, movieCats, tvCats []int, reserve Reserver) ([]core.Release, error)

Search runs a request's attempts in order and returns the first non-empty result set.

func (*Runner) Test

func (r *Runner) Test(ctx context.Context) (TestResult, error)

Test signs in afresh (when the site needs it) and runs a sample search for the latest releases.

type Search struct {
	Paths                []SearchPath
	Inputs               []KV
	Headers              []HeaderKV
	KeywordsFilters      []Filter
	PreprocessingFilters []Filter
	Rows                 Rows
	Fields               []Field
	Error                []ErrorBlock
	AllowEmptyInputs     bool
}

Search is the definition's search block.

type SearchPath

type SearchPath struct {
	Path           string
	Method         string
	Inputs         []KV
	InheritInputs  bool
	Categories     []string
	FollowRedirect bool
	Response       Response
}

SearchPath is one request issued per search.

type Selector

type Selector struct {
	Selector          string
	Attribute         string
	Remove            string
	Filters           []Filter
	Case              []KV
	Optional          bool
	Text              string
	HasText           bool
	Default           string
	HasDefault        bool
	UseBeforeResponse bool
}

Selector is a Cardigann selector block.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service manages installed definitions and the runners of configured built-in indexers.

func New

func New(o Options) *Service

New builds a Service.

func (*Service) ApplyConfig

func (s *Service) ApplyConfig(cfg config.Config)

ApplyConfig takes the definitions source and FlareSolverr settings from a config snapshot; subscribe it to config changes.

func (*Service) Backend

func (s *Service) Backend(cfg config.Indexer) (newznab.Backend, error)

Backend implements newznab.Options.Backend for built-in indexers.

func (*Service) Catalog

func (s *Service) Catalog(ctx context.Context, refresh bool) ([]CatalogEntry, error)

Catalog lists the definitions the configured source offers, marking installed ones. refresh bypasses the hour-long cache.

func (*Service) Definition

func (s *Service) Definition(ctx context.Context, id string) (Summary, error)

Definition returns one installed definition.

func (*Service) Definitions

func (s *Service) Definitions(ctx context.Context) ([]Summary, error)

Definitions lists installed definitions by name.

func (*Service) Handler

func (s *Service) Handler(deps HandlerDeps) http.Handler

Handler serves the owner API for built-in indexers:

GET    /definitions            installed definitions
POST   /definitions            install an uploaded definition {"yaml": "..."}
GET    /definitions/{id}       one installed definition
DELETE /definitions/{id}       remove a definition no indexer uses
GET    /catalog[?refresh=1]    the definitions source listing
POST   /catalog/install        install {"id": "..."} from the source
POST   /update                 refresh definitions installed from the source
POST   /test                   test an indexer config (saved or not)
GET    /status                 last test result per indexer

func (*Service) Install

func (s *Service) Install(ctx context.Context, data []byte, origin, sha string) (Summary, error)

Install validates and stores a definition (replacing one with the same id). origin is the URL it came from ("" for an upload).

func (*Service) InstallFromSource

func (s *Service) InstallFromSource(ctx context.Context, id string) (Summary, error)

InstallFromSource downloads one definition from the source and installs it.

func (*Service) MigrateSecrets added in v0.2.4

func (s *Service) MigrateSecrets(ctx context.Context, indexers []config.Indexer) (int, error)

MigrateSecrets seals login cookies stored in plaintext, bound to each configured built-in indexer's site origin, drops plaintext cookies of indexers no longer configured, and returns how many rows it changed. Indexers whose definition cannot be loaded keep their row for a later run (reported in the error).

func (*Service) Remove

func (s *Service) Remove(ctx context.Context, id string) error

Remove deletes an installed definition.

func (*Service) Statuses

func (s *Service) Statuses(ctx context.Context) ([]TestStatus, error)

Statuses returns the last test result of every tested indexer.

func (*Service) Test

func (s *Service) Test(ctx context.Context, cfg config.Indexer, record bool) TestResult

Test signs in with cfg (saved or not) and runs a sample search. With record set (a saved indexer) the result is kept for the indexer list.

func (*Service) Update

func (s *Service) Update(ctx context.Context) (UpdateReport, error)

Update refreshes every definition installed from a source. Uploaded definitions are left alone.

type Setting

type Setting struct {
	Name     string   `json:"name"`
	Type     string   `json:"type"`
	Label    string   `json:"label,omitempty"`
	Default  string   `json:"default,omitempty"`
	Defaults []string `json:"defaults,omitempty"`
	Options  []Option `json:"options,omitempty"`
}

Setting is one owner-editable setting a definition declares.

func (Setting) Info

func (s Setting) Info() bool

Info reports whether the setting is read-only guidance text.

func (Setting) Secret

func (s Setting) Secret() bool

Secret reports whether the setting holds a credential.

type Summary

type Summary struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Description string    `json:"description,omitempty"`
	Language    string    `json:"language,omitempty"`
	Type        string    `json:"type,omitempty"`
	Protocol    string    `json:"protocol"`
	Links       []string  `json:"links"`
	Settings    []Setting `json:"settings"`
	Movies      bool      `json:"movies"`
	TV          bool      `json:"tv"`
	Login       string    `json:"login,omitempty"`
	Source      string    `json:"source"` // "upload" or "source"
	Warnings    []string  `json:"warnings,omitempty"`
	InstalledAt time.Time `json:"installedAt"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

Summary describes an installed definition for the owner UI.

type TestResult

type TestResult struct {
	OK      bool     `json:"ok"`
	Results int      `json:"results"`
	Titles  []string `json:"titles,omitempty"`
	Error   string   `json:"error,omitempty"`
}

TestResult is the outcome of an indexer test.

type TestStatus

type TestStatus struct {
	IndexerID string    `json:"indexerId"`
	OK        bool      `json:"ok"`
	Message   string    `json:"message,omitempty"`
	Results   int       `json:"results"`
	TestedAt  time.Time `json:"testedAt"`
}

TestStatus is the outcome of an indexer's most recent test.

type UpdateFailed

type UpdateFailed struct {
	ID    string `json:"id"`
	Error string `json:"error"`
}

UpdateFailed is a definition that could not be refreshed.

type UpdateReport

type UpdateReport struct {
	Updated   []string       `json:"updated"`
	Unchanged int            `json:"unchanged"`
	Failed    []UpdateFailed `json:"failed"`
}

UpdateReport summarises "Update definitions".

type ValidationError

type ValidationError struct{ Problems []string }

ValidationError lists the reasons a definition cannot be used.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL