-
-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
994 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,277 @@ | ||
package baiduphoto | ||
|
||
import ( | ||
"context" | ||
"crypto/md5" | ||
"encoding/hex" | ||
"fmt" | ||
"io" | ||
"math" | ||
"os" | ||
"regexp" | ||
|
||
"github.com/alist-org/alist/v3/internal/driver" | ||
"github.com/alist-org/alist/v3/internal/errs" | ||
"github.com/alist-org/alist/v3/internal/model" | ||
"github.com/alist-org/alist/v3/pkg/utils" | ||
"github.com/go-resty/resty/v2" | ||
) | ||
|
||
type BaiduPhoto struct { | ||
model.Storage | ||
Addition | ||
|
||
AccessToken string | ||
} | ||
|
||
func (d *BaiduPhoto) Config() driver.Config { | ||
return config | ||
} | ||
|
||
func (d *BaiduPhoto) GetAddition() driver.Additional { | ||
return d.Addition | ||
} | ||
|
||
func (d *BaiduPhoto) Init(ctx context.Context, storage model.Storage) error { | ||
d.Storage = storage | ||
err := utils.Json.UnmarshalFromString(d.Storage.Addition, &d.Addition) | ||
if err != nil { | ||
return err | ||
} | ||
return d.refreshToken() | ||
} | ||
|
||
func (d *BaiduPhoto) Drop(ctx context.Context) error { | ||
return nil | ||
} | ||
|
||
func (d *BaiduPhoto) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { | ||
var objs []model.Obj | ||
var err error | ||
if IsRoot(dir) { | ||
var albums []Album | ||
if d.ShowType != "root_only_file" { | ||
albums, err = d.GetAllAlbum(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
var files []File | ||
if d.ShowType != "root_only_album" { | ||
files, err = d.GetAllFile(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
objs = make([]model.Obj, 0, len(files)+len(albums)) | ||
for i := 0; i < len(albums); i++ { | ||
objs = append(objs, &albums[i]) | ||
} | ||
for i := 0; i < len(files); i++ { | ||
objs = append(objs, &files[i]) | ||
} | ||
} else if IsAlbum(dir) || IsAlbumRoot(dir) { | ||
var files []AlbumFile | ||
files, err = d.GetAllAlbumFile(ctx, splitID(dir.GetID())[0], "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
objs = make([]model.Obj, 0, len(files)) | ||
for i := 0; i < len(files); i++ { | ||
objs = append(objs, &files[i]) | ||
} | ||
} | ||
return objs, nil | ||
} | ||
|
||
func (d *BaiduPhoto) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { | ||
if IsAlbumFile(file) { | ||
return d.linkAlbum(ctx, file, args) | ||
} else if IsFile(file) { | ||
return d.linkFile(ctx, file, args) | ||
} | ||
return nil, errs.NotFile | ||
} | ||
|
||
func (d *BaiduPhoto) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { | ||
if IsRoot(parentDir) { | ||
code := regexp.MustCompile(`(?i)join:([\S]*)`).FindStringSubmatch(dirName) | ||
if len(code) > 1 { | ||
return d.JoinAlbum(ctx, code[1]) | ||
} | ||
return d.CreateAlbum(ctx, dirName) | ||
} | ||
return errs.NotSupport | ||
} | ||
|
||
func (d *BaiduPhoto) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { | ||
if IsFile(srcObj) { | ||
if IsAlbum(dstDir) { | ||
//rootfile -> album | ||
e := splitID(dstDir.GetID()) | ||
return d.AddAlbumFile(ctx, e[0], e[1], srcObj.GetID()) | ||
} | ||
} else if IsAlbumFile(srcObj) { | ||
if IsRoot(dstDir) { | ||
//albumfile -> root | ||
e := splitID(srcObj.GetID()) | ||
_, err := d.CopyAlbumFile(ctx, e[1], e[2], e[3], srcObj.GetID()) | ||
return err | ||
} else if IsAlbum(dstDir) { | ||
// albumfile -> root -> album | ||
e := splitID(srcObj.GetID()) | ||
file, err := d.CopyAlbumFile(ctx, e[1], e[2], e[3], srcObj.GetID()) | ||
if err != nil { | ||
return err | ||
} | ||
e = splitID(dstDir.GetID()) | ||
return d.AddAlbumFile(ctx, e[0], e[1], fmt.Sprint(file.Fsid)) | ||
} | ||
} | ||
return errs.NotSupport | ||
} | ||
|
||
func (d *BaiduPhoto) Move(ctx context.Context, srcObj, dstDir model.Obj) error { | ||
// 仅支持相册之间移动 | ||
if IsAlbumFile(srcObj) && IsAlbum(dstDir) { | ||
err := d.Copy(ctx, srcObj, dstDir) | ||
if err != nil { | ||
return err | ||
} | ||
e := splitID(srcObj.GetID()) | ||
return d.DeleteAlbumFile(ctx, e[1], e[2], srcObj.GetID()) | ||
} | ||
return errs.NotSupport | ||
} | ||
|
||
func (d *BaiduPhoto) Rename(ctx context.Context, srcObj model.Obj, newName string) error { | ||
// 仅支持相册改名 | ||
if IsAlbum(srcObj) { | ||
e := splitID(srcObj.GetID()) | ||
return d.SetAlbumName(ctx, e[0], e[1], newName) | ||
} | ||
return errs.NotSupport | ||
} | ||
|
||
func (d *BaiduPhoto) Remove(ctx context.Context, obj model.Obj) error { | ||
e := splitID(obj.GetID()) | ||
if IsFile(obj) { | ||
return d.DeleteFile(ctx, e[0]) | ||
} else if IsAlbum(obj) { | ||
return d.DeleteAlbum(ctx, e[0], e[1]) | ||
} else if IsAlbumFile(obj) { | ||
return d.DeleteAlbumFile(ctx, e[1], e[2], obj.GetID()) | ||
} | ||
return errs.NotSupport | ||
} | ||
|
||
func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { | ||
// 需要获取完整文件md5,必须支持 io.Seek | ||
tempFile, err := utils.CreateTempFile(stream.GetReadCloser()) | ||
if err != nil { | ||
return err | ||
} | ||
defer func() { | ||
_ = tempFile.Close() | ||
_ = os.Remove(tempFile.Name()) | ||
}() | ||
stream.SetReadCloser(tempFile) | ||
|
||
// 计算需要的数据 | ||
const DEFAULT = 1 << 22 | ||
const SliceSize = 1 << 18 | ||
count := int(math.Ceil(float64(stream.GetSize()) / float64(DEFAULT))) | ||
|
||
sliceMD5List := make([]string, 0, count) | ||
fileMd5 := md5.New() | ||
sliceMd5 := md5.New() | ||
sliceMd52 := md5.New() | ||
slicemd52Write := utils.LimitWriter(sliceMd52, SliceSize) | ||
for i := 1; i <= count; i++ { | ||
select { | ||
case <-ctx.Done(): | ||
return ctx.Err() | ||
default: | ||
} | ||
_, err := io.CopyN(io.MultiWriter(fileMd5, sliceMd5, slicemd52Write), stream, DEFAULT) | ||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { | ||
return err | ||
} | ||
sliceMD5List = append(sliceMD5List, hex.EncodeToString(sliceMd5.Sum(nil))) | ||
sliceMd5.Reset() | ||
} | ||
if _, err = tempFile.Seek(0, io.SeekStart); err != nil { | ||
return err | ||
} | ||
content_md5 := hex.EncodeToString(fileMd5.Sum(nil)) | ||
slice_md5 := hex.EncodeToString(sliceMd52.Sum(nil)) | ||
|
||
// 开始执行上传 | ||
params := map[string]string{ | ||
"autoinit": "1", | ||
"isdir": "0", | ||
"rtype": "1", | ||
"ctype": "11", | ||
"path": stream.GetName(), | ||
"size": fmt.Sprint(stream.GetSize()), | ||
"slice-md5": slice_md5, | ||
"content-md5": content_md5, | ||
"block_list": MustString(utils.Json.MarshalToString(sliceMD5List)), | ||
} | ||
|
||
// 预上传 | ||
var precreateResp PrecreateResp | ||
_, err = d.Post(FILE_API_URL_V1+"/precreate", func(r *resty.Request) { | ||
r.SetContext(ctx) | ||
r.SetFormData(params) | ||
}, &precreateResp) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
switch precreateResp.ReturnType { | ||
case 1: // 上传文件 | ||
uploadParams := map[string]string{ | ||
"method": "upload", | ||
"path": params["path"], | ||
"uploadid": precreateResp.UploadID, | ||
} | ||
|
||
for i := 0; i < count; i++ { | ||
uploadParams["partseq"] = fmt.Sprint(i) | ||
_, err = d.Post("https://c3.pcs.baidu.com/rest/2.0/pcs/superfile2", func(r *resty.Request) { | ||
r.SetContext(ctx) | ||
r.SetQueryParams(uploadParams) | ||
r.SetFileReader("file", stream.GetName(), io.LimitReader(tempFile, DEFAULT)) | ||
}, nil) | ||
if err != nil { | ||
return err | ||
} | ||
up(i * 100 / count) | ||
} | ||
fallthrough | ||
case 2: // 创建文件 | ||
params["uploadid"] = precreateResp.UploadID | ||
_, err = d.Post(FILE_API_URL_V1+"/create", func(r *resty.Request) { | ||
r.SetContext(ctx) | ||
r.SetFormData(params) | ||
}, &precreateResp) | ||
if err != nil { | ||
return err | ||
} | ||
fallthrough | ||
case 3: // 增加到相册 | ||
if IsAlbum(dstDir) || IsAlbumRoot(dstDir) { | ||
e := splitID(dstDir.GetID()) | ||
err = d.AddAlbumFile(ctx, e[0], e[1], fmt.Sprint(precreateResp.Data.FsID)) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
var _ driver.Driver = (*BaiduPhoto)(nil) |
Oops, something went wrong.