Path: blob/main/internal/offline_download/transmission/client.go
1562 views
package transmission12import (3"bytes"4"context"5"encoding/base64"6"fmt"7"net/http"8"net/url"9"strconv"1011"github.com/alist-org/alist/v3/internal/conf"12"github.com/alist-org/alist/v3/internal/errs"13"github.com/alist-org/alist/v3/internal/model"14"github.com/alist-org/alist/v3/internal/offline_download/tool"15"github.com/alist-org/alist/v3/internal/setting"16"github.com/alist-org/alist/v3/pkg/utils"17"github.com/hekmon/transmissionrpc/v3"18"github.com/pkg/errors"19log "github.com/sirupsen/logrus"20)2122type Transmission struct {23client *transmissionrpc.Client24}2526func (t *Transmission) Run(task *tool.DownloadTask) error {27return errs.NotSupport28}2930func (t *Transmission) Name() string {31return "Transmission"32}3334func (t *Transmission) Items() []model.SettingItem {35// transmission settings36return []model.SettingItem{37{Key: conf.TransmissionUri, Value: "http://localhost:9091/transmission/rpc", Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},38{Key: conf.TransmissionSeedtime, Value: "0", Type: conf.TypeNumber, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},39}40}4142func (t *Transmission) Init() (string, error) {43t.client = nil44uri := setting.GetStr(conf.TransmissionUri)45endpoint, err := url.Parse(uri)46if err != nil {47return "", errors.Wrap(err, "failed to init transmission client")48}49c, err := transmissionrpc.New(endpoint, nil)50if err != nil {51return "", errors.Wrap(err, "failed to init transmission client")52}5354ok, serverVersion, serverMinimumVersion, err := c.RPCVersion(context.Background())55if err != nil {56return "", errors.Wrapf(err, "failed get transmission version")57}5859if !ok {60return "", fmt.Errorf("remote transmission RPC version (v%d) is incompatible with the transmission library (v%d): remote needs at least v%d",61serverVersion, transmissionrpc.RPCVersion, serverMinimumVersion)62}6364t.client = c65log.Infof("remote transmission RPC version (v%d) is compatible with our transmissionrpc library (v%d)\n",66serverVersion, transmissionrpc.RPCVersion)67log.Infof("using transmission version: %d", serverVersion)68return fmt.Sprintf("transmission version: %d", serverVersion), nil69}7071func (t *Transmission) IsReady() bool {72return t.client != nil73}7475func (t *Transmission) AddURL(args *tool.AddUrlArgs) (string, error) {76endpoint, err := url.Parse(args.Url)77if err != nil {78return "", errors.Wrap(err, "failed to parse transmission uri")79}8081rpcPayload := transmissionrpc.TorrentAddPayload{82DownloadDir: &args.TempDir,83}84// http url for .torrent file85if endpoint.Scheme == "http" || endpoint.Scheme == "https" {86resp, err := http.Get(args.Url)87if err != nil {88return "", errors.Wrap(err, "failed to get .torrent file")89}90defer resp.Body.Close()91buffer := new(bytes.Buffer)92encoder := base64.NewEncoder(base64.StdEncoding, buffer)93// Stream file to the encoder94if _, err = utils.CopyWithBuffer(encoder, resp.Body); err != nil {95return "", errors.Wrap(err, "can't copy file content into the base64 encoder")96}97// Flush last bytes98if err = encoder.Close(); err != nil {99return "", errors.Wrap(err, "can't flush last bytes of the base64 encoder")100}101// Get the string form102b64 := buffer.String()103rpcPayload.MetaInfo = &b64104} else { // magnet uri105rpcPayload.Filename = &args.Url106}107108torrent, err := t.client.TorrentAdd(context.TODO(), rpcPayload)109if err != nil {110return "", err111}112113if torrent.ID == nil {114return "", fmt.Errorf("failed get torrent ID")115}116gid := strconv.FormatInt(*torrent.ID, 10)117return gid, nil118}119120func (t *Transmission) Remove(task *tool.DownloadTask) error {121gid, err := strconv.ParseInt(task.GID, 10, 64)122if err != nil {123return err124}125err = t.client.TorrentRemove(context.TODO(), transmissionrpc.TorrentRemovePayload{126IDs: []int64{gid},127DeleteLocalData: false,128})129return err130}131132func (t *Transmission) Status(task *tool.DownloadTask) (*tool.Status, error) {133gid, err := strconv.ParseInt(task.GID, 10, 64)134if err != nil {135return nil, err136}137infos, err := t.client.TorrentGetAllFor(context.TODO(), []int64{gid})138if err != nil {139return nil, err140}141142if len(infos) < 1 {143return nil, fmt.Errorf("failed get status, wrong gid: %s", task.GID)144}145info := infos[0]146147s := &tool.Status{148Completed: *info.IsFinished,149Err: err,150}151s.Progress = *info.PercentDone * 100152s.TotalBytes = int64(*info.SizeWhenDone / 8)153154switch *info.Status {155case transmissionrpc.TorrentStatusCheckWait,156transmissionrpc.TorrentStatusDownloadWait,157transmissionrpc.TorrentStatusCheck,158transmissionrpc.TorrentStatusDownload,159transmissionrpc.TorrentStatusIsolated:160s.Status = "[transmission] " + info.Status.String()161case transmissionrpc.TorrentStatusSeedWait,162transmissionrpc.TorrentStatusSeed:163s.Completed = true164case transmissionrpc.TorrentStatusStopped:165s.Err = errors.Errorf("[transmission] failed to download %s, status: %s, error: %s", task.GID, info.Status.String(), *info.ErrorString)166default:167s.Err = errors.Errorf("[transmission] unknown status occurred downloading %s, err: %s", task.GID, *info.ErrorString)168}169return s, nil170}171172var _ tool.Tool = (*Transmission)(nil)173174func init() {175tool.Tools.Add(&Transmission{})176}177178179