@@ -3,19 +3,25 @@ package doubao
3
3
import (
4
4
"context"
5
5
"errors"
6
- "time"
7
-
8
6
"github.com/alist-org/alist/v3/drivers/base"
9
7
"github.com/alist-org/alist/v3/internal/driver"
10
8
"github.com/alist-org/alist/v3/internal/errs"
11
9
"github.com/alist-org/alist/v3/internal/model"
10
+ "github.com/alist-org/alist/v3/pkg/utils"
12
11
"github.com/go-resty/resty/v2"
13
12
"github.com/google/uuid"
13
+ "net/http"
14
+ "strconv"
15
+ "strings"
16
+ "time"
14
17
)
15
18
16
19
type Doubao struct {
17
20
model.Storage
18
21
Addition
22
+ * UploadToken
23
+ UserId string
24
+ uploadThread int
19
25
}
20
26
21
27
func (d * Doubao ) Config () driver.Config {
@@ -29,6 +35,31 @@ func (d *Doubao) GetAddition() driver.Additional {
29
35
func (d * Doubao ) Init (ctx context.Context ) error {
30
36
// TODO login / refresh token
31
37
//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
+
32
63
return nil
33
64
}
34
65
@@ -38,18 +69,12 @@ func (d *Doubao) Drop(ctx context.Context) error {
38
69
39
70
func (d * Doubao ) List (ctx context.Context , dir model.Obj , args model.ListArgs ) ([]model.Obj , error ) {
40
71
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 (), "" )
48
73
if err != nil {
49
74
return nil , err
50
75
}
51
76
52
- for _ , child := range r . Data . Children {
77
+ for _ , child := range fileList {
53
78
files = append (files , & Object {
54
79
Object : model.Object {
55
80
ID : child .ID ,
@@ -60,34 +85,65 @@ func (d *Doubao) List(ctx context.Context, dir model.Obj, args model.ListArgs) (
60
85
Ctime : time .Unix (child .CreateTime , 0 ),
61
86
IsFolder : child .NodeType == 1 ,
62
87
},
63
- Key : child .Key ,
88
+ Key : child .Key ,
89
+ NodeType : child .NodeType ,
64
90
})
65
91
}
92
+
66
93
return files , nil
67
94
}
68
95
69
96
func (d * Doubao ) Link (ctx context.Context , file model.Obj , args model.LinkArgs ) (* model.Link , error ) {
97
+ var downloadUrl string
98
+
70
99
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
80
127
}
128
+
129
+ // 生成标准的Content-Disposition
130
+ contentDisposition := generateContentDisposition (u .Name )
131
+
81
132
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
+ },
83
138
}, nil
84
139
}
140
+
85
141
return nil , errors .New ("can't convert obj to URL" )
86
142
}
87
143
88
144
func (d * Doubao ) MakeDir (ctx context.Context , parentDir model.Obj , dirName string ) error {
89
145
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 ) {
91
147
req .SetBody (base.Json {
92
148
"node_list" : []base.Json {
93
149
{
@@ -104,7 +160,7 @@ func (d *Doubao) MakeDir(ctx context.Context, parentDir model.Obj, dirName strin
104
160
105
161
func (d * Doubao ) Move (ctx context.Context , srcObj , dstDir model.Obj ) error {
106
162
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 ) {
108
164
req .SetBody (base.Json {
109
165
"node_list" : []base.Json {
110
166
{"id" : srcObj .GetID ()},
@@ -118,7 +174,7 @@ func (d *Doubao) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
118
174
119
175
func (d * Doubao ) Rename (ctx context.Context , srcObj model.Obj , newName string ) error {
120
176
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 ) {
122
178
req .SetBody (base.Json {
123
179
"node_id" : srcObj .GetID (),
124
180
"node_name" : newName ,
@@ -134,15 +190,38 @@ func (d *Doubao) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj,
134
190
135
191
func (d * Doubao ) Remove (ctx context.Context , obj model.Obj ) error {
136
192
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 ) {
138
194
req .SetBody (base.Json {"node_list" : []base.Json {{"id" : obj .GetID ()}}})
139
195
}, & r )
140
196
return err
141
197
}
142
198
143
199
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 )
146
225
}
147
226
148
227
func (d * Doubao ) GetArchiveMeta (ctx context.Context , obj model.Obj , args model.ArchiveArgs ) (model.ArchiveMeta , error ) {
0 commit comments