2023-11-20 10:01:51 +00:00
|
|
|
package tool
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2024-01-20 05:06:46 +00:00
|
|
|
"time"
|
|
|
|
|
2023-12-11 07:20:29 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/conf"
|
2023-11-24 08:26:05 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/errs"
|
2023-12-11 07:20:29 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/setting"
|
2024-11-01 15:32:26 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/task"
|
2023-11-20 10:01:51 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/xhofe/tache"
|
|
|
|
)
|
|
|
|
|
|
|
|
type DownloadTask struct {
|
2024-12-25 13:09:54 +00:00
|
|
|
task.TaskExtension
|
2024-08-07 04:16:21 +00:00
|
|
|
Url string `json:"url"`
|
|
|
|
DstDirPath string `json:"dst_dir_path"`
|
|
|
|
TempDir string `json:"temp_dir"`
|
|
|
|
DeletePolicy DeletePolicy `json:"delete_policy"`
|
|
|
|
Toolname string `json:"toolname"`
|
|
|
|
Status string `json:"-"`
|
|
|
|
Signal chan int `json:"-"`
|
|
|
|
GID string `json:"-"`
|
2023-11-20 10:01:51 +00:00
|
|
|
tool Tool
|
|
|
|
callStatusRetried int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *DownloadTask) Run() error {
|
2024-12-25 13:09:54 +00:00
|
|
|
t.ClearEndTime()
|
|
|
|
t.SetStartTime(time.Now())
|
|
|
|
defer func() { t.SetEndTime(time.Now()) }()
|
2024-08-07 04:16:21 +00:00
|
|
|
if t.tool == nil {
|
|
|
|
tool, err := Tools.Get(t.Toolname)
|
|
|
|
if err != nil {
|
|
|
|
return errors.WithMessage(err, "failed get tool")
|
|
|
|
}
|
|
|
|
t.tool = tool
|
|
|
|
}
|
2023-11-24 08:26:05 +00:00
|
|
|
if err := t.tool.Run(t); !errs.IsNotSupportError(err) {
|
|
|
|
if err == nil {
|
|
|
|
return t.Complete()
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2023-11-20 10:01:51 +00:00
|
|
|
t.Signal = make(chan int)
|
|
|
|
defer func() {
|
|
|
|
t.Signal = nil
|
|
|
|
}()
|
|
|
|
gid, err := t.tool.AddURL(&AddUrlArgs{
|
|
|
|
Url: t.Url,
|
|
|
|
UID: t.ID,
|
|
|
|
TempDir: t.TempDir,
|
|
|
|
Signal: t.Signal,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
t.GID = gid
|
2024-08-10 12:59:07 +00:00
|
|
|
var ok bool
|
2023-11-20 10:01:51 +00:00
|
|
|
outer:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-t.CtxDone():
|
|
|
|
err := t.tool.Remove(t)
|
|
|
|
return err
|
|
|
|
case <-t.Signal:
|
|
|
|
ok, err = t.Update()
|
|
|
|
if ok {
|
|
|
|
break outer
|
|
|
|
}
|
|
|
|
case <-time.After(time.Second * 3):
|
|
|
|
ok, err = t.Update()
|
|
|
|
if ok {
|
|
|
|
break outer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-07-07 08:50:05 +00:00
|
|
|
if t.tool.Name() == "pikpak" {
|
|
|
|
return nil
|
|
|
|
}
|
2024-12-25 13:23:58 +00:00
|
|
|
if t.tool.Name() == "thunder" {
|
|
|
|
return nil
|
|
|
|
}
|
2024-08-10 12:59:07 +00:00
|
|
|
if t.tool.Name() == "115 Cloud" {
|
|
|
|
// hack for 115
|
|
|
|
<-time.After(time.Second * 1)
|
|
|
|
err := t.tool.Remove(t)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorln(err.Error())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2023-12-03 06:20:01 +00:00
|
|
|
t.Status = "offline download completed, maybe transferring"
|
2023-12-11 07:20:29 +00:00
|
|
|
// hack for qBittorrent
|
|
|
|
if t.tool.Name() == "qBittorrent" {
|
|
|
|
seedTime := setting.GetInt(conf.QbittorrentSeedtime, 0)
|
|
|
|
if seedTime >= 0 {
|
|
|
|
t.Status = "offline download completed, waiting for seeding"
|
2024-09-28 15:15:58 +00:00
|
|
|
<-time.After(time.Minute * time.Duration(seedTime))
|
|
|
|
err := t.tool.Remove(t)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorln(err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if t.tool.Name() == "transmission" {
|
|
|
|
// hack for transmission
|
|
|
|
seedTime := setting.GetInt(conf.TransmissionSeedtime, 0)
|
|
|
|
if seedTime >= 0 {
|
|
|
|
t.Status = "offline download completed, waiting for seeding"
|
2023-12-11 07:20:29 +00:00
|
|
|
<-time.After(time.Minute * time.Duration(seedTime))
|
|
|
|
err := t.tool.Remove(t)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorln(err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-20 10:01:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update download status, return true if download completed
|
|
|
|
func (t *DownloadTask) Update() (bool, error) {
|
|
|
|
info, err := t.tool.Status(t)
|
|
|
|
if err != nil {
|
|
|
|
t.callStatusRetried++
|
|
|
|
log.Errorf("failed to get status of %s, retried %d times", t.ID, t.callStatusRetried)
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
if t.callStatusRetried > 5 {
|
|
|
|
return true, errors.Errorf("failed to get status of %s, retried %d times", t.ID, t.callStatusRetried)
|
|
|
|
}
|
|
|
|
t.callStatusRetried = 0
|
|
|
|
t.SetProgress(info.Progress)
|
2024-12-25 13:09:54 +00:00
|
|
|
t.SetTotalBytes(info.TotalBytes)
|
2023-11-20 10:01:51 +00:00
|
|
|
t.Status = fmt.Sprintf("[%s]: %s", t.tool.Name(), info.Status)
|
|
|
|
if info.NewGID != "" {
|
|
|
|
log.Debugf("followen by: %+v", info.NewGID)
|
|
|
|
t.GID = info.NewGID
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
// if download completed
|
|
|
|
if info.Completed {
|
|
|
|
err := t.Complete()
|
|
|
|
return true, errors.WithMessage(err, "failed to transfer file")
|
|
|
|
}
|
|
|
|
// if download failed
|
|
|
|
if info.Err != nil {
|
|
|
|
return true, errors.Errorf("failed to download %s, error: %s", t.ID, info.Err.Error())
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *DownloadTask) Complete() error {
|
|
|
|
var (
|
|
|
|
files []File
|
|
|
|
err error
|
|
|
|
)
|
2024-07-07 08:50:05 +00:00
|
|
|
if t.tool.Name() == "pikpak" {
|
|
|
|
return nil
|
|
|
|
}
|
2024-12-25 13:23:58 +00:00
|
|
|
if t.tool.Name() == "thunder" {
|
|
|
|
return nil
|
|
|
|
}
|
2024-08-10 12:59:07 +00:00
|
|
|
if t.tool.Name() == "115 Cloud" {
|
|
|
|
return nil
|
|
|
|
}
|
2023-11-20 10:01:51 +00:00
|
|
|
if getFileser, ok := t.tool.(GetFileser); ok {
|
|
|
|
files = getFileser.GetFiles(t)
|
|
|
|
} else {
|
|
|
|
files, err = GetFiles(t.TempDir)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "failed to get files")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// upload files
|
2024-07-07 08:50:05 +00:00
|
|
|
for i := range files {
|
2023-11-20 10:01:51 +00:00
|
|
|
file := files[i]
|
2024-12-25 13:09:54 +00:00
|
|
|
tsk := &TransferTask{
|
|
|
|
TaskExtension: task.TaskExtension{
|
|
|
|
Creator: t.GetCreator(),
|
2024-11-01 15:32:26 +00:00
|
|
|
},
|
2023-11-24 07:02:36 +00:00
|
|
|
file: file,
|
2024-08-07 04:16:21 +00:00
|
|
|
DstDirPath: t.DstDirPath,
|
|
|
|
TempDir: t.TempDir,
|
|
|
|
DeletePolicy: t.DeletePolicy,
|
|
|
|
FileDir: file.Path,
|
2024-12-25 13:09:54 +00:00
|
|
|
}
|
|
|
|
tsk.SetTotalBytes(file.Size)
|
|
|
|
TransferTaskManager.Add(tsk)
|
2023-11-20 10:01:51 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *DownloadTask) GetName() string {
|
|
|
|
return fmt.Sprintf("download %s to (%s)", t.Url, t.DstDirPath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *DownloadTask) GetStatus() string {
|
|
|
|
return t.Status
|
|
|
|
}
|
|
|
|
|
2024-08-10 12:59:07 +00:00
|
|
|
var DownloadTaskManager *tache.Manager[*DownloadTask]
|