Skip to content

Commit 2bfbad2

Browse files
authored
feat(offline_download): add 123 open (#1427)
1 parent 4ba7696 commit 2bfbad2

File tree

10 files changed

+250
-8
lines changed

10 files changed

+250
-8
lines changed

drivers/123_open/driver.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ func (d *Open123) GetDetails(ctx context.Context) (*model.StorageDetails, error)
229229
}, nil
230230
}
231231

232+
func (d *Open123) OfflineDownload(ctx context.Context, url string, dir model.Obj, callback string) (int, error) {
233+
return d.createOfflineDownloadTask(ctx, url, dir.GetID(), callback)
234+
}
235+
236+
func (d *Open123) OfflineDownloadProcess(ctx context.Context, taskID int) (float64, int, error) {
237+
return d.queryOfflineDownloadStatus(ctx, taskID)
238+
}
239+
232240
var (
233241
_ driver.Driver = (*Open123)(nil)
234242
_ driver.PutResult = (*Open123)(nil)

drivers/123_open/types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,24 @@ func (a *ApiInfo) Require() {
1919
a.token <- struct{}{}
2020
}
2121
}
22+
2223
func (a *ApiInfo) Release() {
2324
if a.qps > 0 {
2425
time.AfterFunc(time.Second, func() {
2526
<-a.token
2627
})
2728
}
2829
}
30+
2931
func (a *ApiInfo) SetQPS(qps int) {
3032
a.qps = qps
3133
a.token = make(chan struct{}, qps)
3234
}
35+
3336
func (a *ApiInfo) NowLen() int {
3437
return len(a.token)
3538
}
39+
3640
func InitApiInfo(url string, qps int) *ApiInfo {
3741
return &ApiInfo{
3842
url: url,
@@ -185,3 +189,18 @@ type UploadCompleteResp struct {
185189
FileID int64 `json:"fileID"`
186190
} `json:"data"`
187191
}
192+
193+
type OfflineDownloadResp struct {
194+
BaseResp
195+
Data struct {
196+
TaskID int `json:"taskID"`
197+
} `json:"data"`
198+
}
199+
200+
type OfflineDownloadProcessResp struct {
201+
BaseResp
202+
Data struct {
203+
Process float64 `json:"process"`
204+
Status int `json:"status"`
205+
} `json:"data"`
206+
}

drivers/123_open/util.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ var ( // 不同情况下获取的AccessTokenQPS限制不同 如下模块化易
3434
Trash = InitApiInfo(Api+"/api/v1/file/trash", 2)
3535
UploadCreate = InitApiInfo(Api+"/upload/v2/file/create", 2)
3636
UploadComplete = InitApiInfo(Api+"/upload/v2/file/upload_complete", 0)
37+
38+
OfflineDownload = InitApiInfo(Api+"/api/v1/offline/download", 1)
39+
OfflineDownloadProcess = InitApiInfo(Api+"/api/v1/offline/download/process", 5)
3740
)
3841

3942
func (d *Open123) Request(apiInfo *ApiInfo, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
@@ -277,3 +280,34 @@ func (d *Open123) trash(fileId int64) error {
277280

278281
return nil
279282
}
283+
284+
func (d *Open123) createOfflineDownloadTask(ctx context.Context, url string, dirID, callback string) (taskID int, err error) {
285+
body := base.Json{
286+
"url": url,
287+
"dirID": dirID,
288+
}
289+
if len(callback) > 0 {
290+
body["callBackUrl"] = callback
291+
}
292+
var resp OfflineDownloadResp
293+
_, err = d.Request(OfflineDownload, http.MethodPost, func(req *resty.Request) {
294+
req.SetBody(body)
295+
}, &resp)
296+
if err != nil {
297+
return 0, err
298+
}
299+
return resp.Data.TaskID, nil
300+
}
301+
302+
func (d *Open123) queryOfflineDownloadStatus(ctx context.Context, taskID int) (process float64, status int, err error) {
303+
var resp OfflineDownloadProcessResp
304+
_, err = d.Request(OfflineDownloadProcess, http.MethodGet, func(req *resty.Request) {
305+
req.SetQueryParams(map[string]string{
306+
"taskID": strconv.Itoa(taskID),
307+
})
308+
}, &resp)
309+
if err != nil {
310+
return .0, 0, err
311+
}
312+
return resp.Data.Process, resp.Data.Status, nil
313+
}

internal/conf/const.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ const (
125125
QbittorrentUrl = "qbittorrent_url"
126126
QbittorrentSeedtime = "qbittorrent_seedtime"
127127

128+
// 123 open offline download
129+
Pan123OpenOfflineDownloadCallbackUrl = "123_open_callback_url"
130+
Pan123OpenTempDir = "123_open_temp_dir"
131+
128132
// ftp
129133
FTPPublicHost = "ftp_public_host"
130134
FTPPasvPortMap = "ftp_pasv_port_map"
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package _123_open
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
8+
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
9+
"github.com/OpenListTeam/OpenList/v4/internal/conf"
10+
"github.com/OpenListTeam/OpenList/v4/internal/errs"
11+
"github.com/OpenListTeam/OpenList/v4/internal/model"
12+
"github.com/OpenListTeam/OpenList/v4/internal/offline_download/tool"
13+
"github.com/OpenListTeam/OpenList/v4/internal/op"
14+
"github.com/OpenListTeam/OpenList/v4/internal/setting"
15+
)
16+
17+
type Open123 struct{}
18+
19+
func (*Open123) Name() string {
20+
return "123 Open"
21+
}
22+
23+
func (*Open123) Items() []model.SettingItem {
24+
return nil
25+
}
26+
27+
func (*Open123) Run(_ *tool.DownloadTask) error {
28+
return errs.NotSupport
29+
}
30+
31+
func (*Open123) Init() (string, error) {
32+
return "ok", nil
33+
}
34+
35+
func (*Open123) IsReady() bool {
36+
tempDir := setting.GetStr(conf.Pan123OpenTempDir)
37+
if tempDir == "" {
38+
return false
39+
}
40+
storage, _, err := op.GetStorageAndActualPath(tempDir)
41+
if err != nil {
42+
return false
43+
}
44+
if _, ok := storage.(*_123_open.Open123); !ok {
45+
return false
46+
}
47+
return true
48+
}
49+
50+
func (*Open123) AddURL(args *tool.AddUrlArgs) (string, error) {
51+
storage, actualPath, err := op.GetStorageAndActualPath(args.TempDir)
52+
if err != nil {
53+
return "", err
54+
}
55+
driver123Open, ok := storage.(*_123_open.Open123)
56+
if !ok {
57+
return "", fmt.Errorf("unsupported storage driver for offline download, only 123 Open is supported")
58+
}
59+
ctx := context.Background()
60+
if err := op.MakeDir(ctx, storage, actualPath); err != nil {
61+
return "", err
62+
}
63+
parentDir, err := op.GetUnwrap(ctx, storage, actualPath)
64+
if err != nil {
65+
return "", err
66+
}
67+
cb := setting.GetStr(conf.Pan123OpenOfflineDownloadCallbackUrl)
68+
taskID, err := driver123Open.OfflineDownload(ctx, args.Url, parentDir, cb)
69+
if err != nil {
70+
return "", fmt.Errorf("failed to add offline download task: %w", err)
71+
}
72+
return strconv.Itoa(taskID), nil
73+
}
74+
75+
func (*Open123) Remove(_ *tool.DownloadTask) error {
76+
return errs.NotSupport
77+
}
78+
79+
func (*Open123) Status(task *tool.DownloadTask) (*tool.Status, error) {
80+
taskID, err := strconv.Atoi(task.GID)
81+
if err != nil {
82+
return nil, fmt.Errorf("failed to parse task ID: %s", task.GID)
83+
}
84+
storage, _, err := op.GetStorageAndActualPath(task.TempDir)
85+
if err != nil {
86+
return nil, err
87+
}
88+
driver123Open, ok := storage.(*_123_open.Open123)
89+
if !ok {
90+
return nil, fmt.Errorf("unsupported storage driver for offline download, only 123 Open is supported")
91+
}
92+
process, status, err := driver123Open.OfflineDownloadProcess(context.Background(), taskID)
93+
if err != nil {
94+
return nil, err
95+
}
96+
var statusStr string
97+
switch status {
98+
case 0:
99+
statusStr = "downloading"
100+
case 1:
101+
err = fmt.Errorf("offline download failed")
102+
case 2:
103+
statusStr = "succeed"
104+
case 3:
105+
statusStr = "retrying"
106+
}
107+
return &tool.Status{
108+
Progress: process,
109+
Completed: status == 2,
110+
Status: statusStr,
111+
Err: err,
112+
}, nil
113+
}
114+
115+
var _ tool.Tool = (*Open123)(nil)
116+
117+
func init() {
118+
tool.Tools.Add(&Open123{})
119+
}

internal/offline_download/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package offline_download
33
import (
44
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115"
55
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115_open"
6+
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/123_open"
67
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/aria2"
78
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/http"
89
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/pikpak"

internal/offline_download/tool/add.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@ package tool
22

33
import (
44
"context"
5-
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
6-
7-
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
8-
"github.com/OpenListTeam/OpenList/v4/server/common"
9-
105
"net/url"
116
stdpath "path"
127
"path/filepath"
138

149
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
10+
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
11+
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
1512
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
1613
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
14+
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
1715
"github.com/OpenListTeam/OpenList/v4/drivers/thunderx"
1816
"github.com/OpenListTeam/OpenList/v4/internal/conf"
1917
"github.com/OpenListTeam/OpenList/v4/internal/errs"
@@ -22,6 +20,7 @@ import (
2220
"github.com/OpenListTeam/OpenList/v4/internal/op"
2321
"github.com/OpenListTeam/OpenList/v4/internal/setting"
2422
"github.com/OpenListTeam/OpenList/v4/internal/task"
23+
"github.com/OpenListTeam/OpenList/v4/server/common"
2524
"github.com/google/uuid"
2625
"github.com/pkg/errors"
2726
)
@@ -104,6 +103,13 @@ func AddURL(ctx context.Context, args *AddURLArgs) (task.TaskExtensionInfo, erro
104103
} else {
105104
tempDir = filepath.Join(setting.GetStr(conf.Pan115OpenTempDir), uid)
106105
}
106+
case "123 Open":
107+
if _, ok := storage.(*_123_open.Open123); ok && dstDirActualPath != "/" {
108+
// directly offline downloading to the root path is not allowed via 123 open platform
109+
tempDir = args.DstDirPath
110+
} else {
111+
tempDir = filepath.Join(setting.GetStr(conf.Pan123OpenTempDir), uid)
112+
}
107113
case "PikPak":
108114
if _, ok := storage.(*pikpak.PikPak); ok {
109115
tempDir = args.DstDirPath

internal/offline_download/tool/download.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ outer:
111111
if t.tool.Name() == "115 Open" {
112112
return nil
113113
}
114+
if t.tool.Name() == "123 Open" {
115+
return nil
116+
}
114117
t.Status = "offline download completed, maybe transferring"
115118
// hack for qBittorrent
116119
if t.tool.Name() == "qBittorrent" {
@@ -174,7 +177,7 @@ func (t *DownloadTask) Update() (bool, error) {
174177

175178
func (t *DownloadTask) Transfer() error {
176179
toolName := t.tool.Name()
177-
if toolName == "115 Cloud" || toolName == "115 Open" || toolName == "PikPak" || toolName == "Thunder" || toolName == "ThunderX" || toolName == "ThunderBrowser" {
180+
if toolName == "115 Cloud" || toolName == "115 Open" || toolName == "123 Open" || toolName == "PikPak" || toolName == "Thunder" || toolName == "ThunderX" || toolName == "ThunderBrowser" {
178181
// 如果不是直接下载到目标路径,则进行转存
179182
if t.TempDir != t.DstDirPath {
180183
return transferObj(t.Ctx(), t.TempDir, t.DstDirPath, t.DeletePolicy)

server/handles/offline_download.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package handles
22

33
import (
44
"strings"
5-
5+
66
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
77
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
8+
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
89
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
910
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
1011
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
@@ -200,6 +201,52 @@ func Set115Open(c *gin.Context) {
200201
common.SuccessResp(c, "ok")
201202
}
202203

204+
type Set123OpenReq struct {
205+
TempDir string `json:"temp_dir" form:"temp_dir"`
206+
CallbackUrl string `json:"callback_url" form:"callback_url"`
207+
}
208+
209+
func Set123Open(c *gin.Context) {
210+
var req Set123OpenReq
211+
if err := c.ShouldBind(&req); err != nil {
212+
common.ErrorResp(c, err, 400)
213+
return
214+
}
215+
if req.TempDir != "" {
216+
storage, _, err := op.GetStorageAndActualPath(req.TempDir)
217+
if err != nil {
218+
common.ErrorStrResp(c, "storage does not exists", 400)
219+
return
220+
}
221+
if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK {
222+
common.ErrorStrResp(c, "storage not init: "+storage.GetStorage().Status, 400)
223+
return
224+
}
225+
if _, ok := storage.(*_123_open.Open123); !ok {
226+
common.ErrorStrResp(c, "unsupported storage driver for offline download, only 123 Open is supported", 400)
227+
return
228+
}
229+
}
230+
items := []model.SettingItem{
231+
{Key: conf.Pan123OpenTempDir, Value: req.TempDir, Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},
232+
{Key: conf.Pan123OpenOfflineDownloadCallbackUrl, Value: req.CallbackUrl, Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},
233+
}
234+
if err := op.SaveSettingItems(items); err != nil {
235+
common.ErrorResp(c, err, 500)
236+
return
237+
}
238+
_tool, err := tool.Tools.Get("123 Open")
239+
if err != nil {
240+
common.ErrorResp(c, err, 500)
241+
return
242+
}
243+
if _, err := _tool.Init(); err != nil {
244+
common.ErrorResp(c, err, 500)
245+
return
246+
}
247+
common.SuccessResp(c, "ok")
248+
}
249+
203250
type SetPikPakReq struct {
204251
TempDir string `json:"temp_dir" form:"temp_dir"`
205252
}
@@ -413,7 +460,7 @@ func AddOfflineDownload(c *gin.Context) {
413460
if trimmedUrl == "" {
414461
continue
415462
}
416-
463+
417464
t, err := tool.AddURL(c, &tool.AddURLArgs{
418465
URL: trimmedUrl,
419466
DstDirPath: reqPath,

server/router.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ func admin(g *gin.RouterGroup) {
160160
setting.POST("/set_transmission", handles.SetTransmission)
161161
setting.POST("/set_115", handles.Set115)
162162
setting.POST("/set_115_open", handles.Set115Open)
163+
setting.POST("/set_123_open", handles.Set123Open)
163164
setting.POST("/set_pikpak", handles.SetPikPak)
164165
setting.POST("/set_thunder", handles.SetThunder)
165166
setting.POST("/set_thunderx", handles.SetThunderX)

0 commit comments

Comments
 (0)