mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-11-25 03:15:19 +08:00
feat(offline_download): add 123 open (#1427)
This commit is contained in:
@@ -229,6 +229,14 @@ func (d *Open123) GetDetails(ctx context.Context) (*model.StorageDetails, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Open123) OfflineDownload(ctx context.Context, url string, dir model.Obj, callback string) (int, error) {
|
||||
return d.createOfflineDownloadTask(ctx, url, dir.GetID(), callback)
|
||||
}
|
||||
|
||||
func (d *Open123) OfflineDownloadProcess(ctx context.Context, taskID int) (float64, int, error) {
|
||||
return d.queryOfflineDownloadStatus(ctx, taskID)
|
||||
}
|
||||
|
||||
var (
|
||||
_ driver.Driver = (*Open123)(nil)
|
||||
_ driver.PutResult = (*Open123)(nil)
|
||||
|
||||
@@ -19,6 +19,7 @@ func (a *ApiInfo) Require() {
|
||||
a.token <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ApiInfo) Release() {
|
||||
if a.qps > 0 {
|
||||
time.AfterFunc(time.Second, func() {
|
||||
@@ -26,13 +27,16 @@ func (a *ApiInfo) Release() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ApiInfo) SetQPS(qps int) {
|
||||
a.qps = qps
|
||||
a.token = make(chan struct{}, qps)
|
||||
}
|
||||
|
||||
func (a *ApiInfo) NowLen() int {
|
||||
return len(a.token)
|
||||
}
|
||||
|
||||
func InitApiInfo(url string, qps int) *ApiInfo {
|
||||
return &ApiInfo{
|
||||
url: url,
|
||||
@@ -185,3 +189,18 @@ type UploadCompleteResp struct {
|
||||
FileID int64 `json:"fileID"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type OfflineDownloadResp struct {
|
||||
BaseResp
|
||||
Data struct {
|
||||
TaskID int `json:"taskID"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type OfflineDownloadProcessResp struct {
|
||||
BaseResp
|
||||
Data struct {
|
||||
Process float64 `json:"process"`
|
||||
Status int `json:"status"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ var ( // 不同情况下获取的AccessTokenQPS限制不同 如下模块化易
|
||||
Trash = InitApiInfo(Api+"/api/v1/file/trash", 2)
|
||||
UploadCreate = InitApiInfo(Api+"/upload/v2/file/create", 2)
|
||||
UploadComplete = InitApiInfo(Api+"/upload/v2/file/upload_complete", 0)
|
||||
|
||||
OfflineDownload = InitApiInfo(Api+"/api/v1/offline/download", 1)
|
||||
OfflineDownloadProcess = InitApiInfo(Api+"/api/v1/offline/download/process", 5)
|
||||
)
|
||||
|
||||
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 {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Open123) createOfflineDownloadTask(ctx context.Context, url string, dirID, callback string) (taskID int, err error) {
|
||||
body := base.Json{
|
||||
"url": url,
|
||||
"dirID": dirID,
|
||||
}
|
||||
if len(callback) > 0 {
|
||||
body["callBackUrl"] = callback
|
||||
}
|
||||
var resp OfflineDownloadResp
|
||||
_, err = d.Request(OfflineDownload, http.MethodPost, func(req *resty.Request) {
|
||||
req.SetBody(body)
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return resp.Data.TaskID, nil
|
||||
}
|
||||
|
||||
func (d *Open123) queryOfflineDownloadStatus(ctx context.Context, taskID int) (process float64, status int, err error) {
|
||||
var resp OfflineDownloadProcessResp
|
||||
_, err = d.Request(OfflineDownloadProcess, http.MethodGet, func(req *resty.Request) {
|
||||
req.SetQueryParams(map[string]string{
|
||||
"taskID": strconv.Itoa(taskID),
|
||||
})
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return .0, 0, err
|
||||
}
|
||||
return resp.Data.Process, resp.Data.Status, nil
|
||||
}
|
||||
|
||||
@@ -125,6 +125,10 @@ const (
|
||||
QbittorrentUrl = "qbittorrent_url"
|
||||
QbittorrentSeedtime = "qbittorrent_seedtime"
|
||||
|
||||
// 123 open offline download
|
||||
Pan123OpenOfflineDownloadCallbackUrl = "123_open_callback_url"
|
||||
Pan123OpenTempDir = "123_open_temp_dir"
|
||||
|
||||
// ftp
|
||||
FTPPublicHost = "ftp_public_host"
|
||||
FTPPasvPortMap = "ftp_pasv_port_map"
|
||||
|
||||
119
internal/offline_download/123_open/client.go
Normal file
119
internal/offline_download/123_open/client.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package _123_open
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/offline_download/tool"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/setting"
|
||||
)
|
||||
|
||||
type Open123 struct{}
|
||||
|
||||
func (*Open123) Name() string {
|
||||
return "123 Open"
|
||||
}
|
||||
|
||||
func (*Open123) Items() []model.SettingItem {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Open123) Run(_ *tool.DownloadTask) error {
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (*Open123) Init() (string, error) {
|
||||
return "ok", nil
|
||||
}
|
||||
|
||||
func (*Open123) IsReady() bool {
|
||||
tempDir := setting.GetStr(conf.Pan123OpenTempDir)
|
||||
if tempDir == "" {
|
||||
return false
|
||||
}
|
||||
storage, _, err := op.GetStorageAndActualPath(tempDir)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if _, ok := storage.(*_123_open.Open123); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*Open123) AddURL(args *tool.AddUrlArgs) (string, error) {
|
||||
storage, actualPath, err := op.GetStorageAndActualPath(args.TempDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
driver123Open, ok := storage.(*_123_open.Open123)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unsupported storage driver for offline download, only 123 Open is supported")
|
||||
}
|
||||
ctx := context.Background()
|
||||
if err := op.MakeDir(ctx, storage, actualPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
parentDir, err := op.GetUnwrap(ctx, storage, actualPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cb := setting.GetStr(conf.Pan123OpenOfflineDownloadCallbackUrl)
|
||||
taskID, err := driver123Open.OfflineDownload(ctx, args.Url, parentDir, cb)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to add offline download task: %w", err)
|
||||
}
|
||||
return strconv.Itoa(taskID), nil
|
||||
}
|
||||
|
||||
func (*Open123) Remove(_ *tool.DownloadTask) error {
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (*Open123) Status(task *tool.DownloadTask) (*tool.Status, error) {
|
||||
taskID, err := strconv.Atoi(task.GID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse task ID: %s", task.GID)
|
||||
}
|
||||
storage, _, err := op.GetStorageAndActualPath(task.TempDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
driver123Open, ok := storage.(*_123_open.Open123)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported storage driver for offline download, only 123 Open is supported")
|
||||
}
|
||||
process, status, err := driver123Open.OfflineDownloadProcess(context.Background(), taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var statusStr string
|
||||
switch status {
|
||||
case 0:
|
||||
statusStr = "downloading"
|
||||
case 1:
|
||||
err = fmt.Errorf("offline download failed")
|
||||
case 2:
|
||||
statusStr = "succeed"
|
||||
case 3:
|
||||
statusStr = "retrying"
|
||||
}
|
||||
return &tool.Status{
|
||||
Progress: process,
|
||||
Completed: status == 2,
|
||||
Status: statusStr,
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ tool.Tool = (*Open123)(nil)
|
||||
|
||||
func init() {
|
||||
tool.Tools.Add(&Open123{})
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package offline_download
|
||||
import (
|
||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115"
|
||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115_open"
|
||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/123_open"
|
||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/aria2"
|
||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/http"
|
||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/pikpak"
|
||||
|
||||
@@ -2,18 +2,16 @@ package tool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
||||
|
||||
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
||||
"github.com/OpenListTeam/OpenList/v4/server/common"
|
||||
|
||||
"net/url"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
|
||||
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
|
||||
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
||||
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunderx"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||
@@ -22,6 +20,7 @@ import (
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/setting"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/task"
|
||||
"github.com/OpenListTeam/OpenList/v4/server/common"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -104,6 +103,13 @@ func AddURL(ctx context.Context, args *AddURLArgs) (task.TaskExtensionInfo, erro
|
||||
} else {
|
||||
tempDir = filepath.Join(setting.GetStr(conf.Pan115OpenTempDir), uid)
|
||||
}
|
||||
case "123 Open":
|
||||
if _, ok := storage.(*_123_open.Open123); ok && dstDirActualPath != "/" {
|
||||
// directly offline downloading to the root path is not allowed via 123 open platform
|
||||
tempDir = args.DstDirPath
|
||||
} else {
|
||||
tempDir = filepath.Join(setting.GetStr(conf.Pan123OpenTempDir), uid)
|
||||
}
|
||||
case "PikPak":
|
||||
if _, ok := storage.(*pikpak.PikPak); ok {
|
||||
tempDir = args.DstDirPath
|
||||
|
||||
@@ -111,6 +111,9 @@ outer:
|
||||
if t.tool.Name() == "115 Open" {
|
||||
return nil
|
||||
}
|
||||
if t.tool.Name() == "123 Open" {
|
||||
return nil
|
||||
}
|
||||
t.Status = "offline download completed, maybe transferring"
|
||||
// hack for qBittorrent
|
||||
if t.tool.Name() == "qBittorrent" {
|
||||
@@ -174,7 +177,7 @@ func (t *DownloadTask) Update() (bool, error) {
|
||||
|
||||
func (t *DownloadTask) Transfer() error {
|
||||
toolName := t.tool.Name()
|
||||
if toolName == "115 Cloud" || toolName == "115 Open" || toolName == "PikPak" || toolName == "Thunder" || toolName == "ThunderX" || toolName == "ThunderBrowser" {
|
||||
if toolName == "115 Cloud" || toolName == "115 Open" || toolName == "123 Open" || toolName == "PikPak" || toolName == "Thunder" || toolName == "ThunderX" || toolName == "ThunderBrowser" {
|
||||
// 如果不是直接下载到目标路径,则进行转存
|
||||
if t.TempDir != t.DstDirPath {
|
||||
return transferObj(t.Ctx(), t.TempDir, t.DstDirPath, t.DeletePolicy)
|
||||
|
||||
@@ -2,9 +2,10 @@ package handles
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
|
||||
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
|
||||
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
||||
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
|
||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
||||
@@ -200,6 +201,52 @@ func Set115Open(c *gin.Context) {
|
||||
common.SuccessResp(c, "ok")
|
||||
}
|
||||
|
||||
type Set123OpenReq struct {
|
||||
TempDir string `json:"temp_dir" form:"temp_dir"`
|
||||
CallbackUrl string `json:"callback_url" form:"callback_url"`
|
||||
}
|
||||
|
||||
func Set123Open(c *gin.Context) {
|
||||
var req Set123OpenReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ErrorResp(c, err, 400)
|
||||
return
|
||||
}
|
||||
if req.TempDir != "" {
|
||||
storage, _, err := op.GetStorageAndActualPath(req.TempDir)
|
||||
if err != nil {
|
||||
common.ErrorStrResp(c, "storage does not exists", 400)
|
||||
return
|
||||
}
|
||||
if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK {
|
||||
common.ErrorStrResp(c, "storage not init: "+storage.GetStorage().Status, 400)
|
||||
return
|
||||
}
|
||||
if _, ok := storage.(*_123_open.Open123); !ok {
|
||||
common.ErrorStrResp(c, "unsupported storage driver for offline download, only 123 Open is supported", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
items := []model.SettingItem{
|
||||
{Key: conf.Pan123OpenTempDir, Value: req.TempDir, Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},
|
||||
{Key: conf.Pan123OpenOfflineDownloadCallbackUrl, Value: req.CallbackUrl, Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},
|
||||
}
|
||||
if err := op.SaveSettingItems(items); err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
_tool, err := tool.Tools.Get("123 Open")
|
||||
if err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
if _, err := _tool.Init(); err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
common.SuccessResp(c, "ok")
|
||||
}
|
||||
|
||||
type SetPikPakReq struct {
|
||||
TempDir string `json:"temp_dir" form:"temp_dir"`
|
||||
}
|
||||
@@ -413,7 +460,7 @@ func AddOfflineDownload(c *gin.Context) {
|
||||
if trimmedUrl == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
t, err := tool.AddURL(c, &tool.AddURLArgs{
|
||||
URL: trimmedUrl,
|
||||
DstDirPath: reqPath,
|
||||
|
||||
@@ -160,6 +160,7 @@ func admin(g *gin.RouterGroup) {
|
||||
setting.POST("/set_transmission", handles.SetTransmission)
|
||||
setting.POST("/set_115", handles.Set115)
|
||||
setting.POST("/set_115_open", handles.Set115Open)
|
||||
setting.POST("/set_123_open", handles.Set123Open)
|
||||
setting.POST("/set_pikpak", handles.SetPikPak)
|
||||
setting.POST("/set_thunder", handles.SetThunder)
|
||||
setting.POST("/set_thunderx", handles.SetThunderX)
|
||||
|
||||
Reference in New Issue
Block a user