Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 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
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 @@ -204,4 +205,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
}
51 changes: 51 additions & 0 deletions drivers/189pc/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,54 @@ func (y *Cloud189PC) GetDetails(ctx context.Context) (*model.StorageDetails, err
DiskUsage: driver.DiskUsageFromUsedAndTotal(used, total),
}, 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
15 changes: 14 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,13 @@ 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"`
}
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 @@ -368,4 +368,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)
9 changes: 9 additions & 0 deletions drivers/aliyundrive/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,12 @@ type UploadResp struct {

RapidUpload bool `json:"rapid_upload"`
}

type SharedTokenResp struct {
ShareToken string `json:"share_token"`
}

type ShareInfoResp struct {
FileId string `json:"file_id"`
ParentFileId string `json:"parent_file_id"`
}
46 changes: 46 additions & 0 deletions drivers/aliyundrive/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net/http"
"regexp"

"github.com/OpenListTeam/OpenList/v4/drivers/base"
"github.com/OpenListTeam/OpenList/v4/internal/op"
Expand Down Expand Up @@ -202,3 +203,48 @@ func (d *AliDrive) batch(srcId, dstId string, url string) error {
}
return errors.New(string(res))
}

func (d *AliDrive) getShareToken(shareid, share_pwd string) (string, error) {
resp := SharedTokenResp{}
_, err, _ := d.request("https://api.aliyundrive.com/v2/share_link/get_share_token", http.MethodPost, func(req *resty.Request) {
req.SetBody(base.Json{
"share_id": shareid,
"share_pwd": share_pwd,
})
}, resp)
if err != nil {
return "", err
}
return resp.ShareToken, nil
}

func (d *AliDrive) getFileId(shareid, token string) (string, string) {
resp := ShareInfoResp{}
_, err, _ := d.request("https://api.aliyundrive.com/adrive/v2/file/list_by_share", http.MethodPost, func(req *resty.Request) {
req.SetHeader("x-share-token", token)
req.SetBody(base.Json{
"share_id": shareid,
"order_by": "name",
"order_direction": "DESC",
"limit": 20,
"parent_file_id": "root",
"image_thumbnail_process": "image/resize,w_256/format,jpeg",
"image_url_process": "image/resize,w_1920/format,jpeg/interlace,1",
"video_thumbnail_process": "video/snapshot,t_1000,f_jpg,ar_auto,w_256",
})
}, &resp)
if err != nil {
return "", ""
}
return resp.FileId, resp.ParentFileId
}

func (d *AliDrive) extractShareId(shareUrl string) string {
// https://www.alipan.com/s/XVDFP7mpuZK
re := regexp.MustCompile(`https?://(?:[a-zA-Z0-9-]+\.)*alipan\.com(?:\:\d+)?/s/([a-zA-Z0-9_-]+)`)
matches := re.FindStringSubmatch(shareUrl)
if len(matches) >= 2 {
return matches[1]
}
return ""
}
Loading