download

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 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) Downloader

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"
	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