Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b8a77ee
feat(189pan):support transfer
mkitsdts Dec 1, 2025
35664fa
feat(alipan):support transfer
mkitsdts Dec 2, 2025
f3a98aa
feat(api):add transfer share file api
mkitsdts Dec 25, 2025
5af854c
feat(189pan):support transfer interface
mkitsdts Dec 25, 2025
430e380
feat(alipan):support transfer interface
mkitsdts Dec 25, 2025
c098c0f
fix(op/transfer):fix the wrong error handler
mkitsdts Dec 26, 2025
f128e81
fix(189pan):extract code error
mkitsdts Dec 26, 2025
8415ed1
feat(189panPC):support transfer interface
mkitsdts Dec 26, 2025
ac8b654
fix(189pan):type error
mkitsdts Dec 26, 2025
95c03ad
fix(189panPC):use exist function
mkitsdts Dec 26, 2025
309e79b
feat(quark_uc):support transfer interface
mkitsdts Dec 28, 2025
be7de1f
refactor:improve code robustness
mkitsdts Dec 28, 2025
ea364ed
Merge remote-tracking branch 'upstream'
mkitsdts Dec 30, 2025
4aa7895
chore(internal/op):rename unwrapobj function
mkitsdts Dec 30, 2025
3fc42cb
fix(pan189PC):transfer para error
mkitsdts Dec 30, 2025
94f1ba1
chore(internal/fs):add error check
mkitsdts Dec 30, 2025
41f8e7f
chore(code review):add more check in transfer interface
mkitsdts Dec 31, 2025
c8ee1ec
fix(quark_uc):transfer interface error
mkitsdts Jan 1, 2026
7f4a0cc
chore(transfer):add dir check
mkitsdts Jan 1, 2026
64f59d2
fix(transfer): bad cache handling
KirCute Jan 1, 2026
55e428e
chore(189pc):remove unnecessary request para
mkitsdts Jan 2, 2026
f1e88a4
Merge remote-tracking branch 'origin'
mkitsdts Jan 2, 2026
71e2acf
chore(189pc):check permission at first
mkitsdts Jan 4, 2026
d7da74b
chore(189PC):remove unnessary check
mkitsdts Jan 4, 2026
4212927
fix(webdav/drivers):add errors check
mkitsdts Jan 11, 2026
bcdb049
Merge branch 'OpenListTeam:main' into main
mkitsdts Jan 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions drivers/189/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package _189

import (
"context"
"fmt"
"net/http"
"strings"

Expand Down Expand Up @@ -207,4 +208,18 @@ func (d *Cloud189) GetDetails(ctx context.Context) (*model.StorageDetails, error
}, nil
}

func (d *Cloud189) Transfer(ctx context.Context, dst model.Obj, shareURL, validCode string) error {
sharecode := d.extractCode(shareURL)
if sharecode == "" {
return fmt.Errorf("need share code")
}

shareid, err := d.getSharedID(sharecode)
if err != nil {
return err
}

return d.transfer(dst, shareid)
}

var _ driver.Driver = (*Cloud189)(nil)
2 changes: 1 addition & 1 deletion drivers/189/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

func random() string {
return fmt.Sprintf("0.%17v", myrand.Rand.Int63n(100000000000000000))
return fmt.Sprintf("0.%017d", myrand.Rand.Int63n(1e17))
}

func RsaEncode(origData []byte, j_rsakey string, hex bool) string {
Expand Down
8 changes: 8 additions & 0 deletions drivers/189/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,11 @@ type CapacityResp struct {
} `json:"familyCapacityInfo"`
TotalSize uint64 `json:"totalSize"`
}

type GetSharedInfoResp struct {
ResCode int `json:"res_code"`
ResMessage string `json:"res_message"`
AccessCode string `json:"accessCode"`
ShareID int64 `json:"shareId"`
ExpireTime int64 `json:"expireTime"`
}
52 changes: 52 additions & 0 deletions drivers/189/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"io"
"math"
"net/http"
"net/url"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -406,3 +407,54 @@ func (d *Cloud189) getCapacityInfo(ctx context.Context) (*CapacityResp, error) {
}
return &resp, nil
}

func (d *Cloud189) getSharedID(code string) (int64, error) {
resp := GetSharedInfoResp{}
_, err := d.request("https://cloud.189.cn/api/open/share/getShareInfoByCodeV2.action", http.MethodGet, func(req *resty.Request) {
req.SetHeader("Accept", "application/json;charset=UTF-8")
req.SetQueryParams(map[string]string{
"code": code,
})
}, &resp)
if err != nil {
return 0, err
}
if resp.ResCode != 0 || resp.ResMessage != "成功" {
return 0, errors.New(resp.ResMessage)
}
return resp.ShareID, nil
}

func (d *Cloud189) extractCode(str string) string {
u, err := url.Parse(str)
if err != nil {
fmt.Println("invalid share url")
return ""
}
return u.Query().Get("code")
}

