feat(offline_download): add 123 open (#1427)

This commit is contained in:
KirCute
2025-10-07 01:13:25 +08:00
committed by GitHub
parent 4ba7696032
commit 2bfbad2874
10 changed files with 250 additions and 8 deletions

View File

@@ -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)

View File

@@ -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"`
}

View File

@@ -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
}

View File

@@ -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"

View 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{})
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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)

View File

@@ -5,6 +5,7 @@ import (
_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"`
}

View File

@@ -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)