diff --git a/drivers/baidu_photo/driver.go b/drivers/baidu_photo/driver.go index 828e6ec6..0501c7ea 100644 --- a/drivers/baidu_photo/driver.go +++ b/drivers/baidu_photo/driver.go @@ -9,6 +9,8 @@ import ( "math" "os" "regexp" + "strconv" + "strings" "github.com/alist-org/alist/v3/internal/driver" "github.com/alist-org/alist/v3/internal/errs" @@ -22,6 +24,8 @@ type BaiduPhoto struct { Addition AccessToken string + Uk int64 + root model.Obj } func (d *BaiduPhoto) Config() driver.Config { @@ -33,146 +37,178 @@ func (d *BaiduPhoto) GetAddition() driver.Additional { } func (d *BaiduPhoto) Init(ctx context.Context) error { - return d.refreshToken() + if err := d.refreshToken(); err != nil { + return err + } + + // root + if d.AlbumID != "" { + albumID := strings.Split(d.AlbumID, "|")[0] + album, err := d.GetAlbumDetail(ctx, albumID) + if err != nil { + return err + } + d.root = album + } else { + d.root = &Root{ + Name: "root", + Modified: d.Modified, + IsFolder: true, + } + } + + // uk + info, err := d.uInfo() + if err != nil { + return err + } + d.Uk, err = strconv.ParseInt(info.YouaID, 10, 64) + return err +} + +func (d *BaiduPhoto) GetRoot(ctx context.Context) (model.Obj, error) { + return d.root, nil } func (d *BaiduPhoto) Drop(ctx context.Context) error { + d.AccessToken = "" + d.Uk = 0 + d.root = nil 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 - } - } - - alubmName := make(map[string]int) - objs, _ = utils.SliceConvert(albums, func(album Album) (model.Obj, error) { - i := alubmName[album.GetName()] - if i != 0 { - alubmName[album.GetName()]++ - album.Title = fmt.Sprintf("%s(%d)", album.Title, i) - } - alubmName[album.GetName()]++ - return &album, nil - }) - for i := 0; i < len(files); i++ { - objs = append(objs, &files[i]) - } - } else if IsAlbum(dir) || IsAlbumRoot(dir) { + /* album */ + if album, ok := dir.(*Album); ok { var files []AlbumFile - files, err = d.GetAllAlbumFile(ctx, splitID(dir.GetID())[0], "") + files, err = d.GetAllAlbumFile(ctx, album, "") 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 utils.MustSliceConvert(files, func(file AlbumFile) model.Obj { + return &file + }), nil + } + + /* root */ + var albums []Album + if d.ShowType != "root_only_file" { + albums, err = d.GetAllAlbum(ctx) + if err != nil { + return nil, err } } - return objs, nil + + var files []File + if d.ShowType != "root_only_album" { + files, err = d.GetAllFile(ctx) + if err != nil { + return nil, err + } + } + + return append( + utils.MustSliceConvert(albums, func(album Album) model.Obj { + return &album + }), + utils.MustSliceConvert(files, func(album File) model.Obj { + return &album + })..., + ), 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) { + switch file := file.(type) { + case *File: return d.linkFile(ctx, file, args) + case *AlbumFile: + return d.linkAlbum(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) +var joinReg = regexp.MustCompile(`(?i)join:([\S]*)`) + +func (d *BaiduPhoto) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) { + if _, ok := parentDir.(*Root); ok { + code := joinReg.FindStringSubmatch(dirName) if len(code) > 1 { return d.JoinAlbum(ctx, code[1]) } return d.CreateAlbum(ctx, dirName) } - return errs.NotSupport + return nil, errs.NotSupport } -func (d *BaiduPhoto) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - if IsFile(srcObj) { - if IsAlbum(dstDir) { +func (d *BaiduPhoto) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) { + switch file := srcObj.(type) { + case *File: + if album, ok := dstDir.(*Album); ok { //rootfile -> album - e := splitID(dstDir.GetID()) - return d.AddAlbumFile(ctx, e[0], e[1], srcObj.GetID()) + return d.AddAlbumFile(ctx, album, file) } - } else if IsAlbumFile(srcObj) { - if IsRoot(dstDir) { + case *AlbumFile: + switch album := dstDir.(type) { + case *Root: //albumfile -> root - e := splitID(srcObj.GetID()) - _, err := d.CopyAlbumFile(ctx, e[1], e[2], e[3], srcObj.GetID()) - return err - } else if IsAlbum(dstDir) { + return d.CopyAlbumFile(ctx, file) + case *Album: // albumfile -> root -> album - e := splitID(srcObj.GetID()) - file, err := d.CopyAlbumFile(ctx, e[1], e[2], e[3], srcObj.GetID()) + rootfile, err := d.CopyAlbumFile(ctx, file) if err != nil { - return err + return nil, err } - e = splitID(dstDir.GetID()) - return d.AddAlbumFile(ctx, e[0], e[1], fmt.Sprint(file.Fsid)) + return d.AddAlbumFile(ctx, album, rootfile) } } - return errs.NotSupport + return nil, errs.NotSupport } -func (d *BaiduPhoto) Move(ctx context.Context, srcObj, dstDir model.Obj) error { +func (d *BaiduPhoto) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) { // 仅支持相册之间移动 - if IsAlbumFile(srcObj) && IsAlbum(dstDir) { - err := d.Copy(ctx, srcObj, dstDir) - if err != nil { - return err + if file, ok := srcObj.(*AlbumFile); ok { + if _, ok := dstDir.(*Album); ok { + newObj, err := d.Copy(ctx, srcObj, dstDir) + if err != nil { + return nil, err + } + // 删除原相册文件 + _ = d.DeleteAlbumFile(ctx, file) + return newObj, nil } - e := splitID(srcObj.GetID()) - return d.DeleteAlbumFile(ctx, e[1], e[2], srcObj.GetID()) } - return errs.NotSupport + return nil, errs.NotSupport } -func (d *BaiduPhoto) Rename(ctx context.Context, srcObj model.Obj, newName string) error { +func (d *BaiduPhoto) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) { // 仅支持相册改名 - if IsAlbum(srcObj) { - e := splitID(srcObj.GetID()) - return d.SetAlbumName(ctx, e[0], e[1], newName) + if album, ok := srcObj.(*Album); ok { + return d.SetAlbumName(ctx, album, newName) } - return errs.NotSupport + return nil, 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()) + switch obj := obj.(type) { + case *File: + return d.DeleteFile(ctx, obj) + case *AlbumFile: + return d.DeleteAlbumFile(ctx, obj) + case *Album: + return d.DeleteAlbum(ctx, obj) } return errs.NotSupport } -func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { +func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) { // 需要获取完整文件md5,必须支持 io.Seek tempFile, err := utils.CreateTempFile(stream.GetReadCloser()) if err != nil { - return err + return nil, err } defer func() { _ = tempFile.Close() @@ -190,20 +226,19 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil sliceMd52 := md5.New() slicemd52Write := utils.LimitWriter(sliceMd52, SliceSize) for i := 1; i <= count; i++ { - select { - case <-ctx.Done(): - return ctx.Err() - default: + if utils.IsCanceled(ctx) { + return nil, ctx.Err() } + _, err := io.CopyN(io.MultiWriter(fileMd5, sliceMd5, slicemd52Write), tempFile, DEFAULT) if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { - return err + return nil, err } sliceMD5List = append(sliceMD5List, hex.EncodeToString(sliceMd5.Sum(nil))) sliceMd5.Reset() } if _, err = tempFile.Seek(0, io.SeekStart); err != nil { - return err + return nil, err } content_md5 := hex.EncodeToString(fileMd5.Sum(nil)) slice_md5 := hex.EncodeToString(sliceMd52.Sum(nil)) @@ -228,7 +263,7 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil r.SetFormData(params) }, &precreateResp) if err != nil { - return err + return nil, err } switch precreateResp.ReturnType { @@ -241,7 +276,7 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil for i := 0; i < count; i++ { if utils.IsCanceled(ctx) { - return ctx.Err() + return nil, ctx.Err() } uploadParams["partseq"] = fmt.Sprint(i) _, err = d.Post("https://c3.pcs.baidu.com/rest/2.0/pcs/superfile2", func(r *resty.Request) { @@ -250,7 +285,7 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil r.SetFileReader("file", stream.GetName(), io.LimitReader(tempFile, DEFAULT)) }, nil) if err != nil { - return err + return nil, err } up(i * 100 / count) } @@ -262,19 +297,24 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil r.SetFormData(params) }, &precreateResp) if err != nil { - return err + return nil, 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 - } + rootfile := precreateResp.Data.toFile() + if album, ok := dstDir.(*Album); ok { + return d.AddAlbumFile(ctx, album, rootfile) } + return rootfile, nil } - return nil + return nil, errs.NotSupport } var _ driver.Driver = (*BaiduPhoto)(nil) +var _ driver.Getter = (*BaiduPhoto)(nil) +var _ driver.MkdirResult = (*BaiduPhoto)(nil) +var _ driver.CopyResult = (*BaiduPhoto)(nil) +var _ driver.MoveResult = (*BaiduPhoto)(nil) +var _ driver.Remove = (*BaiduPhoto)(nil) +var _ driver.PutResult = (*BaiduPhoto)(nil) +var _ driver.RenameResult = (*BaiduPhoto)(nil) diff --git a/drivers/baidu_photo/help.go b/drivers/baidu_photo/help.go index 80c8e673..524f6a89 100644 --- a/drivers/baidu_photo/help.go +++ b/drivers/baidu_photo/help.go @@ -8,10 +8,10 @@ import ( "strings" "time" - "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/utils" ) -//Tid生成 +// Tid生成 func getTid() string { return fmt.Sprintf("3%d%.0f", time.Now().Unix(), math.Floor(9000000*rand.Float64()+1000000)) } @@ -26,82 +26,52 @@ func toTime(t int64) *time.Time { return &tm } -func fsidsFormat(ids ...string) string { - var buf []string - for _, id := range ids { - e := splitID(id) - buf = append(buf, fmt.Sprintf(`{"fsid":%s,"uk":%s}`, e[0], e[3])) - } +func fsidsFormatNotUk(ids ...int64) string { + buf := utils.MustSliceConvert(ids, func(id int64) string { + return fmt.Sprintf(`{"fsid":%d}`, id) + }) return fmt.Sprintf("[%s]", strings.Join(buf, ",")) } -func fsidsFormatNotUk(ids ...string) string { - var buf []string - for _, id := range ids { - buf = append(buf, fmt.Sprintf(`{"fsid":%s}`, splitID(id)[0])) - } - return fmt.Sprintf("[%s]", strings.Join(buf, ",")) -} - -/* -结构 - -{fsid} 文件 - -{album_id}|{tid} 相册 - -{fsid}|{album_id}|{tid}|{uk} 相册文件 -*/ -func splitID(id string) []string { - return strings.SplitN(id, "|", 4)[:4] -} - -/* -结构 - -{fsid} 文件 - -{album_id}|{tid} 相册 - -{fsid}|{album_id}|{tid}|{uk} 相册文件 -*/ -func joinID(ids ...interface{}) string { - idsStr := make([]string, 0, len(ids)) - for _, id := range ids { - idsStr = append(idsStr, fmt.Sprint(id)) - } - return strings.Join(idsStr, "|") -} - func getFileName(path string) string { return path[strings.LastIndex(path, "/")+1:] } -// 相册 -func IsAlbum(obj model.Obj) bool { - return obj.IsDir() && obj.GetPath() == "album" -} - -// 根目录 -func IsRoot(obj model.Obj) bool { - return obj.IsDir() && obj.GetPath() == "" && obj.GetID() == "" -} - -// 以相册为根目录 -func IsAlbumRoot(obj model.Obj) bool { - return obj.IsDir() && obj.GetPath() == "" && obj.GetID() != "" -} - -// 根文件 -func IsFile(obj model.Obj) bool { - return !obj.IsDir() && obj.GetPath() == "file" -} - -// 相册文件 -func IsAlbumFile(obj model.Obj) bool { - return !obj.IsDir() && obj.GetPath() == "albumfile" -} - func MustString(str string, err error) string { return str } + +/* +* 处理文件变化 +* 最大程度利用重复数据 +**/ +func copyFile(file *AlbumFile, cf *CopyFile) *File { + return &File{ + Fsid: cf.Fsid, + Path: cf.Path, + Ctime: cf.Ctime, + Mtime: cf.Ctime, + Size: file.Size, + Thumburl: file.Thumburl, + } +} + +func moveFileToAlbumFile(file *File, album *Album, uk int64) *AlbumFile { + return &AlbumFile{ + File: *file, + AlbumID: album.AlbumID, + Tid: album.Tid, + Uk: uk, + } +} + +func renameAlbum(album *Album, newName string) *Album { + return &Album{ + AlbumID: album.AlbumID, + Tid: album.Tid, + JoinTime: album.JoinTime, + CreateTime: album.CreateTime, + Title: newName, + Mtime: time.Now().Unix(), + } +} diff --git a/drivers/baidu_photo/meta.go b/drivers/baidu_photo/meta.go index 5c824229..06ab6046 100644 --- a/drivers/baidu_photo/meta.go +++ b/drivers/baidu_photo/meta.go @@ -14,10 +14,6 @@ type Addition struct { ClientSecret string `json:"client_secret" required:"true" default:"jXiFMOPVPCWlO2M5CwWQzffpNPaGTRBG"` } -func (a Addition) GetRootId() string { - return a.AlbumID -} - var config = driver.Config{ Name: "BaiduPhoto", LocalSort: true, diff --git a/drivers/baidu_photo/types.go b/drivers/baidu_photo/types.go index 4701fc51..b701a4da 100644 --- a/drivers/baidu_photo/types.go +++ b/drivers/baidu_photo/types.go @@ -3,6 +3,8 @@ package baiduphoto import ( "fmt" "time" + + "github.com/alist-org/alist/v3/internal/model" ) type TokenErrResp struct { @@ -19,6 +21,12 @@ type Erron struct { RequestID int `json:"request_id"` } +// 用户信息 +type UInfo struct { + // uk + YouaID string `json:"youa_id"` +} + type Page struct { HasMore int `json:"has_more"` Cursor string `json:"cursor"` @@ -28,6 +36,8 @@ func (p Page) HasNextPage() bool { return p.HasMore == 1 } +type Root = model.Object + type ( FileListResp struct { Page @@ -55,8 +65,8 @@ func (c *File) ModTime() time.Time { return *c.parseTime } func (c *File) IsDir() bool { return false } -func (c *File) GetID() string { return joinID(c.Fsid) } -func (c *File) GetPath() string { return "file" } +func (c *File) GetID() string { return "" } +func (c *File) GetPath() string { return "" } func (c *File) Thumb() string { if len(c.Thumburl) > 0 { return c.Thumburl[0] @@ -108,11 +118,8 @@ func (a *Album) ModTime() time.Time { return *a.parseTime } func (a *Album) IsDir() bool { return true } -func (a *Album) GetID() string { return joinID(a.AlbumID, a.Tid) } -func (a *Album) GetPath() string { return "album" } - -func (af *AlbumFile) GetID() string { return joinID(af.Fsid, af.AlbumID, af.Tid, af.Uk) } -func (c *AlbumFile) GetPath() string { return "albumfile" } +func (a *Album) GetID() string { return "" } +func (a *Album) GetPath() string { return "" } type ( CopyFileResp struct { @@ -120,7 +127,8 @@ type ( } CopyFile struct { FromFsid int64 `json:"from_fsid"` // 源ID - Fsid int64 `json:"fsid"` // 目标ID + Ctime int64 `json:"ctime"` + Fsid int64 `json:"fsid"` // 目标ID Path string `json:"path"` ShootTime int `json:"shoot_time"` } @@ -134,8 +142,8 @@ type ( Md5 string `json:"md5"` ServerFilename string `json:"server_filename"` Path string `json:"path"` - Ctime int `json:"ctime"` - Mtime int `json:"mtime"` + Ctime int64 `json:"ctime"` + Mtime int64 `json:"mtime"` Isdir int `json:"isdir"` Category int `json:"category"` ServerMd5 string `json:"server_md5"` @@ -158,6 +166,18 @@ type ( } ) +func (f *UploadFile) toFile() *File { + return &File{ + Fsid: f.FsID, + Path: f.Path, + Size: f.Size, + Ctime: f.Ctime, + Mtime: f.Mtime, + Thumburl: nil, + } +} + +/* 共享相册部分 */ type InviteResp struct { Pdata struct { // 邀请码 @@ -167,3 +187,9 @@ type InviteResp struct { ShareID string `json:"share_id"` } `json:"pdata"` } + +/* 加入相册部分 */ +type JoinOrCreateAlbumResp struct { + AlbumID string `json:"album_id"` + AlreadyExists int `json:"already_exists"` +} diff --git a/drivers/baidu_photo/utils.go b/drivers/baidu_photo/utils.go index 3aa763af..23264b9c 100644 --- a/drivers/baidu_photo/utils.go +++ b/drivers/baidu_photo/utils.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "net/http" - "strings" "github.com/alist-org/alist/v3/drivers/base" "github.com/alist-org/alist/v3/internal/errs" @@ -17,6 +16,7 @@ import ( const ( API_URL = "https://photo.baidu.com/youai" + USER_API_URL = API_URL + "/user/v1" ALBUM_API_URL = API_URL + "/album/v1" FILE_API_URL_V1 = API_URL + "/file/v1" FILE_API_URL_V2 = API_URL + "/file/v2" @@ -116,11 +116,11 @@ func (p *BaiduPhoto) GetAllFile(ctx context.Context) (files []File, err error) { } // 删除根文件 -func (p *BaiduPhoto) DeleteFile(ctx context.Context, fileIDs ...string) error { +func (p *BaiduPhoto) DeleteFile(ctx context.Context, file *File) error { _, err := p.Get(FILE_API_URL_V1+"/delete", func(req *resty.Request) { req.SetContext(ctx) req.SetQueryParams(map[string]string{ - "fsid_list": fmt.Sprintf("[%s]", strings.Join(fileIDs, ",")), + "fsid_list": fmt.Sprintf("[%d]", file.Fsid), }) }, nil) return err @@ -156,14 +156,14 @@ func (p *BaiduPhoto) GetAllAlbum(ctx context.Context) (albums []Album, err error } // 获取相册中所有文件 -func (p *BaiduPhoto) GetAllAlbumFile(ctx context.Context, albumID, passwd string) (files []AlbumFile, err error) { +func (p *BaiduPhoto) GetAllAlbumFile(ctx context.Context, album *Album, passwd string) (files []AlbumFile, err error) { var cursor string for { var resp AlbumFileListResp _, err = p.Get(ALBUM_API_URL+"/listfile", func(r *resty.Request) { r.SetContext(ctx) r.SetQueryParams(map[string]string{ - "album_id": albumID, + "album_id": album.AlbumID, "need_amount": "1", "limit": "1000", "passwd": passwd, @@ -187,45 +187,52 @@ func (p *BaiduPhoto) GetAllAlbumFile(ctx context.Context, albumID, passwd string } // 创建相册 -func (p *BaiduPhoto) CreateAlbum(ctx context.Context, name string) error { +func (p *BaiduPhoto) CreateAlbum(ctx context.Context, name string) (*Album, error) { if !checkName(name) { - return ErrNotSupportName + return nil, ErrNotSupportName } + var resp JoinOrCreateAlbumResp _, err := p.Post(ALBUM_API_URL+"/create", func(r *resty.Request) { - r.SetContext(ctx) + r.SetContext(ctx).SetResult(&resp) r.SetQueryParams(map[string]string{ "title": name, "tid": getTid(), "source": "0", }) }, nil) - return err + if err != nil { + return nil, err + } + return p.GetAlbumDetail(ctx, resp.AlbumID) } // 相册改名 -func (p *BaiduPhoto) SetAlbumName(ctx context.Context, albumID, tID, name string) error { +func (p *BaiduPhoto) SetAlbumName(ctx context.Context, album *Album, name string) (*Album, error) { if !checkName(name) { - return ErrNotSupportName + return nil, ErrNotSupportName } _, err := p.Post(ALBUM_API_URL+"/settitle", func(r *resty.Request) { r.SetContext(ctx) r.SetFormData(map[string]string{ "title": name, - "album_id": albumID, - "tid": tID, + "album_id": album.AlbumID, + "tid": fmt.Sprint(album.Tid), }) }, nil) - return err + if err != nil { + return nil, err + } + return renameAlbum(album, name), nil } // 删除相册 -func (p *BaiduPhoto) DeleteAlbum(ctx context.Context, albumID, tID string) error { +func (p *BaiduPhoto) DeleteAlbum(ctx context.Context, album *Album) error { _, err := p.Post(ALBUM_API_URL+"/delete", func(r *resty.Request) { r.SetContext(ctx) r.SetFormData(map[string]string{ - "album_id": albumID, - "tid": tID, + "album_id": album.AlbumID, + "tid": fmt.Sprint(album.Tid), "delete_origin_image": "0", // 是否删除原图 0 不删除 1 删除 }) }, nil) @@ -233,13 +240,13 @@ func (p *BaiduPhoto) DeleteAlbum(ctx context.Context, albumID, tID string) error } // 删除相册文件 -func (p *BaiduPhoto) DeleteAlbumFile(ctx context.Context, albumID, tID string, fileIDs ...string) error { +func (p *BaiduPhoto) DeleteAlbumFile(ctx context.Context, file *AlbumFile) error { _, err := p.Post(ALBUM_API_URL+"/delfile", func(r *resty.Request) { r.SetContext(ctx) r.SetFormData(map[string]string{ - "album_id": albumID, - "tid": tID, - "list": fsidsFormat(fileIDs...), + "album_id": fmt.Sprint(file.AlbumID), + "tid": fmt.Sprint(file.Tid), + "list": fmt.Sprintf(`[{"fsid":%d,"uk":%d}]`, file.Fsid, file.Uk), "del_origin": "0", // 是否删除原图 0 不删除 1 删除 }) }, nil) @@ -247,39 +254,42 @@ func (p *BaiduPhoto) DeleteAlbumFile(ctx context.Context, albumID, tID string, f } // 增加相册文件 -func (p *BaiduPhoto) AddAlbumFile(ctx context.Context, albumID, tID string, fileIDs ...string) error { +func (p *BaiduPhoto) AddAlbumFile(ctx context.Context, album *Album, file *File) (*AlbumFile, error) { _, err := p.Get(ALBUM_API_URL+"/addfile", func(r *resty.Request) { r.SetContext(ctx) r.SetQueryParams(map[string]string{ - "album_id": albumID, - "tid": tID, - "list": fsidsFormatNotUk(fileIDs...), + "album_id": fmt.Sprint(album.AlbumID), + "tid": fmt.Sprint(album.Tid), + "list": fsidsFormatNotUk(file.Fsid), }) }, nil) - return err + if err != nil { + return nil, err + } + return moveFileToAlbumFile(file, album, p.Uk), nil } // 保存相册文件为根文件 -func (p *BaiduPhoto) CopyAlbumFile(ctx context.Context, albumID, tID, uk string, fileID ...string) (*CopyFile, error) { +func (p *BaiduPhoto) CopyAlbumFile(ctx context.Context, file *AlbumFile) (*File, error) { var resp CopyFileResp _, err := p.Post(ALBUM_API_URL+"/copyfile", func(r *resty.Request) { r.SetContext(ctx) r.SetFormData(map[string]string{ - "album_id": albumID, - "tid": tID, - "uk": uk, - "list": fsidsFormatNotUk(fileID...), + "album_id": file.AlbumID, + "tid": fmt.Sprint(file.Tid), + "uk": fmt.Sprint(file.Uk), + "list": fsidsFormatNotUk(file.Fsid), }) r.SetResult(&resp) }, nil) if err != nil { return nil, err } - return &resp.List[0], nil + return copyFile(file, &resp.List[0]), nil } // 加入相册 -func (p *BaiduPhoto) JoinAlbum(ctx context.Context, code string) error { +func (p *BaiduPhoto) JoinAlbum(ctx context.Context, code string) (*Album, error) { var resp InviteResp _, err := p.Get(ALBUM_API_URL+"/querypcode", func(req *resty.Request) { req.SetContext(ctx) @@ -289,18 +299,37 @@ func (p *BaiduPhoto) JoinAlbum(ctx context.Context, code string) error { }) }, &resp) if err != nil { - return err + return nil, err } + var resp2 JoinOrCreateAlbumResp _, err = p.Get(ALBUM_API_URL+"/join", func(req *resty.Request) { req.SetContext(ctx) req.SetQueryParams(map[string]string{ "invite_code": resp.Pdata.InviteCode, }) - }, nil) - return err + }, &resp2) + if err != nil { + return nil, err + } + return p.GetAlbumDetail(ctx, resp2.AlbumID) } -func (d *BaiduPhoto) linkAlbum(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { +// 获取相册详细信息 +func (p *BaiduPhoto) GetAlbumDetail(ctx context.Context, albumID string) (*Album, error) { + var album Album + _, err := p.Get(ALBUM_API_URL+"/detail", func(req *resty.Request) { + req.SetContext(ctx).SetResult(&album) + req.SetQueryParams(map[string]string{ + "album_id": albumID, + }) + }, &album) + if err != nil { + return nil, err + } + return &album, nil +} + +func (d *BaiduPhoto) linkAlbum(ctx context.Context, file *AlbumFile, args model.LinkArgs) (*model.Link, error) { headers := map[string]string{ "User-Agent": base.UserAgent, } @@ -311,16 +340,15 @@ func (d *BaiduPhoto) linkAlbum(ctx context.Context, file model.Obj, args model.L headers["X-Forwarded-For"] = args.IP } - e := splitID(file.GetID()) res, err := base.NoRedirectClient.R(). SetContext(ctx). SetHeaders(headers). SetQueryParams(map[string]string{ "access_token": d.AccessToken, - "fsid": e[0], - "album_id": e[1], - "tid": e[2], - "uk": e[3], + "fsid": fmt.Sprint(file.Fsid), + "album_id": file.AlbumID, + "tid": fmt.Sprint(file.Tid), + "uk": fmt.Sprint(file.Uk), }). Head(ALBUM_API_URL + "/download") @@ -328,19 +356,17 @@ func (d *BaiduPhoto) linkAlbum(ctx context.Context, file model.Obj, args model.L return nil, err } - //exp := 8 * time.Hour link := &model.Link{ URL: res.Header().Get("location"), Header: http.Header{ "User-Agent": []string{headers["User-Agent"]}, "Referer": []string{"https://photo.baidu.com/"}, }, - //Expiration: &exp, } return link, nil } -func (d *BaiduPhoto) linkFile(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { +func (d *BaiduPhoto) linkFile(ctx context.Context, file *File, args model.LinkArgs) (*model.Link, error) { headers := map[string]string{ "User-Agent": base.UserAgent, } @@ -358,21 +384,31 @@ func (d *BaiduPhoto) linkFile(ctx context.Context, file model.Obj, args model.Li r.SetContext(ctx) r.SetHeaders(headers) r.SetQueryParams(map[string]string{ - "fsid": splitID(file.GetID())[0], + "fsid": fmt.Sprint(file.Fsid), }) }, &downloadUrl) if err != nil { return nil, err } - //exp := 8 * time.Hour link := &model.Link{ URL: downloadUrl.Dlink, Header: http.Header{ "User-Agent": []string{headers["User-Agent"]}, "Referer": []string{"https://photo.baidu.com/"}, }, - //Expiration: &exp, } return link, nil } + +// 获取uk +func (d *BaiduPhoto) uInfo() (*UInfo, error) { + var info UInfo + _, err := d.Get(USER_API_URL+"/getuinfo", func(req *resty.Request) { + + }, &info) + if err != nil { + return nil, err + } + return &info, nil +} diff --git a/pkg/utils/slice.go b/pkg/utils/slice.go index a9733eb2..8d2aa2a2 100644 --- a/pkg/utils/slice.go +++ b/pkg/utils/slice.go @@ -31,7 +31,7 @@ func SliceContains[T comparable](arr []T, v T) bool { // SliceConvert convert slice to another type slice func SliceConvert[S any, D any](srcS []S, convert func(src S) (D, error)) ([]D, error) { - var res []D + res := make([]D, 0, len(srcS)) for i := range srcS { dst, err := convert(srcS[i]) if err != nil { @@ -43,7 +43,7 @@ func SliceConvert[S any, D any](srcS []S, convert func(src S) (D, error)) ([]D, } func MustSliceConvert[S any, D any](srcS []S, convert func(src S) D) []D { - var res []D + res := make([]D, 0, len(srcS)) for i := range srcS { dst := convert(srcS[i]) res = append(res, dst)