func (d *Cloud189) transfer(dstDir model.Obj, shareID int64) error {
taskInfos := []base.Json{
{
"fileId": dstDir.GetID(),
"fileName": dstDir.GetName(),
"isFolder": 1,
},
}

if !dstDir.IsDir() {
return fmt.Errorf("it should be in the folder")
}
taskInfosBytes, err := utils.Json.Marshal(taskInfos)
form := map[string]string{
"type": "SHARE_SAVE",
"targetFolderId": dstDir.GetID(),
"taskInfos": string(taskInfosBytes),
"shareId": fmt.Sprintf("%d", shareID),
}
_, err = d.request("https://cloud.189.cn/api/open/batch/createBatchTask.action", http.MethodPost, func(req *resty.Request) {
req.SetFormData(form)
}, nil)
return err
}
71 changes: 64 additions & 7 deletions drivers/189pc/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,29 +271,35 @@ func (y *Cloud189PC) Rename(ctx context.Context, srcObj model.Obj, newName strin
queryParam["familyId"] = y.FamilyID
}

var newObj model.Obj
switch f := srcObj.(type) {
switch srcObj.(type) {
case *Cloud189File:
fullUrl += "/renameFile.action"
queryParam["fileId"] = srcObj.GetID()
queryParam["destFileName"] = newName
newObj = &Cloud189File{Icon: f.Icon} // 复用预览
case *Cloud189Folder:
fullUrl += "/renameFolder.action"
queryParam["folderId"] = srcObj.GetID()
queryParam["destFolderName"] = newName
newObj = &Cloud189Folder{}
default:
return nil, errs.NotSupport
}

var resp RenameResp
_, err := y.request(fullUrl, method, func(req *resty.Request) {
req.SetContext(ctx).SetQueryParams(queryParam)
}, nil, newObj, isFamily)
}, nil, resp, isFamily)
if err != nil {
if resp.ResCode == "FileAlreadyExists" {
return nil, errs.ObjectAlreadyExists
}
return nil, err
}
return newObj, nil
switch f := srcObj.(type) {
case *Cloud189File:
return resp.toFile(f), nil
case *Cloud189Folder:
return resp.toFolder(), nil
}
return nil, errs.NotSupport
}

func (y *Cloud189PC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
Expand Down Expand Up @@ -431,3 +437,54 @@ func (y *Cloud189PC) GetDetails(ctx context.Context) (*model.StorageDetails, err
},
}, nil
}

func (y *Cloud189PC) Transfer(ctx context.Context, dst model.Obj, shareURL, validCode string) error {
sharecode := y.extractCode(shareURL)
if sharecode == "" {
return fmt.Errorf("need share code")
}
shareid, fileid, filename, err := y.getSharedInfo(sharecode)
if err != nil {
return err
}
if shareid == -1 {
return fmt.Errorf("failed get share id")
}

taskInfos := []base.Json{
{
"fileId": fileid,
"fileName": filename,
"isFolder": 1,
},
}

taskInfosBytes, err := utils.Json.Marshal(taskInfos)
if err != nil {
return err
}

form := map[string]string{
"targetFolderId": dst.GetID(),
"taskInfos": string(taskInfosBytes),
"shareId": fmt.Sprintf("%d", shareid),
}

resp, err := y.CreateBatchTask("SHARE_SAVE", y.FamilyID, dst.GetID(), form)

for {
state, err := y.CheckBatchTask("SHARE_SAVE", resp.TaskID)
if err != nil {
return err
}
switch state.TaskStatus {
case 4:
if state.FailedCount == 0 {
return nil
} else {
return fmt.Errorf("transfer failed")
}
}
time.Sleep(time.Millisecond * 400)
}
}
4 changes: 4 additions & 0 deletions drivers/189pc/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import (
"github.com/OpenListTeam/OpenList/v4/pkg/utils/random"
)

func random_num() string {
return fmt.Sprintf("0.%017d", random.Rand.Int63n(1e17))
}

func clientSuffix() map[string]string {
rand := random.Rand
return map[string]string{
Expand Down
53 changes: 52 additions & 1 deletion drivers/189pc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,9 @@ func (f *OldCommitUploadFileResp) toFile() *Cloud189File {
}

type CreateBatchTaskResp struct {
TaskID string `json:"taskId"`
ResCode int `json:"res_code"`
TaskID string `json:"taskId"`
ResMessage string `json:"res_message"`
}

type BatchTaskStateResp struct {
Expand All @@ -371,6 +373,7 @@ type BatchTaskStateResp struct {
SuccessedCount int `json:"successedCount"`
SuccessedFileIDList []int64 `json:"successedFileIdList"`
TaskID string `json:"taskId"`
ResMessage string `json:"res_message"`
TaskStatus int `json:"taskStatus"` //1 初始化 2 存在冲突 3 执行中,4 完成
}

Expand Down Expand Up @@ -427,3 +430,51 @@ type CapacityResp struct {
} `json:"familyCapacityInfo"`
TotalSize uint64 `json:"totalSize"`
}

type GetSharedInfoResp struct {
ResCode int `json:"res_code"`
ResMessage string `json:"res_message"`
AccessCode string `json:"accessCode"`
ShareID int64 `json:"shareId"`
ExpireTime int64 `json:"expireTime"`
FileName string `json:"fileName"`
FileId string `json:"fileId"`
}

type RenameResp struct {
ResMsg string `json:"res_message"`
CreateDate Time `json:"createDate"`
FileCate int `json:"fileCata"`
ID string `json:"id"`
LastOpTime Time `json:"lastOpTime"`
MD5 string `json:"md5"`
MediaType int `json:"mediaType"`
Name string `json:"name"`
Oeientation int `json:"orientation"`
ParentID int64 `json:"parentId"`
Rev string `json:"rev"`
Size int64 `json:"size"`
ResCode string `json:"res_code"`
}

func (r *RenameResp) toFile(f *Cloud189File) *Cloud189File {
return &Cloud189File{
ID: String(r.ID),
Name: r.Name,
Size: r.Size,
Md5: r.MD5,
LastOpTime: r.LastOpTime,
CreateDate: r.CreateDate,
Icon: f.Icon,
}
}

func (r *RenameResp) toFolder() *Cloud189Folder {
return &Cloud189Folder{
ID: String(r.ID),
Name: r.Name,
ParentID: r.ParentID,
LastOpTime: r.LastOpTime,
CreateDate: r.CreateDate,
}
}
48 changes: 48 additions & 0 deletions drivers/189pc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -1483,3 +1483,51 @@ func (y *Cloud189PC) getCapacityInfo(ctx context.Context) (*CapacityResp, error)
}
return &resp, nil
}

func (y *Cloud189PC) getSharedInfo(code string) (int64, string, string, error) {
resp := GetSharedInfoResp{}
sessionKey := y.getTokenInfo().SessionKey
if sessionKey == "" {
if err := y.refreshSession(); err != nil {
return -1, "", "", err
}
}
req := y.getClient().R().
SetHeader("Accept", "application/json;charset=UTF-8").
SetHeader("Referer", fmt.Sprintf("https://cloud.189.cn/web/share?code=%s", code)).
SetHeader("SessionKey", y.getTokenInfo().SessionKey).
SetQueryParams(map[string]string{
"noCache": random_num(),
"shareCode": code,
})
req.SetResult(&resp)
res, err := req.Execute(http.MethodGet, "https://cloud.189.cn/api/open/share/getShareInfoByCodeV2.action")

if strings.Contains(res.String(), "userSessionBO is null") {
if err = y.refreshSession(); err != nil {
return -1, "", "", err
}
return y.getSharedInfo(code)
}

if strings.Contains(res.String(), "InvalidSessionKey") {
if err = y.refreshSession(); err != nil {
return -1, "", "", err
}
return y.getSharedInfo(code)
}

if resp.ResCode != 0 || resp.ResMessage != "成功" {
return -1, "", "", errors.New(resp.ResMessage)
}
return resp.ShareID, resp.FileId, resp.FileName, nil
}

func (y *Cloud189PC) extractCode(str string) string {
u, err := url.Parse(str)
if err != nil {
fmt.Println("invalid share url")
return ""
}
return u.Query().Get("code")
}
42 changes: 42 additions & 0 deletions drivers/aliyundrive/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,46 @@ func (d *AliDrive) Other(ctx context.Context, args model.OtherArgs) (interface{}
return resp, nil
}

func (d *AliDrive) Transfer(ctx context.Context, dst model.Obj, shareURL, validCode string) error {
shareid := d.extractShareId(shareURL)
if shareid == "" {
return fmt.Errorf("invalid share url")
}
shareToken, err := d.getShareToken(shareid, validCode)
if err != nil {
return err
}
fileid, parent_fileid := d.getFileId(shareid, shareToken)
res, err, _ := d.request("https://api.aliyundrive.com/adrive/v4/batch", http.MethodPost, func(req *resty.Request) {
req.SetBody(base.Json{
"requests": []base.Json{
{
"headers": base.Json{
"Content-Type": "application/json",
},
"method": "POST",
"id": "0",
"body": base.Json{
"share_id": shareid,
"file_id": fileid,
"to_drive_id": dst.GetID(),
"to_parent_file_id": parent_fileid,
},
"url": "/file/copy",
},
},
"resource": "file",
})
req.SetHeader("X-Share-Token", shareToken)
}, nil)
if err != nil {
return err
}
status := utils.Json.Get(res, "responses", 0, "status").ToInt()
if status < 300 && status >= 100 {
return nil
}
return fmt.Errorf("transfer failed: %s", string(res))
}

var _ driver.Driver = (*AliDrive)(nil)
Loading
Loading