mirror of https://github.com/Xhofe/alist
* fix(baidushare): large file download * refactor: optimize clientpull/3927/head
parent
aeb48b2ecc
commit
c65d868e09
|
@ -2,25 +2,30 @@ package baidu_share
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Xhofe/go-cache"
|
||||
"github.com/alist-org/alist/v3/drivers/base"
|
||||
"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/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type BaiduShare struct {
|
||||
model.Storage
|
||||
Addition
|
||||
config map[string]string
|
||||
dlinkCache cache.ICache[string]
|
||||
client *resty.Client
|
||||
info struct {
|
||||
Root string
|
||||
Seckey string
|
||||
Shareid string
|
||||
Uk string
|
||||
}
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Config() driver.Config {
|
||||
|
@ -34,115 +39,208 @@ func (d *BaiduShare) GetAddition() driver.Additional {
|
|||
func (d *BaiduShare) Init(ctx context.Context) error {
|
||||
// TODO login / refresh token
|
||||
//op.MustSaveDriverStorage(d)
|
||||
d.config = map[string]string{}
|
||||
d.dlinkCache = cache.NewMemCache(cache.WithClearInterval[string](time.Duration(d.CacheExpiration) * time.Minute))
|
||||
return nil
|
||||
d.client = resty.New().
|
||||
SetBaseURL("https://pan.baidu.com").
|
||||
SetHeader("User-Agent", "netdisk").
|
||||
SetCookie(&http.Cookie{Name: "BDUSS", Value: d.BDUSS}).
|
||||
SetCookie(&http.Cookie{Name: "ndut_fmt"})
|
||||
respJson := struct {
|
||||
Errno int64 `json:"errno"`
|
||||
Data struct {
|
||||
List [1]struct {
|
||||
Path string `json:"path"`
|
||||
} `json:"list"`
|
||||
Uk json.Number `json:"uk"`
|
||||
Shareid json.Number `json:"shareid"`
|
||||
Seckey string `json:"seckey"`
|
||||
} `json:"data"`
|
||||
}{}
|
||||
resp, err := d.client.R().
|
||||
SetBody(url.Values{
|
||||
"pwd": {d.Pwd},
|
||||
"root": {"1"},
|
||||
"shorturl": {d.Surl},
|
||||
}.Encode()).
|
||||
SetResult(&respJson).
|
||||
Post("share/wxlist?channel=weixin&version=2.2.2&clienttype=25&web=1")
|
||||
if err == nil {
|
||||
if resp.IsSuccess() && respJson.Errno == 0 {
|
||||
d.info.Root = path.Dir(respJson.Data.List[0].Path)
|
||||
d.info.Seckey = respJson.Data.Seckey
|
||||
d.info.Shareid = respJson.Data.Shareid.String()
|
||||
d.info.Uk = respJson.Data.Uk.String()
|
||||
} else {
|
||||
err = fmt.Errorf(" %s; %s; ", resp.Status(), resp.Body())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Drop(ctx context.Context) error {
|
||||
d.dlinkCache.Clear()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *BaiduShare) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
|
||||
// TODO return the files list
|
||||
body := url.Values{
|
||||
"shorturl": {d.Surl},
|
||||
"dir": {dir.GetPath()},
|
||||
"root": {"0"},
|
||||
"pwd": {d.Pwd},
|
||||
"num": {"1000"},
|
||||
"order": {"time"},
|
||||
// TODO return the files list, required
|
||||
reqDir := dir.GetPath()
|
||||
isRoot := "0"
|
||||
if reqDir == d.RootFolderPath {
|
||||
reqDir = path.Join(d.info.Root, reqDir)
|
||||
}
|
||||
if body.Get("dir") == "" || body.Get("dir") == d.config["root"] {
|
||||
body.Set("root", "1")
|
||||
if reqDir == d.info.Root {
|
||||
isRoot = "1"
|
||||
}
|
||||
res := []model.Obj{}
|
||||
objs := []model.Obj{}
|
||||
var err error
|
||||
var page int64 = 1
|
||||
var page uint64 = 1
|
||||
more := true
|
||||
for more {
|
||||
body.Set("page", strconv.FormatInt(page, 10))
|
||||
req := base.RestyClient.R().
|
||||
SetCookies([]*http.Cookie{{Name: "BDUSS", Value: d.BDUSS}}).
|
||||
SetBody(body.Encode())
|
||||
resp, e := req.Post("https://pan.baidu.com/share/wxlist?channel=weixin&version=2.2.2&clienttype=25&web=1")
|
||||
for more && err == nil {
|
||||
respJson := struct {
|
||||
Errno int64 `json:"errno"`
|
||||
Data struct {
|
||||
More bool `json:"has_more"`
|
||||
List []struct {
|
||||
Fsid json.Number `json:"fs_id"`
|
||||
Isdir json.Number `json:"isdir"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"server_filename"`
|
||||
Mtime json.Number `json:"server_mtime"`
|
||||
Size json.Number `json:"size"`
|
||||
} `json:"list"`
|
||||
} `json:"data"`
|
||||
}{}
|
||||
resp, e := d.client.R().
|
||||
SetBody(url.Values{
|
||||
"dir": {reqDir},
|
||||
"num": {"1000"},
|
||||
"order": {"time"},
|
||||
"page": {fmt.Sprint(page)},
|
||||
"pwd": {d.Pwd},
|
||||
"root": {isRoot},
|
||||
"shorturl": {d.Surl},
|
||||
}.Encode()).
|
||||
SetResult(&respJson).
|
||||
Post("share/wxlist?channel=weixin&version=2.2.2&clienttype=25&web=1")
|
||||
err = e
|
||||
jsonresp := jsonResp{}
|
||||
if err == nil {
|
||||
err = base.RestyClient.JSONUnmarshal(resp.Body(), &jsonresp)
|
||||
}
|
||||
if err == nil && jsonresp.Errno == 0 {
|
||||
more = jsonresp.Data.More
|
||||
page += 1
|
||||
for _, v := range jsonresp.Data.List {
|
||||
size, _ := v.Size.Int64()
|
||||
mtime, _ := v.Time.Int64()
|
||||
res = append(res, &model.Object{
|
||||
ID: v.ID.String(),
|
||||
Path: v.Path,
|
||||
Name: v.Name,
|
||||
Size: size,
|
||||
Modified: time.Unix(mtime, 0),
|
||||
IsFolder: v.Dir.String() == "1",
|
||||
})
|
||||
d.dlinkCache.Set(v.Path, v.Dlink, cache.WithEx[string](time.Duration(d.CacheExpiration/2)*time.Minute))
|
||||
if resp.IsSuccess() && respJson.Errno == 0 {
|
||||
page++
|
||||
more = respJson.Data.More
|
||||
for _, v := range respJson.Data.List {
|
||||
size, _ := v.Size.Int64()
|
||||
mtime, _ := v.Mtime.Int64()
|
||||
objs = append(objs, &model.Object{
|
||||
ID: v.Fsid.String(),
|
||||
Path: v.Path,
|
||||
Name: v.Name,
|
||||
Size: size,
|
||||
Modified: time.Unix(mtime, 0),
|
||||
IsFolder: v.Isdir.String() == "1",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf(" %s; %s; ", resp.Status(), resp.Body())
|
||||
}
|
||||
if len(res) > 0 && body.Get("root") == "1" {
|
||||
d.config["root"] = path.Dir(res[0].GetPath())
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("errno:%d", jsonresp.Errno)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return res, err
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||
// TODO return link of file
|
||||
var err error
|
||||
req := base.RestyClient.R().SetCookies([]*http.Cookie{{Name: "BDUSS", Value: d.BDUSS}})
|
||||
url, found := d.dlinkCache.Get(file.GetPath())
|
||||
if !found {
|
||||
_, err = d.List(ctx, &model.Object{Path: path.Dir(file.GetPath())}, model.ListArgs{})
|
||||
url, found = d.dlinkCache.Get(file.GetPath())
|
||||
if err == nil && !found {
|
||||
err = errs.NotSupport
|
||||
// TODO return link of file, required
|
||||
link := model.Link{Header: d.client.Header}
|
||||
sign := ""
|
||||
stamp := ""
|
||||
signJson := struct {
|
||||
Errno int64 `json:"errno"`
|
||||
Data struct {
|
||||
Stamp json.Number `json:"timestamp"`
|
||||
Sign string `json:"sign"`
|
||||
} `json:"data"`
|
||||
}{}
|
||||
resp, err := d.client.R().
|
||||
SetQueryParam("surl", d.Surl).
|
||||
SetResult(&signJson).
|
||||
Get("share/tplconfig?fields=sign,timestamp&channel=chunlei&web=1&app_id=250528&clienttype=0")
|
||||
if err == nil {
|
||||
if resp.IsSuccess() && signJson.Errno == 0 {
|
||||
stamp = signJson.Data.Stamp.String()
|
||||
sign = signJson.Data.Sign
|
||||
} else {
|
||||
err = fmt.Errorf(" %s; %s; ", resp.Status(), resp.Body())
|
||||
}
|
||||
}
|
||||
return &model.Link{URL: url, Header: req.Header}, err
|
||||
if err == nil {
|
||||
respJson := struct {
|
||||
Errno int64 `json:"errno"`
|
||||
List [1]struct {
|
||||
Dlink string `json:"dlink"`
|
||||
} `json:"list"`
|
||||
}{}
|
||||
resp, err = d.client.R().
|
||||
SetQueryParam("sign", sign).
|
||||
SetQueryParam("timestamp", stamp).
|
||||
SetBody(url.Values{
|
||||
"encrypt": {"0"},
|
||||
"extra": {fmt.Sprintf(`{"sekey":"%s"}`, d.info.Seckey)},
|
||||
"fid_list": {fmt.Sprintf("[%s]", file.GetID())},
|
||||
"primaryid": {d.info.Shareid},
|
||||
"product": {"share"},
|
||||
"type": {"nolimit"},
|
||||
"uk": {d.info.Uk},
|
||||
}.Encode()).
|
||||
SetResult(&respJson).
|
||||
Post("api/sharedownload?app_id=250528&channel=chunlei&clienttype=12&web=1")
|
||||
if err == nil {
|
||||
if resp.IsSuccess() && respJson.Errno == 0 && respJson.List[0].Dlink != "" {
|
||||
link.URL = respJson.List[0].Dlink
|
||||
} else {
|
||||
err = fmt.Errorf(" %s; %s; ", resp.Status(), resp.Body())
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
resp, err = d.client.R().
|
||||
SetDoNotParseResponse(true).
|
||||
Get(link.URL)
|
||||
if err == nil {
|
||||
defer resp.RawBody().Close()
|
||||
if resp.IsError() {
|
||||
byt, _ := io.ReadAll(resp.RawBody())
|
||||
err = fmt.Errorf(" %s; %s; ", resp.Status(), byt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return &link, err
|
||||
}
|
||||
|
||||
func (d *BaiduShare) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
||||
// TODO create folder
|
||||
// TODO create folder, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
// TODO move obj
|
||||
// TODO move obj, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
|
||||
// TODO rename obj
|
||||
// TODO rename obj, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
// TODO copy obj
|
||||
// TODO copy obj, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Remove(ctx context.Context, obj model.Obj) error {
|
||||
// TODO remove obj
|
||||
// TODO remove obj, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *BaiduShare) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
|
||||
// TODO upload file
|
||||
// TODO upload file, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
|
|
|
@ -17,14 +17,17 @@ type Addition struct {
|
|||
}
|
||||
|
||||
var config = driver.Config{
|
||||
Name: "BaiduShare",
|
||||
LocalSort: true,
|
||||
OnlyLocal: false,
|
||||
OnlyProxy: false,
|
||||
NoCache: false,
|
||||
NoUpload: true,
|
||||
NeedMs: false,
|
||||
DefaultRoot: "",
|
||||
Name: "BaiduShare",
|
||||
LocalSort: true,
|
||||
OnlyLocal: false,
|
||||
OnlyProxy: false,
|
||||
NoCache: false,
|
||||
NoUpload: true,
|
||||
NeedMs: false,
|
||||
DefaultRoot: "/",
|
||||
CheckStatus: false,
|
||||
Alert: "",
|
||||
NoOverwriteUpload: false,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -1,19 +1 @@
|
|||
package baidu_share
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type jsonResp struct {
|
||||
Errno int64 `json:"errno"`
|
||||
Data struct {
|
||||
More bool `json:"has_more"`
|
||||
List []struct {
|
||||
ID json.Number `json:"fs_id"`
|
||||
Dir json.Number `json:"isdir"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"server_filename"`
|
||||
Time json.Number `json:"server_mtime"`
|
||||
Size json.Number `json:"size"`
|
||||
Dlink string `json:"dlink"`
|
||||
} `json:"list"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue