download

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: GPL-3.0 Imports: 29 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUnsupportedClient = errors.New("unsupported download client type")
	ErrUnreachable       = errors.New("download client unreachable")
	ErrUnauthorized      = errors.New("download client credentials rejected")
	ErrUnexpectedStatus  = errors.New("download client returned unexpected status")
	ErrBadResponse       = errors.New("download client returned malformed response")
	ErrTorrentNotFound   = errors.New("torrent not found in download client")
	// ErrTorrentAlreadyExists is returned by AddTorrent when the download
	// client refuses the add because the infohash is already present. The
	// caller treats this as a soft skip — no grab_failures increment, no
	// new DownloadRecord — since state has drifted, not a real failure.
	ErrTorrentAlreadyExists = errors.New("torrent already exists in download client")
)

Categorised download-client failures. Handlers map these to 422 with friendly messages; anything not matching is a 500 internal error.

Functions

This section is empty.

Types

type Adopter

type Adopter interface {
	AdoptManualTorrents(ctx context.Context) ([]uint32, error)
}

Adopter scans enabled download clients for untracked managed-category torrents and either auto-imports them (returning those record IDs for the caller to enqueue) or files a pending proposal. Driven by the download poll job after the completion pass.

type Checker

type Checker interface {
	CheckStatus(ctx context.Context) ([]CompletedDownload, error)
	ReconcileEpisodeStatuses(ctx context.Context) error
}

Checker is the consumer-facing surface for polling completed downloads. jobs.DownloadMonitor accepts it so it can be driven by a fake in tests without pulling in the full Manager.

type Cleaner

type Cleaner interface {
	PurgeOldRecords(ctx context.Context) error
	PurgeOrphanedTorrents(ctx context.Context) error
}

Cleaner is the consumer-facing surface for the cleanup scheduler job (jobs.Cleanup).

type Client

type Client interface {
	AddTorrent(ctx context.Context, src TorrentSource) (string, error)
	GetTorrent(ctx context.Context, hash string) (*Torrent, error)
	ListTorrents(ctx context.Context) ([]Torrent, error)
	RemoveTorrent(ctx context.Context, hash string, deleteFiles bool) error
	PauseTorrent(ctx context.Context, hash string) error
	ResumeTorrent(ctx context.Context, hash string) error
	TestConnection(ctx context.Context) error
}

type CompletedDownload

type CompletedDownload struct {
	Record   *ent.DownloadRecord
	SavePath string
}

CompletedDownload pairs a finished download record with the local path where the torrent client saved the files.

type Deluge

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

Deluge talks the Deluge Web UI JSON-RPC protocol. Auth is the Web UI password (auth.login → session cookie); the Web UI must then be attached to a daemon (web.connect), which streamline ensures lazily.

func NewDeluge

func NewDeluge(baseURL, password string) *Deluge

func (*Deluge) AddTorrent

func (d *Deluge) AddTorrent(
	ctx context.Context,
	src TorrentSource,
) (string, error)

func (*Deluge) GetTorrent

func (d *Deluge) GetTorrent(
	ctx context.Context,
	hash string,
) (*Torrent, error)

func (*Deluge) ListTorrents

func (d *Deluge) ListTorrents(ctx context.Context) ([]Torrent, error)

func (*Deluge) PauseTorrent

func (d *Deluge) PauseTorrent(ctx context.Context, hash string) error

pause/resume pass a single-element list: Deluge 1.x requires a list and 2.x normalizes a non-list to one, so the list form works on both.

func (*Deluge) RemoveTorrent

func (d *Deluge) RemoveTorrent(
	ctx context.Context,
	hash string,
	deleteFiles bool,
) error

func (*Deluge) ResumeTorrent

func (d *Deluge) ResumeTorrent(ctx context.Context, hash string) error

func (*Deluge) TestConnection

func (d *Deluge) TestConnection(ctx context.Context) error

type Downloader

type Downloader interface {
	Test(ctx context.Context, p TestParams) error
	TestByName(ctx context.Context, name string) error
	Grab(
		ctx context.Context,
		result indexer.SearchResult,
		movieID uint32,
	) (*ent.DownloadRecord, error)
	GrabEpisode(
		ctx context.Context,
		result indexer.SearchResult,
		episodeID uint32,
	) (*ent.DownloadRecord, error)
	CheckStatus(ctx context.Context) ([]CompletedDownload, error)
	ReconcileEpisodeStatuses(ctx context.Context) error
	RemoveTorrent(
		ctx context.Context,
		downloadClientName string,
		torrentHash string,
	) error
	Queue(ctx context.Context) (QueueSnapshot, error)
	CancelQueueItem(ctx context.Context, recordID uint32) error
	PauseQueueItem(ctx context.Context, recordID uint32) error
	ResumeQueueItem(ctx context.Context, recordID uint32) error
}

Downloader is the consumer-facing surface used by HTTP handlers and the scheduler. Implemented by the unexported download struct.

func New

func New(store db.Store, builtin Client) Downloader

New builds the download manager. builtin may be nil (no engine configured); callers must pass an untyped nil, not a typed-nil concrete pointer.

type QBittorrent

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

func NewQBittorrentAPIKey

func NewQBittorrentAPIKey(baseURL, apiKey string) *QBittorrent

