From 1ab73e074248df0e58b700b4ab542ac837f223d0 Mon Sep 17 00:00:00 2001 From: foxxorcat Date: Tue, 20 Sep 2022 15:29:40 +0800 Subject: [PATCH] feat: add lanzou driver --- drivers/all.go | 1 + drivers/lanzou/driver.go | 171 ++++++++++++++++ drivers/lanzou/help.go | 165 ++++++++++++++++ drivers/lanzou/meta.go | 31 +++ drivers/lanzou/types.go | 131 ++++++++++++ drivers/lanzou/util.go | 416 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 915 insertions(+) create mode 100644 drivers/lanzou/driver.go create mode 100644 drivers/lanzou/help.go create mode 100644 drivers/lanzou/meta.go create mode 100644 drivers/lanzou/types.go create mode 100644 drivers/lanzou/util.go diff --git a/drivers/all.go b/drivers/all.go index 53b311dfb51..59a65928598 100644 --- a/drivers/all.go +++ b/drivers/all.go @@ -10,6 +10,7 @@ import ( _ "github.com/alist-org/alist/v3/drivers/baidu_photo" _ "github.com/alist-org/alist/v3/drivers/ftp" _ "github.com/alist-org/alist/v3/drivers/google_drive" + _ "github.com/alist-org/alist/v3/drivers/lanzou" _ "github.com/alist-org/alist/v3/drivers/local" _ "github.com/alist-org/alist/v3/drivers/mediatrack" _ "github.com/alist-org/alist/v3/drivers/onedrive" diff --git a/drivers/lanzou/driver.go b/drivers/lanzou/driver.go new file mode 100644 index 00000000000..8c2eed76b85 --- /dev/null +++ b/drivers/lanzou/driver.go @@ -0,0 +1,171 @@ +package lanzou + +import ( + "context" + "net/http" + "time" + + "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/alist-org/alist/v3/pkg/utils" + "github.com/go-resty/resty/v2" +) + +var upClient = base.NewRestyClient().SetTimeout(120 * time.Second) + +type LanZou struct { + Addition + model.Storage +} + +func (d *LanZou) Config() driver.Config { + return config +} + +func (d *LanZou) GetAddition() driver.Additional { + return d.Addition +} + +func (d *LanZou) Init(ctx context.Context, storage model.Storage) error { + d.Storage = storage + err := utils.Json.UnmarshalFromString(d.Storage.Addition, &d.Addition) + if err != nil { + return err + } + if d.IsCookie() { + if d.RootFolderID == "" { + d.RootFolderID = "-1" + } + } + return nil +} + +func (d *LanZou) Drop(ctx context.Context) error { + return nil +} + +// 获取的大小和时间不准确 +func (d *LanZou) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { + if d.IsCookie() { + return d.GetFiles(ctx, dir.GetID()) + } else { + return d.GetFileOrFolderByShareUrl(ctx, dir.GetID(), d.SharePassword) + } +} + +func (d *LanZou) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { + downID := file.GetID() + pwd := d.SharePassword + if d.IsCookie() { + share, err := d.getFileShareUrlByID(ctx, file.GetID()) + if err != nil { + return nil, err + } + downID = share.FID + pwd = share.Pwd + } + fileInfo, err := d.getFilesByShareUrl(ctx, downID, pwd, nil) + if err != nil { + return nil, err + } + + return &model.Link{ + URL: fileInfo.Url, + Header: http.Header{ + "User-Agent": []string{base.UserAgent}, + }, + }, nil +} + +func (d *LanZou) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { + if d.IsCookie() { + _, err := d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "2", + "parent_id": parentDir.GetID(), + "folder_name": dirName, + "folder_description": "", + }) + }, nil) + return err + } + return errs.NotImplement +} + +func (d *LanZou) Move(ctx context.Context, srcObj, dstDir model.Obj) error { + if d.IsCookie() { + if !srcObj.IsDir() { + _, err := d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "20", + "folder_id": dstDir.GetID(), + "file_id": srcObj.GetID(), + }) + }, nil) + return err + } + } + return errs.NotImplement +} + +func (d *LanZou) Rename(ctx context.Context, srcObj model.Obj, newName string) error { + if d.IsCookie() { + if !srcObj.IsDir() { + _, err := d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "46", + "file_id": srcObj.GetID(), + "file_name": newName, + "type": "2", + }) + }, nil) + return err + } + } + return errs.NotImplement +} + +func (d *LanZou) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { + return errs.NotImplement +} + +func (d *LanZou) Remove(ctx context.Context, obj model.Obj) error { + if d.IsCookie() { + _, err := d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + if obj.IsDir() { + req.SetFormData(map[string]string{ + "task": "3", + "folder_id": obj.GetID(), + }) + } else { + req.SetFormData(map[string]string{ + "task": "6", + "file_id": obj.GetID(), + }) + } + }, nil) + return err + } + return errs.NotImplement +} + +func (d *LanZou) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { + if d.IsCookie() { + _, err := d._post(d.BaseUrl+"/fileup.php", func(req *resty.Request) { + req.SetFormData(map[string]string{ + "task": "1", + "id": "WU_FILE_0", + "name": stream.GetName(), + "folder_id": dstDir.GetID(), + }).SetFileReader("upload_file", stream.GetName(), stream) + }, nil, true) + return err + } + return errs.NotImplement +} diff --git a/drivers/lanzou/help.go b/drivers/lanzou/help.go new file mode 100644 index 00000000000..68a2b4c6b9f --- /dev/null +++ b/drivers/lanzou/help.go @@ -0,0 +1,165 @@ +package lanzou + +import ( + "bytes" + "fmt" + "regexp" + "strconv" + "strings" + "time" + "unicode" +) + +const DAY time.Duration = 84600000000000 + +var timeSplitReg = regexp.MustCompile("([0-9.]*)\\s*([\u4e00-\u9fa5]+)") + +func MustParseTime(str string) time.Time { + lastOpTime, err := time.ParseInLocation("2006-01-02 -07", str+" +08", time.Local) + if err != nil { + strs := timeSplitReg.FindStringSubmatch(str) + lastOpTime = time.Now() + if len(strs) == 3 { + i, _ := strconv.ParseInt(strs[1], 10, 64) + ti := time.Duration(-i) + switch strs[2] { + case "秒前": + lastOpTime = lastOpTime.Add(time.Second * ti) + case "分钟前": + lastOpTime = lastOpTime.Add(time.Minute * ti) + case "小时前": + lastOpTime = lastOpTime.Add(time.Hour * ti) + case "天前": + lastOpTime = lastOpTime.Add(DAY * ti) + case "昨天": + lastOpTime = lastOpTime.Add(-DAY) + case "前天": + lastOpTime = lastOpTime.Add(-DAY * 2) + } + } + } + return lastOpTime +} + +var sizeSplitReg = regexp.MustCompile(`(?i)([0-9.]+)\s*([bkm]+)`) + +func SizeStrToInt64(size string) int64 { + strs := sizeSplitReg.FindStringSubmatch(size) + if len(strs) < 3 { + return 0 + } + + s, _ := strconv.ParseFloat(strs[1], 64) + switch strings.ToUpper(strs[2]) { + case "B": + return int64(s) + case "K": + return int64(s * (1 << 10)) + case "M": + return int64(s * (1 << 20)) + } + return 0 +} + +// 移除注释 +func RemoveNotes(html []byte) []byte { + return regexp.MustCompile(`|//.*|/\*.*?\*/`).ReplaceAll(html, []byte{}) +} + +var findAcwScV2Reg = regexp.MustCompile(`arg1='([0-9A-Z]+)'`) + +// 在页面被过多访问或其他情况下,有时候会先返回一个加密的页面,其执行计算出一个acw_sc__v2后放入页面后再重新访问页面才能获得正常页面 +// 若该页面进行了js加密,则进行解密,计算acw_sc__v2,并加入cookie +func CalcAcwScV2(html string) (string, error) { + acwScV2s := findAcwScV2Reg.FindStringSubmatch(html) + if len(acwScV2s) != 2 { + return "", fmt.Errorf("无法匹配acw_sc__v2") + } + return HexXor(Unbox(acwScV2s[1]), "3000176000856006061501533003690027800375"), nil +} + +func Unbox(hex string) string { + var box = []int{6, 28, 34, 31, 33, 18, 30, 23, 9, 8, 19, 38, 17, 24, 0, 5, 32, 21, 10, 22, 25, 14, 15, 3, 16, 27, 13, 35, 2, 29, 11, 26, 4, 36, 1, 39, 37, 7, 20, 12} + var newBox = make([]byte, len(hex)) + for i := 0; i < len(box); i++ { + j := box[i] + if len(newBox) > j { + newBox[j] = hex[i] + } + } + return string(newBox) +} + +func HexXor(hex1, hex2 string) string { + out := bytes.NewBuffer(make([]byte, len(hex1))) + for i := 0; i < len(hex1) && i < len(hex2); i += 2 { + v1, _ := strconv.ParseInt(hex1[i:i+2], 16, 64) + v2, _ := strconv.ParseInt(hex2[i:i+2], 16, 64) + out.WriteString(strconv.FormatInt(v1^v2, 16)) + } + return out.String() +} + +var findDataReg = regexp.MustCompile(`data[:\s]+({[^}]+})`) // 查找json +var findKVReg = regexp.MustCompile(`'(.+?)':('?([^' },]*)'?)`) // 拆分kv + +// 根据key查询js变量 +func findJSVarFunc(key, data string) string { + values := regexp.MustCompile(`var ` + key + ` = '(.+?)';`).FindStringSubmatch(data) + if len(values) == 0 { + return "" + } + return values[1] +} + +// 解析html中的JSON +func htmlJsonToMap(html string) (map[string]string, error) { + datas := findDataReg.FindStringSubmatch(html) + if len(datas) != 2 { + return nil, fmt.Errorf("not find data") + } + return jsonToMap(datas[1], html), nil +} + +func jsonToMap(data, html string) map[string]string { + var param = make(map[string]string) + kvs := findKVReg.FindAllStringSubmatch(data, -1) + for _, kv := range kvs { + k, v := kv[1], kv[3] + if v == "" || strings.Contains(kv[2], "'") || IsNumber(kv[2]) { + param[k] = v + } else { + param[k] = findJSVarFunc(v, html) + } + } + return param +} + +func IsNumber(str string) bool { + for _, s := range str { + if !unicode.IsDigit(s) { + return false + } + } + return true +} + +var findFromReg = regexp.MustCompile(`data : '(.+?)'`) // 查找from字符串 + +// 解析html中的from +func htmlFormToMap(html string) (map[string]string, error) { + froms := findFromReg.FindStringSubmatch(html) + if len(froms) != 2 { + return nil, fmt.Errorf("not find file sgin") + } + return fromToMap(froms[1]), nil +} + +func fromToMap(from string) map[string]string { + var param = make(map[string]string) + for _, kv := range strings.Split(from, "&") { + kv := strings.SplitN(kv, "=", 2)[:2] + param[kv[0]] = kv[1] + } + return param +} diff --git a/drivers/lanzou/meta.go b/drivers/lanzou/meta.go new file mode 100644 index 00000000000..843c338f75c --- /dev/null +++ b/drivers/lanzou/meta.go @@ -0,0 +1,31 @@ +package lanzou + +import ( + "github.com/alist-org/alist/v3/internal/driver" + "github.com/alist-org/alist/v3/internal/op" +) + +type Addition struct { + Type string `json:"type" type:"select" options:"cookie,url" default:"cookie"` + Cookie string `json:"cookie" required:"true" help:"about 15 days valid"` + driver.RootID + SharePassword string `json:"share_password"` + BaseUrl string `json:"baseUrl" required:"true" default:"https://pc.woozooo.com"` + ShareUrl string `json:"shareUrl" required:"true" default:"https://pan.lanzouo.com"` +} + +func (a *Addition) IsCookie() bool { + return a.Type == "cookie" +} + +var config = driver.Config{ + Name: "Lanzou", + LocalSort: true, + DefaultRoot: "-1", +} + +func init() { + op.RegisterDriver(config, func() driver.Driver { + return &LanZou{} + }) +} diff --git a/drivers/lanzou/types.go b/drivers/lanzou/types.go new file mode 100644 index 00000000000..50f79b095d6 --- /dev/null +++ b/drivers/lanzou/types.go @@ -0,0 +1,131 @@ +package lanzou + +import ( + "fmt" + "time" + + "github.com/alist-org/alist/v3/internal/model" +) + +type FilesOrFoldersResp struct { + Text []FileOrFolder `json:"text"` +} + +type FileOrFolder struct { + Name string `json:"name"` + //Onof string `json:"onof"` // 是否存在提取码 + //IsLock string `json:"is_lock"` + //IsCopyright int `json:"is_copyright"` + + // 文件通用 + ID string `json:"id"` + NameAll string `json:"name_all"` + Size string `json:"size"` + Time string `json:"time"` + //Icon string `json:"icon"` + //Downs string `json:"downs"` + //Filelock string `json:"filelock"` + //IsBakdownload int `json:"is_bakdownload"` + //Bakdownload string `json:"bakdownload"` + //IsDes int `json:"is_des"` // 是否存在描述 + //IsIco int `json:"is_ico"` + + // 文件夹 + FolID string `json:"fol_id"` + //Folderlock string `json:"folderlock"` + //FolderDes string `json:"folder_des"` +} + +func (f *FileOrFolder) isFloder() bool { + return f.FolID != "" +} +func (f *FileOrFolder) ToObj() model.Obj { + obj := &model.Object{} + if f.isFloder() { + obj.ID = f.FolID + obj.Name = f.Name + obj.Modified = time.Now() + obj.IsFolder = true + } else { + obj.ID = f.ID + obj.Name = f.NameAll + obj.Modified = MustParseTime(f.Time) + obj.Size = SizeStrToInt64(f.Size) + } + return obj +} + +type FileShareResp struct { + Info FileShare `json:"info"` +} +type FileShare struct { + Pwd string `json:"pwd"` + Onof string `json:"onof"` + Taoc string `json:"taoc"` + IsNewd string `json:"is_newd"` + + // 文件 + FID string `json:"f_id"` + + // 文件夹 + NewUrl string `json:"new_url"` + Name string `json:"name"` + Des string `json:"des"` +} + +type FileOrFolderByShareUrlResp struct { + Text []FileOrFolderByShareUrl `json:"text"` +} +type FileOrFolderByShareUrl struct { + ID string `json:"id"` + NameAll string `json:"name_all"` + Size string `json:"size"` + Time string `json:"time"` + Duan string `json:"duan"` + //Icon string `json:"icon"` + //PIco int `json:"p_ico"` + //T int `json:"t"` + IsFloder bool +} + +func (f *FileOrFolderByShareUrl) ToObj() model.Obj { + return &model.Object{ + ID: f.ID, + Name: f.NameAll, + Size: SizeStrToInt64(f.Size), + Modified: MustParseTime(f.Time), + IsFolder: f.IsFloder, + } +} + +type FileShareInfoAndUrlResp[T string | int] struct { + Dom string `json:"dom"` + URL string `json:"url"` + Inf T `json:"inf"` +} + +func (u *FileShareInfoAndUrlResp[T]) GetBaseUrl() string { + return fmt.Sprint(u.Dom, "/file") +} + +func (u *FileShareInfoAndUrlResp[T]) GetDownloadUrl() string { + return fmt.Sprint(u.GetBaseUrl(), "/", u.URL) +} + +// 通过分享链接获取文件信息和下载链接 +type FileInfoAndUrlByShareUrl struct { + ID string + Name string + Size string + Time string + Url string +} + +func (f *FileInfoAndUrlByShareUrl) ToObj() model.Obj { + return &model.Object{ + ID: f.ID, + Name: f.Name, + Size: SizeStrToInt64(f.Size), + Modified: MustParseTime(f.Time), + } +} diff --git a/drivers/lanzou/util.go b/drivers/lanzou/util.go new file mode 100644 index 00000000000..4836bdf9465 --- /dev/null +++ b/drivers/lanzou/util.go @@ -0,0 +1,416 @@ +package lanzou + +import ( + "context" + "fmt" + "net/http" + "regexp" + "strconv" + "strings" + "time" + + "github.com/alist-org/alist/v3/drivers/base" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/utils" + "github.com/go-resty/resty/v2" +) + +func (d *LanZou) get(url string, callback base.ReqCallback, resp interface{}) ([]byte, error) { + return d.request(url, http.MethodGet, callback, false) +} + +func (d *LanZou) post(url string, callback base.ReqCallback, resp interface{}) ([]byte, error) { + return d._post(url, callback, resp, false) +} + +func (d *LanZou) _post(url string, callback base.ReqCallback, resp interface{}, up bool) ([]byte, error) { + data, err := d.request(url, http.MethodPost, callback, up) + if err != nil { + return nil, err + } + switch utils.Json.Get(data, "zt").ToInt() { + case 1, 2, 4: + if resp != nil { + // 返回类型不统一,忽略错误 + utils.Json.Unmarshal(data, resp) + } + return data, nil + default: + info := utils.Json.Get(data, "inf").ToString() + if info == "" { + info = utils.Json.Get(data, "info").ToString() + } + return nil, fmt.Errorf(info) + } +} + +func (d *LanZou) request(url string, method string, callback base.ReqCallback, up bool) ([]byte, error) { + var req *resty.Request + if up { + req = upClient.R() + } else { + req = base.RestyClient.R() + } + + req.SetHeaders(map[string]string{ + "Referer": "https://pc.woozooo.com", + }) + + if d.Cookie != "" { + req.SetHeader("cookie", d.Cookie) + } + + if callback != nil { + callback(req) + } + + res, err := req.Execute(method, url) + if err != nil { + return nil, err + } + + return res.Body(), err +} + +/* +通过cookie获取数据 +*/ + +// 获取文件和文件夹,获取到的文件大小、更改时间不可信 +func (d *LanZou) GetFiles(ctx context.Context, folderID string) ([]model.Obj, error) { + folders, err := d.getFolders(ctx, folderID) + if err != nil { + return nil, err + } + files, err := d.getFiles(ctx, folderID) + if err != nil { + return nil, err + } + objs := make([]model.Obj, 0, len(folders)+len(files)) + for _, folder := range folders { + objs = append(objs, folder.ToObj()) + } + + for _, file := range files { + objs = append(objs, file.ToObj()) + } + return objs, nil +} + +// 通过ID获取文件夹 +func (d *LanZou) getFolders(ctx context.Context, folderID string) ([]FileOrFolder, error) { + var resp FilesOrFoldersResp + _, err := d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "47", + "folder_id": folderID, + }) + }, &resp) + if err != nil { + return nil, err + } + return resp.Text, nil +} + +// 通过ID获取文件 +func (d *LanZou) getFiles(ctx context.Context, folderID string) ([]FileOrFolder, error) { + files := make([]FileOrFolder, 0) + for pg := 1; ; pg++ { + var resp FilesOrFoldersResp + _, err := d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "5", + "folder_id": folderID, + "pg": strconv.Itoa(pg), + }) + }, &resp) + if err != nil { + return nil, err + } + if len(resp.Text) == 0 { + break + } + files = append(files, resp.Text...) + } + return files, nil +} + +// 通过ID获取文件夹分享地址 +func (d *LanZou) getFolderShareUrlByID(ctx context.Context, fileID string) (share FileShare, err error) { + var resp FileShareResp + _, err = d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "18", + "file_id": fileID, + }) + }, &resp) + if err != nil { + return + } + share = resp.Info + return +} + +// 通过ID获取文件分享地址 +func (d *LanZou) getFileShareUrlByID(ctx context.Context, fileID string) (share FileShare, err error) { + var resp FileShareResp + _, err = d.post(d.BaseUrl+"/doupload.php", func(req *resty.Request) { + req.SetContext(ctx) + req.SetFormData(map[string]string{ + "task": "22", + "file_id": fileID, + }) + }, &resp) + if err != nil { + return + } + share = resp.Info + return +} + +/* +通过分享链接获取数据 +*/ + +// 判断类容 +var isFileReg = regexp.MustCompile(`class="fileinfo"|id="file"|文件描述`) +var isFolderReg = regexp.MustCompile(`id="infos"`) + +// 获取文件文件夹基础信息 +var nameFindReg = regexp.MustCompile(`(.+?) - 蓝奏云|id="filenajax">(.+?)|var filename = '(.+?)';|
([^<>]+?)
`) +var sizeFindReg = regexp.MustCompile(`(?i)大小\W*([0-9.]+\s*[bkm]+)`) +var timeFindReg = regexp.MustCompile(`\d+\s*[秒天分小][钟时]?前|[昨前]天|\d{4}-\d{2}-\d{2}`) + +var findSubFolaerReg = regexp.MustCompile(`(folderlink|mbxfolder).+href="/(.+?)"(.+filename")?>(.+?)<`) // 查找分享文件夹子文件夹ID和名称 + +// 获取关键数据 +var findDownPageParamReg = regexp.MustCompile(` 1 { + for _, name := range names[1:] { + if name != "" { + file.Name = name + break + } + } + } + } + + sizes := sizeFindReg.FindStringSubmatch(firstPageDataStr) + if len(sizes) == 2 { + file.Size = sizes[1] + } + file.ID = downID + file.Time = timeFindReg.FindString(firstPageDataStr) + + // 重定向获取真实链接 + res, err := base.NoRedirectClient.R().SetHeaders(map[string]string{ + "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + }).SetContext(ctx).Get(downloadUrl) + if err != nil { + return + } + + file.Url = res.Header().Get("location") + + // 触发验证 + rPageDataStr := res.String() + if res.StatusCode() != 302 && strings.Contains(rPageDataStr, "网络异常") { + param, err = htmlJsonToMap(rPageDataStr) + if err != nil { + return + } + param["el"] = "2" + time.Sleep(time.Second * 2) + + // 通过验证获取直连 + var rUrl struct { + Url string `json:"url"` + } + _, err = d.post(fmt.Sprint(baseUrl, "/ajax.php"), func(req *resty.Request) { req.SetContext(ctx).SetFormData(param) }, &rUrl) + if err != nil { + return + } + file.Url = rUrl.Url + } + return +} + +// 通过分享链接获取文件夹 +// 参考 https://github.com/zaxtyson/LanZouCloud-API/blob/ab2e9ec715d1919bf432210fc16b91c6775fbb99/lanzou/api/core.py#L1089 +func (d *LanZou) getFolderByShareUrl(ctx context.Context, downID, pwd string, firstPageData []byte) ([]FileOrFolderByShareUrl, error) { + if firstPageData == nil { + var err error + firstPageData, err = d.get(fmt.Sprint(d.ShareUrl, "/", downID), func(req *resty.Request) { req.SetContext(ctx) }, nil) + if err != nil { + return nil, err + } + firstPageData = RemoveNotes(firstPageData) + } + firstPageDataStr := string(firstPageData) + + // + if strings.Contains(firstPageDataStr, "acw_sc__v2") { + vs, err := CalcAcwScV2(firstPageDataStr) + if err != nil { + return nil, err + } + firstPageData, err = d.get(fmt.Sprint(d.ShareUrl, "/", downID), func(req *resty.Request) { + req.SetCookie(&http.Cookie{ + Name: "acw_sc__v2", + Value: vs, + }) + req.SetContext(ctx) + }, nil) + if err != nil { + return nil, err + } + firstPageData = RemoveNotes(firstPageData) + firstPageDataStr = string(firstPageData) + } + + from, err := htmlJsonToMap(firstPageDataStr) + if err != nil { + return nil, err + } + from["pwd"] = pwd + + files := make([]FileOrFolderByShareUrl, 0) + // vip获取文件夹 + floders := findSubFolaerReg.FindAllStringSubmatch(firstPageDataStr, -1) + for _, floder := range floders { + if len(floder) == 5 { + files = append(files, FileOrFolderByShareUrl{ + ID: floder[2], + NameAll: floder[4], + IsFloder: true, + }) + } + } + + for page := 1; ; page++ { + from["pg"] = strconv.Itoa(page) + var resp FileOrFolderByShareUrlResp + _, err := d.post(d.ShareUrl+"/filemoreajax.php", func(req *resty.Request) { req.SetFormData(from).SetContext(ctx) }, &resp) + if err != nil { + return nil, err + } + files = append(files, resp.Text...) + if len(resp.Text) == 0 { + break + } + time.Sleep(time.Millisecond * 600) + } + return files, nil +}