plugin

package
v0.0.0-...-d88c8eb Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package plugin defines the public interfaces and value types for Pilot's plugin system. Indexer, DownloadClient, and Notifier implementations (built-in or external) depend only on this package.

Index

Constants

This section is empty.

Variables

View Source
var ErrItemNotFound = errors.New("download client: item not found")

ErrItemNotFound is returned by DownloadClient implementations when the item asked about no longer exists in the client (e.g. the user removed it directly in the client's UI, or the client forgot it after a restart).

Callers that persist grab history (queue sync, stall watchers) should distinguish this from transient errors: on ErrItemNotFound the grab is definitively gone and should be marked removed, whereas on any other error the correct behaviour is to log and retry on the next poll — a brief network blip must not nuke the queue.

Functions

This section is empty.

Types

type AudioChannels

type AudioChannels string

AudioChannels is the channel layout of a release.

const (
	AudioChannelsUnknown AudioChannels = ""
	AudioChannels71      AudioChannels = "7.1"
	AudioChannels51      AudioChannels = "5.1"
	AudioChannels20      AudioChannels = "2.0"
	AudioChannels10      AudioChannels = "1.0"
)

type AudioCodec

type AudioCodec string

AudioCodec is the audio codec of a release.

const (
	AudioCodecUnknown     AudioCodec = ""
	AudioCodecTrueHD      AudioCodec = "truehd"
	AudioCodecTrueHDAtmos AudioCodec = "truehd_atmos"
	AudioCodecDTSX        AudioCodec = "dts_x"
	AudioCodecDTSHDMA     AudioCodec = "dts_hd_ma"
	AudioCodecDTSHD       AudioCodec = "dts_hd"
	AudioCodecDTS         AudioCodec = "dts"
	AudioCodecEAC3Atmos   AudioCodec = "eac3_atmos"
	AudioCodecEAC3        AudioCodec = "eac3"
	AudioCodecAC3         AudioCodec = "ac3"
	AudioCodecAAC         AudioCodec = "aac"
	AudioCodecFLAC        AudioCodec = "flac"
	AudioCodecPCM         AudioCodec = "pcm"
	AudioCodecMP3         AudioCodec = "mp3"
	AudioCodecOpus        AudioCodec = "opus"
)

type Capabilities

type Capabilities struct {
	SearchAvailable   bool
	TVSearchAvailable bool
	MovieSearch       bool
	Categories        []int // Newznab/Torznab category IDs
}

Capabilities describes what an indexer supports.

type Codec

type Codec string

Codec is the video codec of a release.

const (
	CodecUnknown Codec = "unknown"
	CodecX264    Codec = "x264"
	CodecX265    Codec = "x265"
	CodecAV1     Codec = "av1"
	CodecXVID    Codec = "xvid"
)

type DownloadClient

type DownloadClient interface {
	Name() string
	Protocol() Protocol

	// Add submits a release to the download client.
	// Returns the client-assigned item ID for future status queries.
	Add(ctx context.Context, r Release) (clientItemID string, err error)

	// Status returns the current state of a download client item.
	Status(ctx context.Context, clientItemID string) (QueueItem, error)

	// GetQueue returns all items currently in the download client.
	GetQueue(ctx context.Context) ([]QueueItem, error)

	// Remove deletes an item from the download client.
	// If deleteFiles is true, the downloaded data is also deleted.
	Remove(ctx context.Context, clientItemID string, deleteFiles bool) error

	// Test validates that the connection to the download client works.
	Test(ctx context.Context) error
}

DownloadClient is the plugin interface for download clients.

type DownloadStatus

type DownloadStatus string

DownloadStatus is the state of an item in the download client.

const (
	StatusQueued      DownloadStatus = "queued"
	StatusDownloading DownloadStatus = "downloading"
	StatusCompleted   DownloadStatus = "completed"
	StatusPaused      DownloadStatus = "paused"
	StatusFailed      DownloadStatus = "failed"
)

type EventType

type EventType string

EventType identifies what happened.

const (
	EventSeriesAdded   EventType = "series_added"
	EventSeriesDeleted EventType = "series_deleted"
	EventGrabStarted   EventType = "grab_started"
	EventDownloadDone  EventType = "download_done"
	EventImportDone    EventType = "import_done"
	EventImportFailed  EventType = "import_failed"
	EventHealthIssue   EventType = "health_issue"
	EventHealthOK      EventType = "health_ok"
)

type HDRFormat

type HDRFormat string

HDRFormat is the high dynamic range format of a release.

const (
	HDRNone        HDRFormat = "none"
	HDRUnknown     HDRFormat = "unknown"
	HDRHDR10       HDRFormat = "hdr10"
	HDRDolbyVision HDRFormat = "dolby_vision"
	HDRHLG         HDRFormat = "hlg"
	HDRHDR10Plus   HDRFormat = "hdr10plus"
)

type ImportList

type ImportList interface {
	Name() string
	Fetch(ctx context.Context) ([]ImportListItem, error)
	Test(ctx context.Context) error
}

ImportList is the plugin interface for import list sources. Implementations fetch series from external services (TMDb, Trakt, Plex, etc.) and return them as a flat list. The sync service handles deduplication, exclusion checks, and adding series to the library.

type ImportListItem

type ImportListItem struct {
	TMDbID     int    // required — canonical identifier
	IMDbID     string // optional; used for display/logging
	Title      string
	Year       int
	PosterPath string // optional; TMDb poster path (e.g. "/abc123.jpg")
}

ImportListItem is a single series returned by an import list source.

type Indexer

type Indexer interface {
	// Name returns the human-readable plugin name, e.g. "Torznab".
	Name() string

	// Protocol returns the release download mechanism this indexer provides.
	Protocol() Protocol

	// Capabilities returns what search types this indexer supports.
	Capabilities(ctx context.Context) (Capabilities, error)

	// Search queries the indexer for releases matching the query.
	Search(ctx context.Context, q SearchQuery) ([]Release, error)

	// GetRecent returns the most recent releases from the indexer's RSS feed.
	GetRecent(ctx context.Context) ([]Release, error)

	// Test validates that the indexer is reachable and configured correctly.
	Test(ctx context.Context) error
}

Indexer is the plugin interface for release indexers.

type IndexerFlag

type IndexerFlag string

IndexerFlag represents a flag reported by an indexer for a release.

const (
	FlagFreeleech    IndexerFlag = "freeleech"
	FlagHalfleech    IndexerFlag = "halfleech"
	FlagFreeleech75  IndexerFlag = "freeleech_75"
	FlagFreeleech25  IndexerFlag = "freeleech_25"
	FlagDoubleUpload IndexerFlag = "double_upload"
	FlagInternal     IndexerFlag = "internal"
	FlagScene        IndexerFlag = "scene"
	FlagNuked        IndexerFlag = "nuked"
)

type MediaServer

type MediaServer interface {
	// Name returns the human-readable name of the media server plugin.
	Name() string

	// RefreshLibrary tells the media server to re-scan the library section
	// that contains seriesPath. Implementations may fall back to a full
	// library refresh if path-scoped scanning is unavailable.
	RefreshLibrary(ctx context.Context, seriesPath string) error

	// Test verifies that the media server is reachable and the credentials
	// are valid.
	Test(ctx context.Context) error
}

MediaServer is implemented by media server plugins (Plex, Emby, Jellyfin). After a series file is imported, the dispatcher calls RefreshLibrary so the media server picks up the new file without waiting for a scheduled scan.

type NotificationEvent

type NotificationEvent struct {
	Type      EventType
	Timestamp time.Time
	SeriesID  string         // UUID, if series-related; empty otherwise
	Message   string         // human-readable summary
	Data      map[string]any // event-specific extra fields
}

NotificationEvent carries the context of something that happened.

type Notifier

type Notifier interface {
	Name() string
	Notify(ctx context.Context, event NotificationEvent) error
	Test(ctx context.Context) error
}

Notifier is the plugin interface for notification channels.

type Protocol

type Protocol string

Protocol identifies the release download mechanism.

const (
	ProtocolTorrent Protocol = "torrent"
	ProtocolNZB     Protocol = "nzb"
	ProtocolUnknown Protocol = "unknown"
)

type Quality

type Quality struct {
	Resolution    Resolution    `json:"resolution"`
	Source        Source        `json:"source"`
	Codec         Codec         `json:"codec"`
	HDR           HDRFormat     `json:"hdr"`
	AudioCodec    AudioCodec    `json:"audio_codec,omitempty"`
	AudioChannels AudioChannels `json:"audio_channels,omitempty"`
	// Name is the human-readable label derived from the video fields,
	// e.g. "Bluray-1080p x265" or "WEBDL-2160p HDR10".
	Name string `json:"name"`
}

Quality describes the technical characteristics of a release. It is a value type — embedded in releases, files, and profiles.

func ParseQualityFromTitle

func ParseQualityFromTitle(title string) Quality

ParseQualityFromTitle extracts quality metadata from a release title string.

func (Quality) AtLeast

func (q Quality) AtLeast(other Quality) bool

AtLeast reports whether q meets or exceeds other.

func (Quality) BetterThan

func (q Quality) BetterThan(other Quality) bool

BetterThan reports whether q is strictly better than other.

func (Quality) Score

func (q Quality) Score() int

Score returns a numeric rank for this quality used when comparing two qualities. Higher is better.

type QueueItem

type QueueItem struct {
	ClientItemID string
	Title        string
	Status       DownloadStatus
	Size         int64
	Downloaded   int64
	SeedRatio    float64 // torrent only; 0 for NZB
	Error        string
	// ContentPath is the absolute filesystem path to the downloaded content.
	// For single-file downloads this is the file path; for multi-file downloads
	// it is the root directory. Empty until the download client reports it.
	ContentPath string
	// AddedAt is the Unix timestamp when the item was added to the client.
	// Zero if the client does not report this field.
	AddedAt int64
}

QueueItem represents an item tracked in the download client.

type Release

type Release struct {
	GUID         string
	Title        string
	Indexer      string
	Protocol     Protocol
	DownloadURL  string
	InfoURL      string
	Size         int64
	Seeds        int
	Peers        int
	AgeDays      float64
	Quality      Quality
	Edition      string // canonical edition name parsed from title; empty = untagged
	ReleaseGroup string // scene group name parsed from title; empty = unknown
	IndexerFlags []IndexerFlag

	// Media context — populated by Pilot/Prism before sending to download client.
	// Download clients that support renaming (Haul) use these fields.
	MediaType     string `json:"media_type,omitempty"`     // "movie" or "tv"
	MediaTitle    string `json:"media_title,omitempty"`    // series or movie title
	MediaYear     int    `json:"media_year,omitempty"`     // release year
	SeasonNumber  int    `json:"season_number,omitempty"`  // TV only
	EpisodeNumber int    `json:"episode_number,omitempty"` // TV only
	EpisodeTitle  string `json:"episode_title,omitempty"`  // TV only

	// Arr-side IDs forwarded to history-aware download clients (Haul)
	// so they can answer "have I downloaded anything for series X?"
	// later. All optional; leaving empty disables the lookup integration
	// for this grab.
	TMDBID    int    `json:"tmdb_id,omitempty"`    // TMDB tv/movie id
	SeriesID  string `json:"series_id,omitempty"`  // Pilot series UUID
	EpisodeID string `json:"episode_id,omitempty"` // Pilot episode UUID
}

Release is the transient result of an indexer search. It is not stored in the database. A summary is written to GrabHistory when a release is grabbed.

type Resolution

type Resolution string

Resolution is the video resolution of a release.

const (
	ResolutionUnknown Resolution = "unknown"
	ResolutionSD      Resolution = "sd" // implied SD (e.g. DVDRip without explicit resolution)
	Resolution480p    Resolution = "480p"
	Resolution576p    Resolution = "576p"
	Resolution720p    Resolution = "720p"
	Resolution1080p   Resolution = "1080p"
	Resolution2160p   Resolution = "2160p" // 4K
)

type ScoreBreakdown

type ScoreBreakdown struct {
	Total      int              `json:"total"`
	Dimensions []ScoreDimension `json:"dimensions"`
	// CustomFormatScore is the sum of matched custom format scores for the
	// quality profile. It sits alongside (not inside) Total because CF scoring
	// is an independent dimension used for separate thresholds.
	CustomFormatScore int      `json:"custom_format_score"`
	MatchedFormats    []string `json:"matched_formats,omitempty"`
	// EditionBonus is the bonus points awarded when the release edition
	// matches the series' preferred edition (+30 pts). It is additive
	// to Total and reflected in the Dimensions list.
	EditionBonus int `json:"edition_bonus"`
}

ScoreBreakdown records how a release was evaluated against a quality profile. Each dimension is independently scored; Total is the sum.

type ScoreDimension

type ScoreDimension struct {
	Name    string `json:"name"`    // "resolution", "source", "codec", "hdr"
	Score   int    `json:"score"`   // points awarded for this dimension
	Max     int    `json:"max"`     // maximum possible for this dimension
	Matched bool   `json:"matched"` // did it meet the profile requirement?
	Got     string `json:"got"`     // what we found (e.g. "x264")
	Want    string `json:"want"`    // what the profile requires (e.g. "x265")
}

ScoreDimension is one component of a ScoreBreakdown.

type SearchQuery

type SearchQuery struct {
	Query   string // free-text query, e.g. "Breaking Bad S01E05"
	TVDBID  int    // TVDB ID when available
	TMDBID  int    // TMDB ID when available
	IMDBID  string // e.g. "tt0903747"
	Year    int
	Season  int // season number for TV episode filtering
	Episode int // episode number for TV episode filtering
}

SearchQuery is the input to an indexer search.

type SeedLimiter

type SeedLimiter interface {
	SetSeedLimits(ctx context.Context, clientItemID string, ratioLimit float64, seedTimeSecs int) error
}

SeedLimiter is an optional interface for download clients that support configuring per-torrent seed ratio and seed time limits. Implementations should treat ratioLimit <= 0 as "use client default" and seedTimeSecs <= 0 as "no time limit".

type Source

type Source string

Source is the origin/format of a release.

const (
	SourceUnknown   Source = "unknown"
	SourceWorkprint Source = "workprint"
	SourceCAM       Source = "cam"
	SourceTelesync  Source = "telesync"
	SourceTELECINE  Source = "telecine"
	SourceDVDSCR    Source = "dvdscr"
	SourceRegional  Source = "regional"
	SourceDVD       Source = "dvd"
	SourceDVDR      Source = "dvdr"
	SourceHDTV      Source = "hdtv"
	SourceWEBRip    Source = "webrip"
	SourceWEBDL     Source = "webdl"
	SourceBluRay    Source = "bluray"
	SourceRemux     Source = "remux"
	SourceBRDisk    Source = "brdisk"
	SourceRawHD     Source = "rawhd"
)

type TMDBInjectable

type TMDBInjectable interface {
	SetTMDBClient(client any)
}

TMDBInjectable is an optional interface for import list plugins that need the shared TMDB client. The service calls SetTMDBClient before Fetch()/Test(). The parameter is typed as any to avoid an import cycle with internal/metadata/tmdb.

type TraktInjectable

type TraktInjectable interface {
	SetTraktClient(client any)
}

TraktInjectable is an optional interface for import list plugins that need the shared Trakt client. The service calls SetTraktClient before Fetch()/Test(). The parameter is typed as any to avoid an import cycle with internal/trakt.

type WatchEvent

type WatchEvent struct {
	TMDBID    int       // series identifier
	Title     string    // for display/logging
	WatchedAt time.Time // when playback completed
	UserName  string    // media server user (for multi-user setups)
}

WatchEvent represents a single completed playback of a series episode.

type WatchProvider

type WatchProvider interface {
	// WatchHistory returns watch events since the given timestamp.
	// Each event represents one completed playback (>= 90% watched).
	WatchHistory(ctx context.Context, since time.Time) ([]WatchEvent, error)
}

WatchProvider is an optional interface for media servers that can report watch history. Plugins that don't support it simply don't implement it. Check with a type assertion at runtime:

if wp, ok := server.(WatchProvider); ok { ... }

Jump to

Keyboard shortcuts

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