Files
polaris/pkg/transmission/transmission.go

238 lines
4.8 KiB
Go

package transmission
import (
"context"
"fmt"
"io/fs"
"net/url"
"os"
"path/filepath"
"polaris/log"
"polaris/pkg"
"polaris/pkg/utils"
"github.com/hekmon/transmissionrpc/v3"
"github.com/pkg/errors"
)
func NewClient(c Config) (*Client, error) {
u, err := url.Parse(c.URL)
if err != nil {
return nil, errors.Wrap(err, "parse url")
}
if c.User != "" {
log.Info("transmission login with user: ", c.User)
u.User = url.UserPassword(c.User, c.Password)
}
u.Path = "/transmission/rpc"
tbt, err := transmissionrpc.New(u, nil)
if err != nil {
return nil, errors.Wrap(err, "connect transmission")
}
_, err = tbt.TorrentGetAll(context.TODO())
if err != nil {
return nil, errors.Wrap(err, "transmission cannot connect")
}
return &Client{c: tbt, cfg: c}, nil
}
type Config struct {
URL string `json:"url"`
User string `json:"user"`
Password string `json:"password"`
}
type Client struct {
c *transmissionrpc.Client
cfg Config
}
func (c *Client) GetAll() ([]pkg.Torrent, error) {
all, err := c.c.TorrentGetAll(context.TODO())
if err != nil {
return nil, errors.Wrap(err, "get all")
}
var torrents []pkg.Torrent
for _, t := range all {
torrents = append(torrents, &Torrent{
hash: *t.HashString,
c: c.c,
//cfg: c.cfg,
})
}
return torrents, nil
}
func (c *Client) Download(link, hash, dir string) (pkg.Torrent, error) {
t, err := c.c.TorrentAdd(context.TODO(), transmissionrpc.TorrentAddPayload{
Filename: &link,
DownloadDir: &dir,
})
if err != nil {
return nil, err
}
log.Debugf("get torrent info: %+v", t)
return &Torrent{
hash: hash,
c: c.c,
//cfg: c.cfg,
}, err
}
func NewTorrentHash(cfg Config, hash string) (*Torrent, error) {
c, err := NewClient(cfg)
if err != nil {
return nil, err
}
t := &Torrent{
c: c.c,
hash: hash,
//cfg: cfg,
}
if !t.Exists() {
return nil, errors.Errorf("torrent not exist: %v", hash)
}
return t, nil
}
func NewTorrent(cfg Config, link string) (*Torrent, error) {
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, err
}
return NewTorrentHash(cfg, hash)
}
type Torrent struct {
//t *transmissionrpc.Torrent
c *transmissionrpc.Client
hash string
//cfg Config
}
func (t *Torrent) getTorrent() (transmissionrpc.Torrent, error) {
r, err := t.c.TorrentGetAllForHashes(context.TODO(), []string{t.hash})
if err != nil {
log.Errorf("get torrent info for error: %v", err)
}
if len(r) == 0 {
return transmissionrpc.Torrent{}, fmt.Errorf("no torrent")
}
return r[0], nil
}
func (t *Torrent) Exists() bool {
r, err := t.c.TorrentGetAllForHashes(context.TODO(), []string{t.hash})
if err != nil {
log.Errorf("get torrent info for error: %v", err)
}
return len(r) > 0
}
func (t *Torrent) Name() (string, error) {
tt, err := t.getTorrent()
if err != nil {
return "", err
}
return *tt.Name, nil
}
func (t *Torrent) Progress() (int, error) {
tt, err := t.getTorrent()
if err != nil {
return 0, err
}
if tt.IsFinished != nil && *tt.IsFinished {
return 100, nil
}
if tt.PercentComplete != nil && *tt.PercentComplete >= 1 {
return 100, nil
}
if tt.PercentComplete != nil {
p := int(*tt.PercentComplete * 100)
if p == 100 {
p = 99
}
return p, nil
}
return 0, nil
}
func (t *Torrent) Stop() error {
return t.c.TorrentStopHashes(context.TODO(), []string{t.hash})
}
func (t *Torrent) SeedRatio() (float64, error) {
tt, err := t.getTorrent()
if err != nil {
return 0, err
}
if tt.UploadRatio == nil {
return 0, nil
}
return *tt.UploadRatio, nil
}
func (t *Torrent) Start() error {
return t.c.TorrentStartHashes(context.TODO(), []string{t.hash})
}
func (t *Torrent) Remove() error {
tt, err := t.getTorrent()
if err != nil {
return errors.Wrap(err, "get torrent")
}
return t.c.TorrentRemove(context.TODO(), transmissionrpc.TorrentRemovePayload{
IDs: []int64{*tt.ID},
DeleteLocalData: true,
})
}
func (t *Torrent) Size() (int, error) {
tt, err := t.getTorrent()
if err != nil {
return 0, errors.Wrap(err, "get torrent")
}
return int(tt.TotalSize.Byte()), nil
}
func (t *Torrent) GetHash() string {
return t.hash
}
func (t *Torrent) WalkFunc() func(fn func(path string, info fs.FileInfo) error) error {
tt, err := t.getTorrent()
if err != nil {
return func(fn func(path string, info fs.FileInfo) error) error {
return errors.Wrap(err, "get torrent info")
}
}
return func(fn func(path string, info fs.FileInfo) error) error {
for _, file := range tt.Files {
name := filepath.Join(*tt.DownloadDir, file.Name)
info, err := os.Stat(name)
if err != nil {
return err
}
if err := fn(name, info); err != nil {
return err
}
}
return nil
}
}