Skip to content

Commit f0b1aea

Browse files
anobodysanobodysxhofeCopilot
authored
feat(doubao): support upload (#8302 close #8335)
* feat(doubao): support upload * fix(doubao): fix file list cursor * fix: handle strconv.Atoi err Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: anobodys <[email protected]> Co-authored-by: Andy Hsu <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent c8470b9 commit f0b1aea

File tree

4 files changed

+1396
-45
lines changed

4 files changed

+1396
-45
lines changed

drivers/doubao/driver.go

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,25 @@ package doubao
33
import (
44
"context"
55
"errors"
6-
"time"
7-
86
"github.com/alist-org/alist/v3/drivers/base"
97
"github.com/alist-org/alist/v3/internal/driver"
108
"github.com/alist-org/alist/v3/internal/errs"
119
"github.com/alist-org/alist/v3/internal/model"
10+
"github.com/alist-org/alist/v3/pkg/utils"
1211
"github.com/go-resty/resty/v2"
1312
"github.com/google/uuid"
13+
"net/http"
14+
"strconv"
15+
"strings"
16+
"time"
1417
)
1518

1619
type Doubao struct {
1720
model.Storage
1821
Addition
22+
*UploadToken
23+
UserId string
24+
uploadThread int
1925
}
2026

2127
func (d *Doubao) Config() driver.Config {
@@ -29,6 +35,31 @@ func (d *Doubao) GetAddition() driver.Additional {
2935
func (d *Doubao) Init(ctx context.Context) error {
3036
// TODO login / refresh token
3137
//op.MustSaveDriverStorage(d)
38+
uploadThread, err := strconv.Atoi(d.UploadThread)
39+
if err != nil || uploadThread < 1 {
40+
d.uploadThread, d.UploadThread = 3, "3" // Set default value
41+
} else {
42+
d.uploadThread = uploadThread
43+
}
44+
45+
if d.UserId == "" {
46+
userInfo, err := d.getUserInfo()
47+
if err != nil {
48+
return err
49+
}
50+
51+
d.UserId = strconv.FormatInt(userInfo.UserID, 10)
52+
}
53+
54+
if d.UploadToken == nil {
55+
uploadToken, err := d.initUploadToken()
56+
if err != nil {
57+
return err
58+
}
59+
60+
d.UploadToken = uploadToken
61+
}
62+
3263
return nil
3364
}
3465

@@ -38,18 +69,12 @@ func (d *Doubao) Drop(ctx context.Context) error {
3869

3970
func (d *Doubao) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
4071
var files []model.Obj
41-
var r NodeInfoResp
42-
_, err := d.request("/samantha/aispace/node_info", "POST", func(req *resty.Request) {
43-
req.SetBody(base.Json{
44-
"node_id": dir.GetID(),
45-
"need_full_path": false,
46-
})
47-
}, &r)
72+
fileList, err := d.getFiles(dir.GetID(), "")
4873
if err != nil {
4974
return nil, err
5075
}
5176

52-
for _, child := range r.Data.Children {
77+
for _, child := range fileList {
5378
files = append(files, &Object{
5479
Object: model.Object{
5580
ID: child.ID,
@@ -60,34 +85,65 @@ func (d *Doubao) List(ctx context.Context, dir model.Obj, args model.ListArgs) (
6085
Ctime: time.Unix(child.CreateTime, 0),
6186
IsFolder: child.NodeType == 1,
6287
},
63-
Key: child.Key,
88+
Key: child.Key,
89+
NodeType: child.NodeType,
6490
})
6591
}
92+
6693
return files, nil
6794
}
6895

6996
func (d *Doubao) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
97+
var downloadUrl string
98+
7099
if u, ok := file.(*Object); ok {
71-
var r GetFileUrlResp
72-
_, err := d.request("/alice/message/get_file_url", "POST", func(req *resty.Request) {
73-
req.SetBody(base.Json{
74-
"uris": []string{u.Key},
75-
"type": "file",
76-
})
77-
}, &r)
78-
if err != nil {
79-
return nil, err
100+
switch u.NodeType {
101+
case VideoType, AudioType:
102+
var r GetVideoFileUrlResp
103+
_, err := d.request("/samantha/media/get_play_info", http.MethodPost, func(req *resty.Request) {
104+
req.SetBody(base.Json{
105+
"key": u.Key,
106+
"node_id": file.GetID(),
107+
})
108+
}, &r)
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
downloadUrl = r.Data.OriginalMediaInfo.MainURL
114+
default:
115+
var r GetFileUrlResp
116+
_, err := d.request("/alice/message/get_file_url", http.MethodPost, func(req *resty.Request) {
117+
req.SetBody(base.Json{
118+
"uris": []string{u.Key},
119+
"type": FileNodeType[u.NodeType],
120+
})
121+
}, &r)
122+
if err != nil {
123+
return nil, err
124+
}
125+
126+
downloadUrl = r.Data.FileUrls[0].MainURL
80127
}
128+
129+
// 生成标准的Content-Disposition
130+
contentDisposition := generateContentDisposition(u.Name)
131+
81132
return &model.Link{
82-
URL: r.Data.FileUrls[0].MainURL,
133+
URL: downloadUrl,
134+
Header: http.Header{
135+
"User-Agent": []string{UserAgent},
136+
"Content-Disposition": []string{contentDisposition},
137+
},
83138
}, nil
84139
}
140+
85141
return nil, errors.New("can't convert obj to URL")
86142
}
87143

88144
func (d *Doubao) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
89145
var r UploadNodeResp
90-
_, err := d.request("/samantha/aispace/upload_node", "POST", func(req *resty.Request) {
146+
_, err := d.request("/samantha/aispace/upload_node", http.MethodPost, func(req *resty.Request) {
91147
req.SetBody(base.Json{
92148
"node_list": []base.Json{
93149
{
@@ -104,7 +160,7 @@ func (d *Doubao) MakeDir(ctx context.Context, parentDir model.Obj, dirName strin
104160

105161
func (d *Doubao) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
106162
var r UploadNodeResp
107-
_, err := d.request("/samantha/aispace/move_node", "POST", func(req *resty.Request) {
163+
_, err := d.request("/samantha/aispace/move_node", http.MethodPost, func(req *resty.Request) {
108164
req.SetBody(base.Json{
109165
"node_list": []base.Json{
110166
{"id": srcObj.GetID()},
@@ -118,7 +174,7 @@ func (d *Doubao) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
118174

119175
func (d *Doubao) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
120176
var r BaseResp
121-
_, err := d.request("/samantha/aispace/rename_node", "POST", func(req *resty.Request) {
177+
_, err := d.request("/samantha/aispace/rename_node", http.MethodPost, func(req *resty.Request) {
122178
req.SetBody(base.Json{
123179
"node_id": srcObj.GetID(),
124180
"node_name": newName,
@@ -134,15 +190,38 @@ func (d *Doubao) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj,
134190

135191
func (d *Doubao) Remove(ctx context.Context, obj model.Obj) error {
136192
var r BaseResp
137-
_, err := d.request("/samantha/aispace/delete_node", "POST", func(req *resty.Request) {
193+
_, err := d.request("/samantha/aispace/delete_node", http.MethodPost, func(req *resty.Request) {
138194
req.SetBody(base.Json{"node_list": []base.Json{{"id": obj.GetID()}}})
139195
}, &r)
140196
return err
141197
}
142198

143199
func (d *Doubao) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
144-
// TODO upload file, optional
145-
return nil, errs.NotImplement
200+
// 根据MIME类型确定数据类型
201+
mimetype := file.GetMimetype()
202+
dataType := FileDataType
203+
204+
switch {
205+
case strings.HasPrefix(mimetype, "video/"):
206+
dataType = VideoDataType
207+
case strings.HasPrefix(mimetype, "audio/"):
208+
dataType = VideoDataType // 音频与视频使用相同的处理方式
209+
case strings.HasPrefix(mimetype, "image/"):
210+
dataType = ImgDataType
211+
}
212+
213+
// 获取上传配置
214+
uploadConfig := UploadConfig{}
215+
if err := d.getUploadConfig(&uploadConfig, dataType, file); err != nil {
216+
return nil, err
217+
}
218+
219+
// 根据文件大小选择上传方式
220+
if file.GetSize() <= 1*utils.MB { // 小于1MB,使用普通模式上传
221+
return d.Upload(&uploadConfig, dstDir, file, up, dataType)
222+
}
223+
// 大文件使用分片上传
224+
return d.UploadByMultipart(ctx, &uploadConfig, file.GetSize(), dstDir, file, up, dataType)
146225
}
147226

148227
func (d *Doubao) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) {

drivers/doubao/meta.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ type Addition struct {
1010
// driver.RootPath
1111
driver.RootID
1212
// define other
13-
Cookie string `json:"cookie" type:"text"`
13+
Cookie string `json:"cookie" type:"text"`
14+
UploadThread string `json:"upload_thread" default:"3"`
1415
}
1516

1617
var config = driver.Config{
@@ -19,7 +20,7 @@ var config = driver.Config{
1920
OnlyLocal: false,
2021
OnlyProxy: false,
2122
NoCache: false,
22-
NoUpload: true,
23+
NoUpload: false,
2324
NeedMs: false,
2425
DefaultRoot: "0",
2526
CheckStatus: false,

0 commit comments

Comments
 (0)