2022-09-12 09:10:02 +00:00
|
|
|
package baiduphoto
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"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"
|
2023-01-06 07:36:05 +00:00
|
|
|
USER_API_URL = API_URL + "/user/v1"
|
2022-09-12 09:10:02 +00:00
|
|
|
ALBUM_API_URL = API_URL + "/album/v1"
|
|
|
|
FILE_API_URL_V1 = API_URL + "/file/v1"
|
|
|
|
FILE_API_URL_V2 = API_URL + "/file/v2"
|
|
|
|
)
|
|
|
|
|
2024-09-08 11:46:23 +00:00
|
|
|
func (d *BaiduPhoto) Request(client *resty.Client, furl string, method string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
|
|
|
req := client.R().
|
2023-01-16 11:55:43 +00:00
|
|
|
SetQueryParam("access_token", d.AccessToken)
|
2022-09-12 09:10:02 +00:00
|
|
|
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")
|
2023-05-27 09:07:57 +00:00
|
|
|
case 50100:
|
|
|
|
return nil, fmt.Errorf("illegal title, only supports 50 characters")
|
2022-09-12 09:10:02 +00:00
|
|
|
case -6:
|
2023-01-16 11:55:43 +00:00
|
|
|
if err = d.refreshToken(); err != nil {
|
2022-09-12 09:10:02 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("errno: %d, refer to https://photo.baidu.com/union/doc", erron)
|
|
|
|
}
|
2023-07-31 08:27:16 +00:00
|
|
|
return res, nil
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 08:27:16 +00:00
|
|
|
//func (d *BaiduPhoto) Request(furl string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
|
|
|
// res, err := d.request(furl, method, callback, resp)
|
|
|
|
// if err != nil {
|
|
|
|
// return nil, err
|
|
|
|
// }
|
|
|
|
// return res.Body(), nil
|
|
|
|
//}
|
|
|
|
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) refreshToken() error {
|
2022-09-12 09:10:02 +00:00
|
|
|
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",
|
2023-01-16 11:55:43 +00:00
|
|
|
"refresh_token": d.RefreshToken,
|
|
|
|
"client_id": d.ClientID,
|
|
|
|
"client_secret": d.ClientSecret,
|
2022-09-12 09:10:02 +00:00
|
|
|
}).Get(u)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if e.ErrorMsg != "" {
|
|
|
|
return &e
|
|
|
|
}
|
|
|
|
if resp.RefreshToken == "" {
|
|
|
|
return errs.EmptyToken
|
|
|
|
}
|
2023-01-16 11:55:43 +00:00
|
|
|
d.AccessToken, d.RefreshToken = resp.AccessToken, resp.RefreshToken
|
|
|
|
op.MustSaveDriverStorage(d)
|
2022-09-12 09:10:02 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-07-31 08:27:16 +00:00
|
|
|
func (d *BaiduPhoto) Get(furl string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
2024-09-08 11:46:23 +00:00
|
|
|
return d.Request(base.RestyClient, furl, http.MethodGet, callback, resp)
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 08:27:16 +00:00
|
|
|
func (d *BaiduPhoto) Post(furl string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
2024-09-08 11:46:23 +00:00
|
|
|
return d.Request(base.RestyClient, furl, http.MethodPost, callback, resp)
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 获取所有文件
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) GetAllFile(ctx context.Context) (files []File, err error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
var cursor string
|
|
|
|
for {
|
|
|
|
var resp FileListResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err = d.Get(FILE_API_URL_V1+"/list", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 删除根文件
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) DeleteFile(ctx context.Context, file *File) error {
|
|
|
|
_, err := d.Get(FILE_API_URL_V1+"/delete", func(req *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
req.SetContext(ctx)
|
|
|
|
req.SetQueryParams(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"fsid_list": fmt.Sprintf("[%d]", file.Fsid),
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
|
|
|
}, nil)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取所有相册
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) GetAllAlbum(ctx context.Context) (albums []Album, err error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
var cursor string
|
|
|
|
for {
|
|
|
|
var resp AlbumListResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err = d.Get(ALBUM_API_URL+"/list", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取相册中所有文件
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) GetAllAlbumFile(ctx context.Context, album *Album, passwd string) (files []AlbumFile, err error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
var cursor string
|
|
|
|
for {
|
|
|
|
var resp AlbumFileListResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err = d.Get(ALBUM_API_URL+"/listfile", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetQueryParams(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"album_id": album.AlbumID,
|
2022-09-12 09:10:02 +00:00
|
|
|
"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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 创建相册
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) CreateAlbum(ctx context.Context, name string) (*Album, error) {
|
2023-01-06 07:36:05 +00:00
|
|
|
var resp JoinOrCreateAlbumResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err := d.Post(ALBUM_API_URL+"/create", func(r *resty.Request) {
|
2023-01-06 07:36:05 +00:00
|
|
|
r.SetContext(ctx).SetResult(&resp)
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetQueryParams(map[string]string{
|
|
|
|
"title": name,
|
|
|
|
"tid": getTid(),
|
|
|
|
"source": "0",
|
|
|
|
})
|
|
|
|
}, nil)
|
2023-01-06 07:36:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-16 11:55:43 +00:00
|
|
|
return d.GetAlbumDetail(ctx, resp.AlbumID)
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 相册改名
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) SetAlbumName(ctx context.Context, album *Album, name string) (*Album, error) {
|
|
|
|
_, err := d.Post(ALBUM_API_URL+"/settitle", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetFormData(map[string]string{
|
|
|
|
"title": name,
|
2023-01-06 07:36:05 +00:00
|
|
|
"album_id": album.AlbumID,
|
|
|
|
"tid": fmt.Sprint(album.Tid),
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
|
|
|
}, nil)
|
2023-01-06 07:36:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return renameAlbum(album, name), nil
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 删除相册
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) DeleteAlbum(ctx context.Context, album *Album) error {
|
|
|
|
_, err := d.Post(ALBUM_API_URL+"/delete", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetFormData(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"album_id": album.AlbumID,
|
|
|
|
"tid": fmt.Sprint(album.Tid),
|
2023-07-31 10:29:45 +00:00
|
|
|
"delete_origin_image": BoolToIntStr(d.DeleteOrigin), // 是否删除原图 0 不删除 1 删除
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
|
|
|
}, nil)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 删除相册文件
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) DeleteAlbumFile(ctx context.Context, file *AlbumFile) error {
|
|
|
|
_, err := d.Post(ALBUM_API_URL+"/delfile", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetFormData(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"album_id": fmt.Sprint(file.AlbumID),
|
|
|
|
"tid": fmt.Sprint(file.Tid),
|
|
|
|
"list": fmt.Sprintf(`[{"fsid":%d,"uk":%d}]`, file.Fsid, file.Uk),
|
2023-07-31 10:29:45 +00:00
|
|
|
"del_origin": BoolToIntStr(d.DeleteOrigin), // 是否删除原图 0 不删除 1 删除
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
|
|
|
}, nil)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 增加相册文件
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) AddAlbumFile(ctx context.Context, album *Album, file *File) (*AlbumFile, error) {
|
|
|
|
_, err := d.Get(ALBUM_API_URL+"/addfile", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetQueryParams(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"album_id": fmt.Sprint(album.AlbumID),
|
|
|
|
"tid": fmt.Sprint(album.Tid),
|
|
|
|
"list": fsidsFormatNotUk(file.Fsid),
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
|
|
|
}, nil)
|
2023-01-06 07:36:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-16 11:55:43 +00:00
|
|
|
return moveFileToAlbumFile(file, album, d.Uk), nil
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 保存相册文件为根文件
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) CopyAlbumFile(ctx context.Context, file *AlbumFile) (*File, error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
var resp CopyFileResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err := d.Post(ALBUM_API_URL+"/copyfile", func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetFormData(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"album_id": file.AlbumID,
|
|
|
|
"tid": fmt.Sprint(file.Tid),
|
|
|
|
"uk": fmt.Sprint(file.Uk),
|
|
|
|
"list": fsidsFormatNotUk(file.Fsid),
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
|
|
|
r.SetResult(&resp)
|
|
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-06 07:36:05 +00:00
|
|
|
return copyFile(file, &resp.List[0]), nil
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 加入相册
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) JoinAlbum(ctx context.Context, code string) (*Album, error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
var resp InviteResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err := d.Get(ALBUM_API_URL+"/querypcode", func(req *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
req.SetContext(ctx)
|
|
|
|
req.SetQueryParams(map[string]string{
|
|
|
|
"pcode": code,
|
|
|
|
"web": "1",
|
|
|
|
})
|
|
|
|
}, &resp)
|
|
|
|
if err != nil {
|
2023-01-06 07:36:05 +00:00
|
|
|
return nil, err
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
2023-01-06 07:36:05 +00:00
|
|
|
var resp2 JoinOrCreateAlbumResp
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err = d.Get(ALBUM_API_URL+"/join", func(req *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
req.SetContext(ctx)
|
|
|
|
req.SetQueryParams(map[string]string{
|
|
|
|
"invite_code": resp.Pdata.InviteCode,
|
|
|
|
})
|
2023-01-06 07:36:05 +00:00
|
|
|
}, &resp2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-16 11:55:43 +00:00
|
|
|
return d.GetAlbumDetail(ctx, resp2.AlbumID)
|
2023-01-06 07:36:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 获取相册详细信息
|
2023-01-16 11:55:43 +00:00
|
|
|
func (d *BaiduPhoto) GetAlbumDetail(ctx context.Context, albumID string) (*Album, error) {
|
2023-01-06 07:36:05 +00:00
|
|
|
var album Album
|
2023-01-16 11:55:43 +00:00
|
|
|
_, err := d.Get(ALBUM_API_URL+"/detail", func(req *resty.Request) {
|
2023-01-06 07:36:05 +00:00
|
|
|
req.SetContext(ctx).SetResult(&album)
|
|
|
|
req.SetQueryParams(map[string]string{
|
|
|
|
"album_id": albumID,
|
|
|
|
})
|
|
|
|
}, &album)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &album, nil
|
2022-09-12 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 07:36:05 +00:00
|
|
|
func (d *BaiduPhoto) linkAlbum(ctx context.Context, file *AlbumFile, args model.LinkArgs) (*model.Link, error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-09-08 11:46:23 +00:00
|
|
|
resp, err := d.Request(base.NoRedirectClient, ALBUM_API_URL+"/download", http.MethodHead, func(r *resty.Request) {
|
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetHeaders(headers)
|
|
|
|
r.SetQueryParams(map[string]string{
|
|
|
|
"fsid": fmt.Sprint(file.Fsid),
|
|
|
|
"album_id": file.AlbumID,
|
|
|
|
"tid": fmt.Sprint(file.Tid),
|
|
|
|
"uk": fmt.Sprint(file.Uk),
|
|
|
|
})
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode() != 302 {
|
|
|
|
return nil, fmt.Errorf("not found 302 redirect")
|
|
|
|
}
|
|
|
|
|
|
|
|
location := resp.Header().Get("Location")
|
2022-09-12 09:10:02 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
link := &model.Link{
|
2024-09-08 11:46:23 +00:00
|
|
|
URL: location,
|
2022-09-12 09:10:02 +00:00
|
|
|
Header: http.Header{
|
|
|
|
"User-Agent": []string{headers["User-Agent"]},
|
2022-09-22 17:15:12 +00:00
|
|
|
"Referer": []string{"https://photo.baidu.com/"},
|
2022-09-12 09:10:02 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
return link, nil
|
|
|
|
}
|
|
|
|
|
2023-01-06 07:36:05 +00:00
|
|
|
func (d *BaiduPhoto) linkFile(ctx context.Context, file *File, args model.LinkArgs) (*model.Link, error) {
|
2022-09-12 09:10:02 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-09-08 11:46:23 +00:00
|
|
|
// var downloadUrl struct {
|
|
|
|
// Dlink string `json:"dlink"`
|
|
|
|
// }
|
|
|
|
// _, err := d.Get(FILE_API_URL_V1+"/download", func(r *resty.Request) {
|
|
|
|
// r.SetContext(ctx)
|
|
|
|
// r.SetHeaders(headers)
|
|
|
|
// r.SetQueryParams(map[string]string{
|
|
|
|
// "fsid": fmt.Sprint(file.Fsid),
|
|
|
|
// })
|
|
|
|
// }, &downloadUrl)
|
|
|
|
|
|
|
|
resp, err := d.Request(base.NoRedirectClient, FILE_API_URL_V1+"/download", http.MethodHead, func(r *resty.Request) {
|
2022-09-12 09:10:02 +00:00
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetHeaders(headers)
|
|
|
|
r.SetQueryParams(map[string]string{
|
2023-01-06 07:36:05 +00:00
|
|
|
"fsid": fmt.Sprint(file.Fsid),
|
2022-09-12 09:10:02 +00:00
|
|
|
})
|
2024-09-08 11:46:23 +00:00
|
|
|
}, nil)
|
|
|
|
|
2022-09-12 09:10:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-09-08 11:46:23 +00:00
|
|
|
if resp.StatusCode() != 302 {
|
|
|
|
return nil, fmt.Errorf("not found 302 redirect")
|
|
|
|
}
|
|
|
|
|
|
|
|
location := resp.Header().Get("Location")
|
2022-09-12 09:10:02 +00:00
|
|
|
link := &model.Link{
|
2024-09-08 11:46:23 +00:00
|
|
|
URL: location,
|
2022-09-12 09:10:02 +00:00
|
|
|
Header: http.Header{
|
|
|
|
"User-Agent": []string{headers["User-Agent"]},
|
2022-09-22 17:15:12 +00:00
|
|
|
"Referer": []string{"https://photo.baidu.com/"},
|
2022-09-12 09:10:02 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
return link, nil
|
|
|
|
}
|
2023-01-06 07:36:05 +00:00
|
|
|
|
feat: Crypt driver, improve http/webdav handling (#4884)
this PR has several enhancements, fixes, and features:
- [x] Crypt: a transparent encryption driver. Anyone can easily, and safely store encrypted data on the remote storage provider. Consider your data is safely stored in the safe, and the storage provider can only see the safe, but not your data.
- [x] Optional: compatible with [Rclone Crypt](https://rclone.org/crypt/). More ways to manipulate the encrypted data.
- [x] directory and filename encryption
- [x] server-side encryption mode (server encrypts & decrypts all data, all data flows thru the server)
- [x] obfuscate sensitive information internally
- [x] introduced a server memory-cached multi-thread downloader.
- [x] Driver: **Quark** enabled this feature, faster load in any single thread scenario. e.g. media player directly playing from the link, now it's faster.
- [x] general improvement on HTTP/WebDAV stream processing & header handling & response handling
- [x] Driver: **Mega** driver support ranged http header
- [x] Driver: **Quark** fix bug of not closing HTTP request to Quark server while user end has closed connection to alist
## Crypt, a transparent Encrypt/Decrypt Driver. (Rclone Crypt compatible)
e.g.
Crypt mount path -> /vault
Crypt remote path -> /ali/encrypted
Aliyun mount paht -> /ali
when the user uploads a.jpg to /vault, the data will be encrypted and saved to /ali/encrypted/xxxxx. And when the user wants to access a.jpg, it's automatically decrypted, and the user can do anything with it.
Since it's Rclone Crypt compatible, users can download /ali/encrypted/xxxxx and decrypt it with rclone crypt tool. Or the user can mount this folder using rclone, then mount the decrypted folder in Linux...
NB. Some breaking changes is made to make it follow global standard, e.g. processing the HTTP header properly.
close #4679
close #4827
Co-authored-by: Sean He <866155+seanhe26@users.noreply.github.com>
Co-authored-by: Andy Hsu <i@nn.ci>
2023-08-02 06:40:36 +00:00
|
|
|
/*func (d *BaiduPhoto) linkStreamAlbum(ctx context.Context, file *AlbumFile) (*model.Link, error) {
|
2023-07-31 08:27:16 +00:00
|
|
|
return &model.Link{
|
|
|
|
Header: http.Header{},
|
|
|
|
Writer: func(w io.Writer) error {
|
|
|
|
res, err := d.Get(ALBUM_API_URL+"/streaming", func(r *resty.Request) {
|
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetQueryParams(map[string]string{
|
|
|
|
"fsid": fmt.Sprint(file.Fsid),
|
|
|
|
"album_id": file.AlbumID,
|
|
|
|
"tid": fmt.Sprint(file.Tid),
|
|
|
|
"uk": fmt.Sprint(file.Uk),
|
|
|
|
}).SetDoNotParseResponse(true)
|
|
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer res.RawBody().Close()
|
|
|
|
_, err = io.Copy(w, res.RawBody())
|
|
|
|
return err
|
|
|
|
},
|
|
|
|
}, nil
|
feat: Crypt driver, improve http/webdav handling (#4884)
this PR has several enhancements, fixes, and features:
- [x] Crypt: a transparent encryption driver. Anyone can easily, and safely store encrypted data on the remote storage provider. Consider your data is safely stored in the safe, and the storage provider can only see the safe, but not your data.
- [x] Optional: compatible with [Rclone Crypt](https://rclone.org/crypt/). More ways to manipulate the encrypted data.
- [x] directory and filename encryption
- [x] server-side encryption mode (server encrypts & decrypts all data, all data flows thru the server)
- [x] obfuscate sensitive information internally
- [x] introduced a server memory-cached multi-thread downloader.
- [x] Driver: **Quark** enabled this feature, faster load in any single thread scenario. e.g. media player directly playing from the link, now it's faster.
- [x] general improvement on HTTP/WebDAV stream processing & header handling & response handling
- [x] Driver: **Mega** driver support ranged http header
- [x] Driver: **Quark** fix bug of not closing HTTP request to Quark server while user end has closed connection to alist
## Crypt, a transparent Encrypt/Decrypt Driver. (Rclone Crypt compatible)
e.g.
Crypt mount path -> /vault
Crypt remote path -> /ali/encrypted
Aliyun mount paht -> /ali
when the user uploads a.jpg to /vault, the data will be encrypted and saved to /ali/encrypted/xxxxx. And when the user wants to access a.jpg, it's automatically decrypted, and the user can do anything with it.
Since it's Rclone Crypt compatible, users can download /ali/encrypted/xxxxx and decrypt it with rclone crypt tool. Or the user can mount this folder using rclone, then mount the decrypted folder in Linux...
NB. Some breaking changes is made to make it follow global standard, e.g. processing the HTTP header properly.
close #4679
close #4827
Co-authored-by: Sean He <866155+seanhe26@users.noreply.github.com>
Co-authored-by: Andy Hsu <i@nn.ci>
2023-08-02 06:40:36 +00:00
|
|
|
}*/
|
2023-07-31 08:27:16 +00:00
|
|
|
|
feat: Crypt driver, improve http/webdav handling (#4884)
this PR has several enhancements, fixes, and features:
- [x] Crypt: a transparent encryption driver. Anyone can easily, and safely store encrypted data on the remote storage provider. Consider your data is safely stored in the safe, and the storage provider can only see the safe, but not your data.
- [x] Optional: compatible with [Rclone Crypt](https://rclone.org/crypt/). More ways to manipulate the encrypted data.
- [x] directory and filename encryption
- [x] server-side encryption mode (server encrypts & decrypts all data, all data flows thru the server)
- [x] obfuscate sensitive information internally
- [x] introduced a server memory-cached multi-thread downloader.
- [x] Driver: **Quark** enabled this feature, faster load in any single thread scenario. e.g. media player directly playing from the link, now it's faster.
- [x] general improvement on HTTP/WebDAV stream processing & header handling & response handling
- [x] Driver: **Mega** driver support ranged http header
- [x] Driver: **Quark** fix bug of not closing HTTP request to Quark server while user end has closed connection to alist
## Crypt, a transparent Encrypt/Decrypt Driver. (Rclone Crypt compatible)
e.g.
Crypt mount path -> /vault
Crypt remote path -> /ali/encrypted
Aliyun mount paht -> /ali
when the user uploads a.jpg to /vault, the data will be encrypted and saved to /ali/encrypted/xxxxx. And when the user wants to access a.jpg, it's automatically decrypted, and the user can do anything with it.
Since it's Rclone Crypt compatible, users can download /ali/encrypted/xxxxx and decrypt it with rclone crypt tool. Or the user can mount this folder using rclone, then mount the decrypted folder in Linux...
NB. Some breaking changes is made to make it follow global standard, e.g. processing the HTTP header properly.
close #4679
close #4827
Co-authored-by: Sean He <866155+seanhe26@users.noreply.github.com>
Co-authored-by: Andy Hsu <i@nn.ci>
2023-08-02 06:40:36 +00:00
|
|
|
/*func (d *BaiduPhoto) linkStream(ctx context.Context, file *File) (*model.Link, error) {
|
2023-07-31 08:27:16 +00:00
|
|
|
return &model.Link{
|
|
|
|
Header: http.Header{},
|
|
|
|
Writer: func(w io.Writer) error {
|
|
|
|
res, err := d.Get(FILE_API_URL_V1+"/streaming", func(r *resty.Request) {
|
|
|
|
r.SetContext(ctx)
|
|
|
|
r.SetQueryParams(map[string]string{
|
|
|
|
"fsid": fmt.Sprint(file.Fsid),
|
|
|
|
}).SetDoNotParseResponse(true)
|
|
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer res.RawBody().Close()
|
|
|
|
_, err = io.Copy(w, res.RawBody())
|
|
|
|
return err
|
|
|
|
},
|
|
|
|
}, nil
|
feat: Crypt driver, improve http/webdav handling (#4884)
this PR has several enhancements, fixes, and features:
- [x] Crypt: a transparent encryption driver. Anyone can easily, and safely store encrypted data on the remote storage provider. Consider your data is safely stored in the safe, and the storage provider can only see the safe, but not your data.
- [x] Optional: compatible with [Rclone Crypt](https://rclone.org/crypt/). More ways to manipulate the encrypted data.
- [x] directory and filename encryption
- [x] server-side encryption mode (server encrypts & decrypts all data, all data flows thru the server)
- [x] obfuscate sensitive information internally
- [x] introduced a server memory-cached multi-thread downloader.
- [x] Driver: **Quark** enabled this feature, faster load in any single thread scenario. e.g. media player directly playing from the link, now it's faster.
- [x] general improvement on HTTP/WebDAV stream processing & header handling & response handling
- [x] Driver: **Mega** driver support ranged http header
- [x] Driver: **Quark** fix bug of not closing HTTP request to Quark server while user end has closed connection to alist
## Crypt, a transparent Encrypt/Decrypt Driver. (Rclone Crypt compatible)
e.g.
Crypt mount path -> /vault
Crypt remote path -> /ali/encrypted
Aliyun mount paht -> /ali
when the user uploads a.jpg to /vault, the data will be encrypted and saved to /ali/encrypted/xxxxx. And when the user wants to access a.jpg, it's automatically decrypted, and the user can do anything with it.
Since it's Rclone Crypt compatible, users can download /ali/encrypted/xxxxx and decrypt it with rclone crypt tool. Or the user can mount this folder using rclone, then mount the decrypted folder in Linux...
NB. Some breaking changes is made to make it follow global standard, e.g. processing the HTTP header properly.
close #4679
close #4827
Co-authored-by: Sean He <866155+seanhe26@users.noreply.github.com>
Co-authored-by: Andy Hsu <i@nn.ci>
2023-08-02 06:40:36 +00:00
|
|
|
}*/
|
2023-07-31 08:27:16 +00:00
|
|
|
|
2023-01-06 07:36:05 +00:00
|
|
|
// 获取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
|
|
|
|
}
|