From 29165d8e608e52af047c4adb1d4f05584b007a5f Mon Sep 17 00:00:00 2001 From: Shelton Zhu <498220739@qq.com> Date: Sat, 10 Aug 2024 20:59:07 +0800 Subject: [PATCH] feat(115): add offline download tool (close #6888 in #6954) --- drivers/115/driver.go | 17 ++- go.mod | 2 +- go.sum | 6 +- internal/offline_download/115/client.go | 124 +++++++++++++++++++++ internal/offline_download/all.go | 1 + internal/offline_download/tool/add.go | 9 +- internal/offline_download/tool/download.go | 20 +++- 7 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 internal/offline_download/115/client.go diff --git a/drivers/115/driver.go b/drivers/115/driver.go index 57b6c45f..2a1c8dee 100644 --- a/drivers/115/driver.go +++ b/drivers/115/driver.go @@ -63,7 +63,7 @@ func (d *Pan115) Link(ctx context.Context, file model.Obj, args model.LinkArgs) if err := d.WaitLimit(ctx); err != nil { return nil, err } - var userAgent = args.Header.Get("User-Agent") + userAgent := args.Header.Get("User-Agent") downloadInfo, err := d. DownloadWithUA(file.(*FileObj).PickCode, userAgent) if err != nil { @@ -179,7 +179,22 @@ func (d *Pan115) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr } // 分片上传 return d.UploadByMultipart(&fastInfo.UploadOSSParams, stream.GetSize(), stream, dirID) +} +func (d *Pan115) OfflineList(ctx context.Context) ([]*driver115.OfflineTask, error) { + resp, err := d.client.ListOfflineTask(0) + if err != nil { + return nil, err + } + return resp.Tasks, nil +} + +func (d *Pan115) OfflineDownload(ctx context.Context, uris []string, dstDir model.Obj) ([]string, error) { + return d.client.AddOfflineTaskURIs(uris, dstDir.GetID()) +} + +func (d *Pan115) DeleteOfflineTasks(ctx context.Context, hashes []string, deleteFiles bool) error { + return d.client.DeleteOfflineTasks(hashes, deleteFiles) } var _ driver.Driver = (*Pan115)(nil) diff --git a/go.mod b/go.mod index 318da350..a6b042f1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/alist-org/alist/v3 go 1.22.4 require ( - github.com/SheltonZhu/115driver v1.0.25 + github.com/SheltonZhu/115driver v1.0.26 github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a github.com/Xhofe/rateg v0.0.0-20230728072201-251a4e1adad4 github.com/alist-org/gofakes3 v0.0.7 diff --git a/go.sum b/go.sum index 9de941c5..ecc7e897 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9 github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc= github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM= github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= -github.com/SheltonZhu/115driver v1.0.25 h1:i101yanLKUwV1Pi7x+vgNOwgz7Hp9JbNmo6BCZ9/4wo= -github.com/SheltonZhu/115driver v1.0.25/go.mod h1:e3fPOBANbH/FsTya8FquJwOR3ErhCQgEab3q6CVY2k4= +github.com/SheltonZhu/115driver v1.0.26 h1:UDUEZffJoQLFYs2nxnyxqvxwSaocxP4LNaOycVY6syU= +github.com/SheltonZhu/115driver v1.0.26/go.mod h1:e3fPOBANbH/FsTya8FquJwOR3ErhCQgEab3q6CVY2k4= github.com/Unknwon/goconfig v1.0.0 h1:9IAu/BYbSLQi8puFjUQApZTxIHqSwrj5d8vpP8vTq4A= github.com/Unknwon/goconfig v1.0.0/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a h1:RenIAa2q4H8UcS/cqmwdT1WCWIAH5aumP8m8RpbqVsE= @@ -550,8 +550,6 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= -golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= diff --git a/internal/offline_download/115/client.go b/internal/offline_download/115/client.go new file mode 100644 index 00000000..0ebf38ff --- /dev/null +++ b/internal/offline_download/115/client.go @@ -0,0 +1,124 @@ +package _115 + +import ( + "context" + "fmt" + + "github.com/alist-org/alist/v3/drivers/115" + "github.com/alist-org/alist/v3/internal/errs" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/offline_download/tool" + "github.com/alist-org/alist/v3/internal/op" +) + +type Cloud115 struct { + refreshTaskCache bool +} + +func (p *Cloud115) Name() string { + return "115 Cloud" +} + +func (p *Cloud115) Items() []model.SettingItem { + return nil +} + +func (p *Cloud115) Run(task *tool.DownloadTask) error { + return errs.NotSupport +} + +func (p *Cloud115) Init() (string, error) { + p.refreshTaskCache = false + return "ok", nil +} + +func (p *Cloud115) IsReady() bool { + return true +} + +func (p *Cloud115) AddURL(args *tool.AddUrlArgs) (string, error) { + // 添加新任务刷新缓存 + p.refreshTaskCache = true + // args.TempDir 已经被修改为了 DstDirPath + storage, actualPath, err := op.GetStorageAndActualPath(args.TempDir) + if err != nil { + return "", err + } + driver115, ok := storage.(*_115.Pan115) + if !ok { + return "", fmt.Errorf("unsupported storage driver for offline download, only 115 Cloud is supported") + } + + ctx := context.Background() + parentDir, err := op.GetUnwrap(ctx, storage, actualPath) + if err != nil { + return "", err + } + + hashs, err := driver115.OfflineDownload(ctx, []string{args.Url}, parentDir) + if err != nil || len(hashs) < 1 { + return "", fmt.Errorf("failed to add offline download task: %w", err) + } + + return hashs[0], nil +} + +func (p *Cloud115) Remove(task *tool.DownloadTask) error { + storage, _, err := op.GetStorageAndActualPath(task.DstDirPath) + if err != nil { + return err + } + driver115, ok := storage.(*_115.Pan115) + if !ok { + return fmt.Errorf("unsupported storage driver for offline download, only 115 Cloud is supported") + } + + ctx := context.Background() + if err := driver115.DeleteOfflineTasks(ctx, []string{task.GID}, false); err != nil { + return err + } + return nil +} + +func (p *Cloud115) Status(task *tool.DownloadTask) (*tool.Status, error) { + storage, _, err := op.GetStorageAndActualPath(task.DstDirPath) + if err != nil { + return nil, err + } + driver115, ok := storage.(*_115.Pan115) + if !ok { + return nil, fmt.Errorf("unsupported storage driver for offline download, only 115 Cloud is supported") + } + + tasks, err := driver115.OfflineList(context.Background()) + if err != nil { + return nil, err + } + + s := &tool.Status{ + Progress: 0, + NewGID: "", + Completed: false, + Status: "the task has been deleted", + Err: nil, + } + for _, t := range tasks { + if t.InfoHash == task.GID { + s.Progress = t.Percent + s.Status = t.GetStatus() + s.Completed = t.IsDone() + if t.IsFailed() { + s.Err = fmt.Errorf(t.GetStatus()) + } + return s, nil + } + } + s.Err = fmt.Errorf("the task has been deleted") + return nil, nil +} + +var _ tool.Tool = (*Cloud115)(nil) + +func init() { + tool.Tools.Add(&Cloud115{}) +} diff --git a/internal/offline_download/all.go b/internal/offline_download/all.go index 67869dee..ee80b5a0 100644 --- a/internal/offline_download/all.go +++ b/internal/offline_download/all.go @@ -1,6 +1,7 @@ package offline_download import ( + _ "github.com/alist-org/alist/v3/internal/offline_download/115" _ "github.com/alist-org/alist/v3/internal/offline_download/aria2" _ "github.com/alist-org/alist/v3/internal/offline_download/http" _ "github.com/alist-org/alist/v3/internal/offline_download/pikpak" diff --git a/internal/offline_download/tool/add.go b/internal/offline_download/tool/add.go index 372c73a6..c7c5c781 100644 --- a/internal/offline_download/tool/add.go +++ b/internal/offline_download/tool/add.go @@ -66,11 +66,18 @@ func AddURL(ctx context.Context, args *AddURLArgs) (tache.TaskWithInfo, error) { uid := uuid.NewString() tempDir := filepath.Join(conf.Conf.TempDir, args.Tool, uid) deletePolicy := args.DeletePolicy - if args.Tool == "pikpak" { + + switch args.Tool { + case "115 Cloud": + tempDir = args.DstDirPath + // 防止将下载好的文件删除 + deletePolicy = DeleteNever + case "pikpak": tempDir = args.DstDirPath // 防止将下载好的文件删除 deletePolicy = DeleteNever } + t := &DownloadTask{ Url: args.URL, DstDirPath: args.DstDirPath, diff --git a/internal/offline_download/tool/download.go b/internal/offline_download/tool/download.go index c778d936..4cc86a26 100644 --- a/internal/offline_download/tool/download.go +++ b/internal/offline_download/tool/download.go @@ -54,9 +54,7 @@ func (t *DownloadTask) Run() error { return err } t.GID = gid - var ( - ok bool - ) + var ok bool outer: for { select { @@ -81,6 +79,15 @@ outer: if t.tool.Name() == "pikpak" { return nil } + 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 + } t.Status = "offline download completed, maybe transferring" // hack for qBittorrent if t.tool.Name() == "qBittorrent" { @@ -136,6 +143,9 @@ func (t *DownloadTask) Complete() error { if t.tool.Name() == "pikpak" { return nil } + if t.tool.Name() == "115 Cloud" { + return nil + } if getFileser, ok := t.tool.(GetFileser); ok { files = getFileser.GetFiles(t) } else { @@ -166,6 +176,4 @@ func (t *DownloadTask) GetStatus() string { return t.Status } -var ( - DownloadTaskManager *tache.Manager[*DownloadTask] -) +var DownloadTaskManager *tache.Manager[*DownloadTask]