From 7c3ea193ff6f97f7b78a39c1c93b5300c7dfb1b6 Mon Sep 17 00:00:00 2001 From: foxxorcat <95907542+foxxorcat@users.noreply.github.com> Date: Sun, 8 Jan 2023 15:37:39 +0800 Subject: [PATCH] fix(lanzou):webdav unable to download and upload (close #2700) * fix(lanzou):Unable to get folder * fix(lanzou):webdav unable to download and upload. (close 2700) --- drivers/lanzou/driver.go | 65 ++++++--- drivers/lanzou/help.go | 11 +- drivers/lanzou/meta.go | 9 +- drivers/lanzou/types.go | 126 ++++++++++------- drivers/lanzou/util.go | 295 +++++++++++++++++++++------------------ 5 files changed, 299 insertions(+), 207 deletions(-) diff --git a/drivers/lanzou/driver.go b/drivers/lanzou/driver.go index 810b0193..4e96ad1d 100644 --- a/drivers/lanzou/driver.go +++ b/drivers/lanzou/driver.go @@ -52,30 +52,65 @@ func (d *LanZou) Drop(ctx context.Context) error { // 获取的大小和时间不准确 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()) + return d.GetAllFiles(dir.GetID()) } else { - return d.GetFileOrFolderByShareUrl(ctx, dir.GetID(), d.SharePassword) + return d.GetFileOrFolderByShareUrl(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()) + var ( + err error + dfile *FileOrFolderByShareUrl + ) + switch file := file.(type) { + case *FileOrFolder: + // 先获取分享链接 + sfile := file.GetShareInfo() + if sfile == nil { + sfile, err = d.getFileShareUrlByID(file.GetID()) + if err != nil { + return nil, err + } + file.SetShareInfo(sfile) + } + + // 然后获取下载链接 + dfile, err = d.GetFilesByShareUrl(sfile.FID, sfile.Pwd) 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 + // 修复文件大小 + if d.RepairFileInfo && !file.repairFlag { + size, time := d.getFileRealInfo(dfile.Url) + if size != nil { + file.size = size + file.repairFlag = true + } + if file.time != nil { + file.time = time + } + } + case *FileOrFolderByShareUrl: + dfile, err = d.GetFilesByShareUrl(file.GetID(), file.Pwd) + if err != nil { + return nil, err + } + // 修复文件大小 + if d.RepairFileInfo && !file.repairFlag { + size, time := d.getFileRealInfo(dfile.Url) + if size != nil { + file.size = size + file.repairFlag = true + } + if file.time != nil { + file.time = time + } + } } return &model.Link{ - URL: fileInfo.Url, + URL: dfile.Url, Header: http.Header{ "User-Agent": []string{base.UserAgent}, }, @@ -133,10 +168,6 @@ func (d *LanZou) Rename(ctx context.Context, srcObj model.Obj, newName string) e 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.doupload(func(req *resty.Request) { diff --git a/drivers/lanzou/help.go b/drivers/lanzou/help.go index f48a936f..4cb646c4 100644 --- a/drivers/lanzou/help.go +++ b/drivers/lanzou/help.go @@ -17,6 +17,7 @@ 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 { @@ -47,6 +48,7 @@ func MustParseTime(str string) time.Time { // 解析大小 var sizeSplitReg = regexp.MustCompile(`(?i)([0-9.]+)\s*([bkm]+)`) +// 解析失败返回0 func SizeStrToInt64(size string) int64 { strs := sizeSplitReg.FindStringSubmatch(size) if len(strs) < 3 { @@ -66,8 +68,13 @@ func SizeStrToInt64(size string) int64 { } // 移除注释 -func RemoveNotes(html []byte) []byte { - return regexp.MustCompile(`|//.*|/\*.*?\*/`).ReplaceAll(html, []byte{}) +func RemoveNotes(html string) string { + return regexp.MustCompile(`|[^:]//.*|/\*.*?\*/`).ReplaceAllStringFunc(html, func(b string) string { + if b[1:3] == "//" { + return b[:1] + } + return "\n" + }) } var findAcwScV2Reg = regexp.MustCompile(`arg1='([0-9A-Z]+)'`) diff --git a/drivers/lanzou/meta.go b/drivers/lanzou/meta.go index 8b2267e9..5fe21d26 100644 --- a/drivers/lanzou/meta.go +++ b/drivers/lanzou/meta.go @@ -7,11 +7,12 @@ import ( 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"` + Cookie string `json:"cookie" required:"true" help:"about 15 days valid, ignore if shareUrl is used"` 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"` + SharePassword string `json:"share_password"` + BaseUrl string `json:"baseUrl" required:"true" default:"https://pc.woozooo.com" help:"basic URL for file operation"` + ShareUrl string `json:"shareUrl" required:"true" default:"https://pan.lanzouo.com" help:"used to get the sharing page"` + RepairFileInfo bool `json:"repair_file_info" help:"To use webdav, you need to enable it"` } func (a *Addition) IsCookie() bool { diff --git a/drivers/lanzou/types.go b/drivers/lanzou/types.go index 50f79b09..9044b296 100644 --- a/drivers/lanzou/types.go +++ b/drivers/lanzou/types.go @@ -1,12 +1,14 @@ package lanzou import ( + "errors" "fmt" "time" - - "github.com/alist-org/alist/v3/internal/model" ) +var ErrFileShareCancel = errors.New("file sharing cancellation") +var ErrFileNotExist = errors.New("file does not exist") + type FilesOrFoldersResp struct { Text []FileOrFolder `json:"text"` } @@ -34,27 +36,51 @@ type FileOrFolder struct { FolID string `json:"fol_id"` //Folderlock string `json:"folderlock"` //FolderDes string `json:"folder_des"` + + // 缓存字段 + size *int64 `json:"-"` + time *time.Time `json:"-"` + repairFlag bool `json:"-"` + shareInfo *FileShare `json:"-"` } -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) +func (f *FileOrFolder) GetID() string { + if f.IsDir() { + return f.FolID } - return obj + return f.ID +} +func (f *FileOrFolder) GetName() string { + if f.IsDir() { + return f.Name + } + return f.NameAll +} +func (f *FileOrFolder) GetPath() string { return "" } +func (f *FileOrFolder) GetSize() int64 { + if f.size == nil { + size := SizeStrToInt64(f.Size) + f.size = &size + } + return *f.size +} +func (f *FileOrFolder) IsDir() bool { return f.FolID != "" } +func (f *FileOrFolder) ModTime() time.Time { + if f.time == nil { + time := MustParseTime(f.Time) + f.time = &time + } + return *f.time } +func (f *FileOrFolder) SetShareInfo(fs *FileShare) { + f.shareInfo = fs +} +func (f *FileOrFolder) GetShareInfo() *FileShare { + return f.shareInfo +} + +/* 通过ID获取文件/文件夹分享信息 */ type FileShareResp struct { Info FileShare `json:"info"` } @@ -73,31 +99,55 @@ type FileShare struct { 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"` + + // 文件特有 + Duan string `json:"duan"` + Size string `json:"size"` + Time string `json:"time"` //Icon string `json:"icon"` //PIco int `json:"p_ico"` //T int `json:"t"` - IsFloder bool + + // 文件夹特有 + IsFloder bool `json:"-"` + + // + Url string `json:"-"` + Pwd string `json:"-"` + + // 缓存字段 + size *int64 `json:"-"` + time *time.Time `json:"-"` + repairFlag bool `json:"-"` } -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, +func (f *FileOrFolderByShareUrl) GetID() string { return f.ID } +func (f *FileOrFolderByShareUrl) GetName() string { return f.NameAll } +func (f *FileOrFolderByShareUrl) GetPath() string { return "" } +func (f *FileOrFolderByShareUrl) GetSize() int64 { + if f.size == nil { + size := SizeStrToInt64(f.Size) + f.size = &size } + return *f.size +} +func (f *FileOrFolderByShareUrl) IsDir() bool { return f.IsFloder } +func (f *FileOrFolderByShareUrl) ModTime() time.Time { + if f.time == nil { + time := MustParseTime(f.Time) + f.time = &time + } + return *f.time } +// 获取下载链接的响应 type FileShareInfoAndUrlResp[T string | int] struct { Dom string `json:"dom"` URL string `json:"url"` @@ -111,21 +161,3 @@ func (u *FileShareInfoAndUrlResp[T]) GetBaseUrl() string { 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 index 7b5d01fd..7bdc0799 100644 --- a/drivers/lanzou/util.go +++ b/drivers/lanzou/util.go @@ -1,7 +1,7 @@ package lanzou import ( - "context" + "errors" "fmt" "net/http" "regexp" @@ -32,7 +32,16 @@ func (d *LanZou) post(url string, callback base.ReqCallback, resp interface{}) ( } func (d *LanZou) _post(url string, callback base.ReqCallback, resp interface{}, up bool) ([]byte, error) { - data, err := d.request(url, http.MethodPost, callback, up) + data, err := d.request(url, http.MethodPost, func(req *resty.Request) { + req.AddRetryCondition(func(r *resty.Response, err error) bool { + if utils.Json.Get(r.Body(), "zt").ToInt() == 4 { + time.Sleep(time.Second) + return true + } + return false + }) + callback(req) + }, up) if err != nil { return nil, err } @@ -85,29 +94,28 @@ func (d *LanZou) request(url string, method string, callback base.ReqCallback, u */ // 获取文件和文件夹,获取到的文件大小、更改时间不可信 -func (d *LanZou) GetFiles(ctx context.Context, folderID string) ([]model.Obj, error) { - folders, err := d.getFolders(ctx, folderID) +func (d *LanZou) GetAllFiles(folderID string) ([]model.Obj, error) { + folders, err := d.GetFolders(folderID) if err != nil { return nil, err } - files, err := d.getFiles(ctx, folderID) + files, err := d.GetFiles(folderID) if err != nil { return nil, err } return append( utils.MustSliceConvert(folders, func(folder FileOrFolder) model.Obj { - return folder.ToObj() + return &folder }), utils.MustSliceConvert(files, func(file FileOrFolder) model.Obj { - return file.ToObj() + return &file })..., ), nil } // 通过ID获取文件夹 -func (d *LanZou) getFolders(ctx context.Context, folderID string) ([]FileOrFolder, error) { +func (d *LanZou) GetFolders(folderID string) ([]FileOrFolder, error) { var resp FilesOrFoldersResp _, err := d.doupload(func(req *resty.Request) { - req.SetContext(ctx) req.SetFormData(map[string]string{ "task": "47", "folder_id": folderID, @@ -120,12 +128,11 @@ func (d *LanZou) getFolders(ctx context.Context, folderID string) ([]FileOrFolde } // 通过ID获取文件 -func (d *LanZou) getFiles(ctx context.Context, folderID string) ([]FileOrFolder, error) { +func (d *LanZou) GetFiles(folderID string) ([]FileOrFolder, error) { files := make([]FileOrFolder, 0) for pg := 1; ; pg++ { var resp FilesOrFoldersResp _, err := d.doupload(func(req *resty.Request) { - req.SetContext(ctx) req.SetFormData(map[string]string{ "task": "5", "folder_id": folderID, @@ -144,37 +151,33 @@ func (d *LanZou) getFiles(ctx context.Context, folderID string) ([]FileOrFolder, } // 通过ID获取文件夹分享地址 -func (d *LanZou) getFolderShareUrlByID(ctx context.Context, fileID string) (share FileShare, err error) { +func (d *LanZou) getFolderShareUrlByID(fileID string) (*FileShare, error) { var resp FileShareResp - _, err = d.doupload(func(req *resty.Request) { - req.SetContext(ctx) + _, err := d.doupload(func(req *resty.Request) { req.SetFormData(map[string]string{ "task": "18", "file_id": fileID, }) }, &resp) if err != nil { - return + return nil, err } - share = resp.Info - return + return &resp.Info, nil } // 通过ID获取文件分享地址 -func (d *LanZou) getFileShareUrlByID(ctx context.Context, fileID string) (share FileShare, err error) { +func (d *LanZou) getFileShareUrlByID(fileID string) (*FileShare, error) { var resp FileShareResp - _, err = d.doupload(func(req *resty.Request) { - req.SetContext(ctx) + _, err := d.doupload(func(req *resty.Request) { req.SetFormData(map[string]string{ "task": "22", "file_id": fileID, }) }, &resp) if err != nil { - return + return nil, err } - share = resp.Info - return + return &resp.Info, nil } /* @@ -186,234 +189,252 @@ 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和名称 +// 查找分享文件夹子文件夹ID和名称 +var findSubFolaerReg = regexp.MustCompile(`(?i)(?:folderlink|mbxfolder).+href="/(.+?)"(?:.+filename")?>(.+?)<`) -// 获取关键数据 +// 获取下载页面链接 var findDownPageParamReg = regexp.MustCompile(` acw_sc__v2 validation error ,data => %s\n", firstPageDataStr) + return "", err + } + continue + } + return firstPageDataStr, nil + } + return "", errors.New("acw_sc__v2 validation error") +} + +// 通过分享链接获取文件或文件夹 +func (d *LanZou) GetFileOrFolderByShareUrl(shareID, pwd string) ([]model.Obj, error) { + pageData, err := d.getShareUrlHtml(shareID) if err != nil { return nil, err } - pageData = RemoveNotes(pageData) - if !isFileReg.Match(pageData) { - files, err := d.getFolderByShareUrl(ctx, downID, pwd, pageData) + if !isFileReg.MatchString(pageData) { + files, err := d.getFolderByShareUrl(pwd, pageData) if err != nil { return nil, err } return utils.MustSliceConvert(files, func(file FileOrFolderByShareUrl) model.Obj { - return file.ToObj() + return &file }), nil } else { - file, err := d.getFilesByShareUrl(ctx, downID, pwd, pageData) + file, err := d.getFilesByShareUrl(shareID, pwd, pageData) if err != nil { return nil, err } - return []model.Obj{file.ToObj()}, nil + return []model.Obj{file}, nil } } // 通过分享链接获取文件(下载链接也使用此方法) +// FileOrFolderByShareUrl 包含 pwd 和 url 字段 // 参考 https://github.com/zaxtyson/LanZouCloud-API/blob/ab2e9ec715d1919bf432210fc16b91c6775fbb99/lanzou/api/core.py#L440 -func (d *LanZou) getFilesByShareUrl(ctx context.Context, downID, pwd string, firstPageData []byte) (file FileInfoAndUrlByShareUrl, err error) { - if firstPageData == nil { - firstPageData, err = d.get(fmt.Sprint(d.ShareUrl, "/", downID), func(req *resty.Request) { req.SetContext(ctx) }, nil) - if err != nil { - return - } - firstPageData = RemoveNotes(firstPageData) - } - firstPageDataStr := string(firstPageData) - - if strings.Contains(firstPageDataStr, "acw_sc__v2") { - var vs string - if vs, err = CalcAcwScV2(firstPageDataStr); err != nil { - return - } - 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 - } - firstPageData = RemoveNotes(firstPageData) - firstPageDataStr = string(firstPageData) +func (d *LanZou) GetFilesByShareUrl(shareID, pwd string) (file *FileOrFolderByShareUrl, err error) { + pageData, err := d.getShareUrlHtml(shareID) + if err != nil { + return nil, err } + return d.getFilesByShareUrl(shareID, pwd, pageData) +} +func (d *LanZou) getFilesByShareUrl(shareID, pwd string, sharePageData string) (*FileOrFolderByShareUrl, error) { var ( param map[string]string downloadUrl string baseUrl string + file FileOrFolderByShareUrl ) // 需要密码 - if strings.Contains(firstPageDataStr, "pwdload") || strings.Contains(firstPageDataStr, "passwddiv") { - param, err = htmlFormToMap(firstPageDataStr) + if strings.Contains(sharePageData, "pwdload") || strings.Contains(sharePageData, "passwddiv") { + param, err := htmlFormToMap(sharePageData) if err != nil { - return + return nil, err } param["p"] = pwd var resp FileShareInfoAndUrlResp[string] - _, err = d.post(d.ShareUrl+"/ajaxm.php", func(req *resty.Request) { req.SetFormData(param).SetContext(ctx) }, &resp) + _, err = d.post(d.ShareUrl+"/ajaxm.php", func(req *resty.Request) { req.SetFormData(param) }, &resp) if err != nil { - return + return nil, err } - file.Name = resp.Inf + file.NameAll = resp.Inf + file.Pwd = pwd baseUrl = resp.GetBaseUrl() downloadUrl = resp.GetDownloadUrl() } else { - urlpaths := findDownPageParamReg.FindStringSubmatch(firstPageDataStr) + urlpaths := findDownPageParamReg.FindStringSubmatch(sharePageData) if len(urlpaths) != 2 { - err = fmt.Errorf("not find file page param") - return + log.Errorf("lanzou: err => not find file page param ,data => %s\n", sharePageData) + return nil, fmt.Errorf("not find file page param") } - var nextPageData []byte - nextPageData, err = d.get(fmt.Sprint(d.ShareUrl, urlpaths[1]), func(req *resty.Request) { req.SetContext(ctx) }, nil) + data, err := d.get(fmt.Sprint(d.ShareUrl, urlpaths[1]), nil, nil) if err != nil { - return + return nil, err } - nextPageData = RemoveNotes(nextPageData) - nextPageDataStr := string(nextPageData) + nextPageData := RemoveNotes(string(data)) - param, err = htmlJsonToMap(nextPageDataStr) + param, err = htmlJsonToMap(nextPageData) if err != nil { - return + return nil, err } var resp FileShareInfoAndUrlResp[int] - _, err = d.post(d.ShareUrl+"/ajaxm.php", func(req *resty.Request) { req.SetFormData(param).SetContext(ctx) }, &resp) + _, err = d.post(d.ShareUrl+"/ajaxm.php", func(req *resty.Request) { req.SetFormData(param) }, &resp) if err != nil { - return + return nil, err } baseUrl = resp.GetBaseUrl() downloadUrl = resp.GetDownloadUrl() - names := nameFindReg.FindStringSubmatch(firstPageDataStr) + names := nameFindReg.FindStringSubmatch(sharePageData) if len(names) > 1 { for _, name := range names[1:] { if name != "" { - file.Name = name + file.NameAll = name break } } } } - sizes := sizeFindReg.FindStringSubmatch(firstPageDataStr) + sizes := sizeFindReg.FindStringSubmatch(sharePageData) if len(sizes) == 2 { file.Size = sizes[1] } - file.ID = downID - file.Time = timeFindReg.FindString(firstPageDataStr) + file.ID = shareID + file.Time = timeFindReg.FindString(sharePageData) // 重定向获取真实链接 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) + }).Get(downloadUrl) if err != nil { - return + return nil, err } file.Url = res.Header().Get("location") // 触发验证 - rPageDataStr := res.String() - if res.StatusCode() != 302 && strings.Contains(rPageDataStr, "网络异常") { - param, err = htmlJsonToMap(rPageDataStr) + rPageData := res.String() + if res.StatusCode() != 302 { + param, err = htmlJsonToMap(rPageData) if err != nil { - return + return nil, err } 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) + data, err := d.post(fmt.Sprint(baseUrl, "/ajax.php"), func(req *resty.Request) { req.SetFormData(param) }, nil) if err != nil { - return + return nil, err } - file.Url = rUrl.Url + file.Url = utils.Json.Get(data, "url").ToString() } - return + return &file, nil } // 通过分享链接获取文件夹 +// 似乎子目录和文件不会加密 // 参考 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) +func (d *LanZou) GetFolderByShareUrl(shareID, pwd string) ([]FileOrFolderByShareUrl, error) { + pageData, err := d.getShareUrlHtml(shareID) + if err != nil { + return nil, err + } + return d.getFolderByShareUrl(pwd, pageData) +} + +func (d *LanZou) getFolderByShareUrl(pwd string, sharePageData string) ([]FileOrFolderByShareUrl, error) { + from, err := htmlJsonToMap(sharePageData) if err != nil { return nil, err } - from["pwd"] = pwd files := make([]FileOrFolderByShareUrl, 0) // vip获取文件夹 - floders := findSubFolaerReg.FindAllStringSubmatch(firstPageDataStr, -1) + floders := findSubFolaerReg.FindAllStringSubmatch(sharePageData, -1) for _, floder := range floders { - if len(floder) == 5 { + if len(floder) == 3 { files = append(files, FileOrFolderByShareUrl{ - ID: floder[2], - NameAll: floder[4], + // Pwd: pwd, // 子文件夹不加密 + ID: floder[1], + NameAll: floder[2], IsFloder: true, }) } } + // 获取文件 + from["pwd"] = pwd 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) + _, err := d.post(d.ShareUrl+"/filemoreajax.php", func(req *resty.Request) { req.SetFormData(from) }, &resp) if err != nil { return nil, err } - files = append(files, resp.Text...) + /*// 文件夹中的文件也不加密 + for i := 0; i < len(resp.Text); i++ { + resp.Text[i].Pwd = pwd + }*/ if len(resp.Text) == 0 { break } - time.Sleep(time.Millisecond * 600) + files = append(files, resp.Text...) + time.Sleep(time.Second) } return files, nil } + +// 通过下载头获取真实文件信息 +func (d *LanZou) getFileRealInfo(downURL string) (*int64, *time.Time) { + res, _ := base.RestyClient.R().Head(downURL) + if res == nil { + return nil, nil + } + time, _ := http.ParseTime(res.Header().Get("Last-Modified")) + size, _ := strconv.ParseInt(res.Header().Get("Content-Length"), 10, 64) + return &size, &time +}