@@ -3,19 +3,25 @@ package doubao
33import (
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
1619type Doubao struct {
1720 model.Storage
1821 Addition
22+ * UploadToken
23+ UserId string
24+ uploadThread int
1925}
2026
2127func (d * Doubao ) Config () driver.Config {
@@ -29,6 +35,31 @@ func (d *Doubao) GetAddition() driver.Additional {
2935func (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
3970func (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
6996func (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
88144func (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
105161func (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
119175func (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
135191func (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
143199func (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
148227func (d * Doubao ) GetArchiveMeta (ctx context.Context , obj model.Obj , args model.ArchiveArgs ) (model.ArchiveMeta , error ) {
0 commit comments