func NewQBittorrentPassword

func NewQBittorrentPassword(baseURL, username, password string) *QBittorrent

func (*QBittorrent) AddTorrent

func (q *QBittorrent) AddTorrent(
	ctx context.Context,
	src TorrentSource,
) (string, error)

AddTorrent uploads the source to qBittorrent and returns the infohash. .torrent bytes are sent as a multipart file part so qBittorrent never has to reach the indexer itself — this is what unblocks deployments where the client lives in a VPN/Docker network the indexer is not on. The save path is intentionally left to qBittorrent's own configuration; streamline only needs to know where to read completed downloads from (library.download_path).

func (*QBittorrent) GetTorrent

func (q *QBittorrent) GetTorrent(
	ctx context.Context,
	hash string,
) (*Torrent, error)

func (*QBittorrent) ListTorrents

func (q *QBittorrent) ListTorrents(ctx context.Context) ([]Torrent, error)

func (*QBittorrent) PauseTorrent

func (q *QBittorrent) PauseTorrent(ctx context.Context, hash string) error

func (*QBittorrent) RemoveTorrent

func (q *QBittorrent) RemoveTorrent(
	ctx context.Context,
	hash string,
	deleteFiles bool,
) error

func (*QBittorrent) ResumeTorrent

func (q *QBittorrent) ResumeTorrent(ctx context.Context, hash string) error

func (*QBittorrent) TestConnection

func (q *QBittorrent) TestConnection(ctx context.Context) error

type QueueEntry

type QueueEntry struct {
	RecordID     uint32
	Status       string // downloading | importing | paused | error
	Title        string
	Quality      string
	ReleaseGroup string
	Movie        *ent.Movie
	// Episode is set for TV download records (with season + show eager-loaded);
	// nil for movie records. Drives the "<show> · SxxExx" row title.
	Episode        *ent.Episode
	Indexer        string
	DownloadClient string
	Size           int64
	Progress       float64
	DownloadSpeed  int64
	ETA            int64
	FailureReason  string
	CreatedAt      time.Time
}

QueueEntry is one in-flight download enriched with live client telemetry.

type QueueSnapshot

type QueueSnapshot struct {
	Items       []QueueEntry
	RefreshedAt time.Time
}

QueueSnapshot is the cached live-queue view with its capture time.

type TestParams

type TestParams struct {
	ClientType string
	Host       string
	Port       uint16
	UseSSL     bool
	AuthMethod string
	Username   string
	Password   string
	APIKey     string
}

TestParams describes ad-hoc credentials for a connection test that has not yet been persisted as a config download-client entry.

type Torrent

type Torrent struct {
	Hash     string
	Name     string
	Status   TorrentStatus
	Progress float64
	Size     int64
	SavePath string
	// DownloadSpeed is bytes/sec (0 when idle/unknown). ETA is seconds to
	// completion; the qBittorrent ∞ sentinel (8640000) is normalized to 0.
	DownloadSpeed int64
	ETA           int64
}

type TorrentSource

type TorrentSource struct {
	Bytes  []byte // raw .torrent file contents
	Magnet string // magnet:?xt=urn:btih:... URI
}

TorrentSource is what the manager hands to Client.AddTorrent. Exactly one of Bytes or Magnet must be set: the manager fetches http(s) .torrent URLs itself (so download clients in network-isolated containers don't need to reach the indexer) and passes magnet URIs straight through.

type TorrentStatus

type TorrentStatus string
const (
	StatusDownloading TorrentStatus = "downloading"
	StatusSeeding     TorrentStatus = "seeding"
	StatusPaused      TorrentStatus = "paused"
	StatusCompleted   TorrentStatus = "completed"
	// StatusFetching (magnet metadata not yet resolved) and StatusStalled
	// (downloading with no connected peers) are only emitted by the builtin
	// bittorrent engine; external clients map their equivalents to
	// StatusDownloading.
	StatusFetching TorrentStatus = "fetching"
	StatusStalled  TorrentStatus = "stalled"
	StatusError    TorrentStatus = "error"
)

type Transmission

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

Transmission talks the Transmission RPC protocol (hyphenated method names, camelCase torrent fields). Auth is optional HTTP Basic; the daemon also requires the X-Transmission-Session-Id CSRF handshake (a 409 challenge).

func NewTransmission

func NewTransmission(baseURL, username, password string) *Transmission

func (*Transmission) AddTorrent

func (t *Transmission) AddTorrent(
	ctx context.Context,
	src TorrentSource,
) (string, error)

func (*Transmission) GetTorrent

func (t *Transmission) GetTorrent(
	ctx context.Context,
	hash string,
) (*Torrent, error)

func (*Transmission) ListTorrents

func (t *Transmission) ListTorrents(ctx context.Context) ([]Torrent, error)

func (*Transmission) PauseTorrent

func (t *Transmission) PauseTorrent(ctx context.Context, hash string) error

func (*Transmission) RemoveTorrent

func (t *Transmission) RemoveTorrent(
	ctx context.Context,
	hash string,
	deleteFiles bool,
) error

func (*Transmission) ResumeTorrent

func (t *Transmission) ResumeTorrent(ctx context.Context, hash string) error

func (*Transmission) TestConnection

func (t *Transmission) TestConnection(ctx context.Context) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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