refactor(baidu_photo): optimize code (close #2911 pr #2924)

pull/2933/head
foxxorcat 2023-01-06 15:36:05 +08:00 committed by GitHub
parent 4a0e47dbac
commit a1ded3a339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 303 additions and 235 deletions

View File

@ -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,17 +37,63 @@ 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) {
/* album */
if album, ok := dir.(*Album); ok {
var files []AlbumFile
files, err = d.GetAllAlbumFile(ctx, album, "")
if err != nil {
return nil, err
}
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)
@ -60,119 +110,105 @@ func (d *BaiduPhoto) List(ctx context.Context, dir model.Obj, args model.ListArg
}
}
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) {
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
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 file, ok := srcObj.(*AlbumFile); ok {
if _, ok := dstDir.(*Album); ok {
newObj, err := d.Copy(ctx, srcObj, dstDir)
if err != nil {
return err
return nil, err
}
e := splitID(srcObj.GetID())
return d.DeleteAlbumFile(ctx, e[1], e[2], srcObj.GetID())
// 删除原相册文件
_ = d.DeleteAlbumFile(ctx, file)
return newObj, nil
}
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)

View File

@ -8,7 +8,7 @@ import (
"strings"
"time"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
)
// Tid生成
@ -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(),
}
}

View File

@ -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,

View File

@ -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,6 +127,7 @@ type (
}
CopyFile struct {
FromFsid int64 `json:"from_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"`
}

View File

@ -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
}

View File

@ -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)