alist/drivers/baidu_photo/utils.go

377 lines
9.1 KiB
Go
Raw Normal View History

2022-09-12 09:10:02 +00:00
package baiduphoto
import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/go-resty/resty/v2"
)
const (
API_URL = "https://photo.baidu.com/youai"
ALBUM_API_URL = API_URL + "/album/v1"
FILE_API_URL_V1 = API_URL + "/file/v1"
FILE_API_URL_V2 = API_URL + "/file/v2"
)
var (
ErrNotSupportName = errors.New("only chinese and english, numbers and underscores are supported, and the length is no more than 20")
)
func (p *BaiduPhoto) Request(furl string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
req := base.RestyClient.R().
SetQueryParam("access_token", p.AccessToken)
if callback != nil {
callback(req)
}
if resp != nil {
req.SetResult(resp)
}
res, err := req.Execute(method, furl)
if err != nil {
return nil, err
}
erron := utils.Json.Get(res.Body(), "errno").ToInt()
switch erron {
case 0:
break
case 50805:
return nil, fmt.Errorf("you have joined album")
case 50820:
return nil, fmt.Errorf("no shared albums found")
case -6:
if err = p.refreshToken(); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("errno: %d, refer to https://photo.baidu.com/union/doc", erron)
}
return res.Body(), nil
}
func (p *BaiduPhoto) refreshToken() error {
u := "https://openapi.baidu.com/oauth/2.0/token"
var resp base.TokenResp
var e TokenErrResp
_, err := base.RestyClient.R().SetResult(&resp).SetError(&e).SetQueryParams(map[string]string{
"grant_type": "refresh_token",
"refresh_token": p.RefreshToken,
"client_id": p.ClientID,
"client_secret": p.ClientSecret,
}).Get(u)
if err != nil {
return err
}
if e.ErrorMsg != "" {
return &e
}
if resp.RefreshToken == "" {
return errs.EmptyToken
}
p.AccessToken, p.RefreshToken = resp.AccessToken, resp.RefreshToken
op.MustSaveDriverStorage(p)
return nil
}
func (p *BaiduPhoto) Get(furl string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
return p.Request(furl, http.MethodGet, callback, resp)
}
func (p *BaiduPhoto) Post(furl string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
return p.Request(furl, http.MethodPost, callback, resp)
}
// 获取所有文件
func (p *BaiduPhoto) GetAllFile(ctx context.Context) (files []File, err error) {
var cursor string
for {
var resp FileListResp
_, err = p.Get(FILE_API_URL_V1+"/list", func(r *resty.Request) {
r.SetContext(ctx)
r.SetQueryParams(map[string]string{
"need_thumbnail": "1",
"need_filter_hidden": "0",
"cursor": cursor,
})
}, &resp)
if err != nil {
return
}
files = append(files, resp.List...)
if !resp.HasNextPage() {
return
}
cursor = resp.Cursor
}
}
// 删除根文件
func (p *BaiduPhoto) DeleteFile(ctx context.Context, fileIDs ...string) 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, ",")),
})
}, nil)
return err
}
// 获取所有相册
func (p *BaiduPhoto) GetAllAlbum(ctx context.Context) (albums []Album, err error) {
var cursor string
for {
var resp AlbumListResp
_, err = p.Get(ALBUM_API_URL+"/list", func(r *resty.Request) {
r.SetContext(ctx)
r.SetQueryParams(map[string]string{
"need_amount": "1",
"limit": "100",
"cursor": cursor,
})
}, &resp)
if err != nil {
return
}
if albums == nil {
albums = make([]Album, 0, resp.TotalCount)
}
cursor = resp.Cursor
albums = append(albums, resp.List...)
if !resp.HasNextPage() {
return
}
}
}
// 获取相册中所有文件
func (p *BaiduPhoto) GetAllAlbumFile(ctx context.Context, albumID, 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,
"need_amount": "1",
"limit": "1000",
"passwd": passwd,
"cursor": cursor,
})
}, &resp)
if err != nil {
return
}
if files == nil {
files = make([]AlbumFile, 0, resp.TotalCount)
}
cursor = resp.Cursor
files = append(files, resp.List...)
if !resp.HasNextPage() {
return
}
}
}
// 创建相册
func (p *BaiduPhoto) CreateAlbum(ctx context.Context, name string) error {
if !checkName(name) {
return ErrNotSupportName
}
_, err := p.Post(ALBUM_API_URL+"/create", func(r *resty.Request) {
r.SetContext(ctx)
r.SetQueryParams(map[string]string{
"title": name,
"tid": getTid(),
"source": "0",
})
}, nil)
return err
}
// 相册改名
func (p *BaiduPhoto) SetAlbumName(ctx context.Context, albumID, tID, name string) error {
if !checkName(name) {
return 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,
})
}, nil)
return err
}
// 删除相册
func (p *BaiduPhoto) DeleteAlbum(ctx context.Context, albumID, tID string) 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,
"delete_origin_image": "0", // 是否删除原图 0 不删除 1 删除
})
}, nil)
return err
}
// 删除相册文件
func (p *BaiduPhoto) DeleteAlbumFile(ctx context.Context, albumID, tID string, fileIDs ...string) 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...),
"del_origin": "0", // 是否删除原图 0 不删除 1 删除
})
}, nil)
return err
}
// 增加相册文件
func (p *BaiduPhoto) AddAlbumFile(ctx context.Context, albumID, tID string, fileIDs ...string) 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...),
})
}, nil)
return err
}
// 保存相册文件为根文件
func (p *BaiduPhoto) CopyAlbumFile(ctx context.Context, albumID, tID, uk string, fileID ...string) (*CopyFile, 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...),
})
r.SetResult(&resp)
}, nil)
if err != nil {
return nil, err
}
return &resp.List[0], nil
}
// 加入相册
func (p *BaiduPhoto) JoinAlbum(ctx context.Context, code string) error {
var resp InviteResp
_, err := p.Get(ALBUM_API_URL+"/querypcode", func(req *resty.Request) {
req.SetContext(ctx)
req.SetQueryParams(map[string]string{
"pcode": code,
"web": "1",
})
}, &resp)
if err != nil {
return err
}
_, 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
}
func (d *BaiduPhoto) linkAlbum(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
headers := map[string]string{
"User-Agent": base.UserAgent,
}
if args.Header.Get("User-Agent") != "" {
headers["User-Agent"] = args.Header.Get("User-Agent")
}
if !utils.IsLocalIPAddr(args.IP) {
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],
}).
Head(ALBUM_API_URL + "/download")
if err != nil {
return nil, err
}
//exp := 8 * time.Hour
2022-09-12 09:10:02 +00:00
link := &model.Link{
URL: res.Header().Get("location"),
Header: http.Header{
"User-Agent": []string{headers["User-Agent"]},
},
//Expiration: &exp,
2022-09-12 09:10:02 +00:00
}
return link, nil
}
func (d *BaiduPhoto) linkFile(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
headers := map[string]string{
"User-Agent": base.UserAgent,
}
if args.Header.Get("User-Agent") != "" {
headers["User-Agent"] = args.Header.Get("User-Agent")
}
if !utils.IsLocalIPAddr(args.IP) {
headers["X-Forwarded-For"] = args.IP
}
var downloadUrl struct {
Dlink string `json:"dlink"`
}
_, err := d.Get(FILE_API_URL_V2+"/download", func(r *resty.Request) {
r.SetContext(ctx)
r.SetHeaders(headers)
r.SetQueryParams(map[string]string{
"fsid": splitID(file.GetID())[0],
})
}, &downloadUrl)
if err != nil {
return nil, err
}
//exp := 8 * time.Hour
2022-09-12 09:10:02 +00:00
link := &model.Link{
URL: downloadUrl.Dlink,
Header: http.Header{
"User-Agent": []string{headers["User-Agent"]},
},
//Expiration: &exp,
2022-09-12 09:10:02 +00:00
}
return link, nil
}