Path: blob/main/internal/offline_download/tool/download.go
1562 views
package tool12import (3"fmt"4"time"56"github.com/alist-org/alist/v3/internal/conf"7"github.com/alist-org/alist/v3/internal/errs"8"github.com/alist-org/alist/v3/internal/setting"9"github.com/alist-org/alist/v3/internal/task"10"github.com/pkg/errors"11log "github.com/sirupsen/logrus"12"github.com/xhofe/tache"13)1415type DownloadTask struct {16task.TaskExtension17Url string `json:"url"`18DstDirPath string `json:"dst_dir_path"`19TempDir string `json:"temp_dir"`20DeletePolicy DeletePolicy `json:"delete_policy"`21Toolname string `json:"toolname"`22Status string `json:"-"`23Signal chan int `json:"-"`24GID string `json:"-"`25tool Tool26callStatusRetried int27}2829func (t *DownloadTask) Run() error {30t.ReinitCtx()31t.ClearEndTime()32t.SetStartTime(time.Now())33defer func() { t.SetEndTime(time.Now()) }()34if t.tool == nil {35tool, err := Tools.Get(t.Toolname)36if err != nil {37return errors.WithMessage(err, "failed get tool")38}39t.tool = tool40}41if err := t.tool.Run(t); !errs.IsNotSupportError(err) {42if err == nil {43return t.Transfer()44}45return err46}47t.Signal = make(chan int)48defer func() {49t.Signal = nil50}()51gid, err := t.tool.AddURL(&AddUrlArgs{52Url: t.Url,53UID: t.ID,54TempDir: t.TempDir,55Signal: t.Signal,56})57if err != nil {58return err59}60t.GID = gid61var ok bool62outer:63for {64select {65case <-t.CtxDone():66err := t.tool.Remove(t)67return err68case <-t.Signal:69ok, err = t.Update()70if ok {71break outer72}73case <-time.After(time.Second * 3):74ok, err = t.Update()75if ok {76break outer77}78}79}80if err != nil {81return err82}83if t.tool.Name() == "Pikpak" {84return nil85}86if t.tool.Name() == "Thunder" {87return nil88}89if t.tool.Name() == "115 Cloud" {90// hack for 11591<-time.After(time.Second * 1)92err := t.tool.Remove(t)93if err != nil {94log.Errorln(err.Error())95}96return nil97}98t.Status = "offline download completed, maybe transferring"99// hack for qBittorrent100if t.tool.Name() == "qBittorrent" {101seedTime := setting.GetInt(conf.QbittorrentSeedtime, 0)102if seedTime >= 0 {103t.Status = "offline download completed, waiting for seeding"104<-time.After(time.Minute * time.Duration(seedTime))105err := t.tool.Remove(t)106if err != nil {107log.Errorln(err.Error())108}109}110}111112if t.tool.Name() == "Transmission" {113// hack for transmission114seedTime := setting.GetInt(conf.TransmissionSeedtime, 0)115if seedTime >= 0 {116t.Status = "offline download completed, waiting for seeding"117<-time.After(time.Minute * time.Duration(seedTime))118err := t.tool.Remove(t)119if err != nil {120log.Errorln(err.Error())121}122}123}124return nil125}126127// Update download status, return true if download completed128func (t *DownloadTask) Update() (bool, error) {129info, err := t.tool.Status(t)130if err != nil {131t.callStatusRetried++132log.Errorf("failed to get status of %s, retried %d times", t.ID, t.callStatusRetried)133return false, nil134}135if t.callStatusRetried > 5 {136return true, errors.Errorf("failed to get status of %s, retried %d times", t.ID, t.callStatusRetried)137}138t.callStatusRetried = 0139t.SetProgress(info.Progress)140t.SetTotalBytes(info.TotalBytes)141t.Status = fmt.Sprintf("[%s]: %s", t.tool.Name(), info.Status)142if info.NewGID != "" {143log.Debugf("followen by: %+v", info.NewGID)144t.GID = info.NewGID145return false, nil146}147// if download completed148if info.Completed {149err := t.Transfer()150return true, errors.WithMessage(err, "failed to transfer file")151}152// if download failed153if info.Err != nil {154return true, errors.Errorf("failed to download %s, error: %s", t.ID, info.Err.Error())155}156return false, nil157}158159func (t *DownloadTask) Transfer() error {160toolName := t.tool.Name()161if toolName == "115 Cloud" || toolName == "PikPak" || toolName == "Thunder" {162// 如果不是直接下载到目标路径,则进行转存163if t.TempDir != t.DstDirPath {164return transferObj(t.Ctx(), t.TempDir, t.DstDirPath, t.DeletePolicy)165}166return nil167}168return transferStd(t.Ctx(), t.TempDir, t.DstDirPath, t.DeletePolicy)169}170171func (t *DownloadTask) GetName() string {172return fmt.Sprintf("download %s to (%s)", t.Url, t.DstDirPath)173}174175func (t *DownloadTask) GetStatus() string {176return t.Status177}178179var DownloadTaskManager *tache.Manager[*DownloadTask]180181182