diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cbf4a8..5a67096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # 189Cloud-Downloader 一个189云盘的下载器。(支持分享链接下载、支持Windows、Linux、macOS)Based Go. +## v0.1.4 +1. 修复单文件分享时找不到shareId的问题。 +2. 修复在个别情况下载文件损坏的问题。 + ## v0.1.3 1. fix `get` current not found. diff --git a/action.go b/action.go index 2976e0e..087cb5f 100644 --- a/action.go +++ b/action.go @@ -92,6 +92,10 @@ func shareAction(ctx *cli.Context) (err error) { return } share.AccessCode = strings.TrimSpace(ctx.Args().Get(1)) + if share.IsFile { + paths = []*model.Path{{FileName: "share"}} + return + } if _, paths, err = d.GetShareDirList(ctx.Context, share, 0, 0, ""); err != nil { log.Error("d.GetShareDirList(%s) error(%v)", ctx.Args().Get(0), err) return @@ -118,9 +122,18 @@ func lsAction(ctx *cli.Context) (err error) { return } } else if share != nil { - if dirs, _, err = d.GetShareDirList(ctx.Context, share, pn, ps, order, path); err != nil { - log.Error("d.GetShareDirList() pn(%d) ps(%d) fileId(%s) error(%v)", pn, ps, path, err) - return + if !share.IsFile { + if dirs, _, err = d.GetShareDirList(ctx.Context, share, pn, ps, order, path); err != nil { + log.Error("d.GetShareDirList() pn(%d) ps(%d) fileId(%s) error(%v)", pn, ps, path, err) + return + } + } else { + var dir *model.Dir + if dir, err = d.GetShareFileInfo(ctx.Context, share); err != nil { + log.Error("d.GetShareFileInfo(%s) error(%v)", share.ShortCode, err) + return + } + dirs = []*model.Dir{dir} } } else { if path != "" { diff --git a/dao/get.go b/dao/get.go index c420dec..8204280 100644 --- a/dao/get.go +++ b/dao/get.go @@ -74,10 +74,6 @@ func (d *dao) Download(ctx context.Context, url, toPath string, c int, tmpDirs . } else { shortName = string(r[:12]) + "..." } - if !strings.Contains(url, "https://cloud.189.cn") && - resp.Header.Get("Accept-Ranges") != "bytes" { - c = 1 - } if c != 1 && b < 10*1024*1024 { c = 1 } @@ -111,10 +107,12 @@ func (d *dao) Download(ctx context.Context, url, toPath string, c int, tmpDirs . ) download: if retry++; retry >= 3 { - log.Error("file(%s) part(%d) 下载失败! 发生了如下错误:%v", matchs[1], i, err) + println() + log.Error("file(%s) part(%d) 下载失败!可能当前资源并不支持多线程下载!", matchs[1], i) return } else if retry > 0 { - log.Info("file(%s) part(%d) 下载失败!正在进行重试...(%d/3)", matchs[1], i, retry) + println() + log.Error("file(%s) part(%d) 下载失败!正在进行重试...(%d/3)", matchs[1], i, retry) bar.Add(-size) size = 0 time.Sleep(3 * time.Second) @@ -136,10 +134,11 @@ func (d *dao) Download(ctx context.Context, url, toPath string, c int, tmpDirs . downResp.Body.Close() goto download } - if _, err = d.readTo(tmpFile, downResp.Body, bar); err != nil { + time.Sleep(time.Duration(i) * time.Second) + var written int64 + if written, err = d.readTo(tmpFile, downResp.Body, bar); err != nil || written < end-start { downResp.Body.Close() tmpFile.Close() - log.Error("d.readTo(target, part) error(%v)", err) goto download } return @@ -194,8 +193,8 @@ func (d *dao) readTo(dst io.Writer, src io.Reader, bar ...*progressbar.Bar) (wri } } if readErr != nil { - if readErr != io.EOF && - readErr != io.ErrUnexpectedEOF { + if readErr != io.EOF && readErr != io.ErrUnexpectedEOF { + log.Error("d.readTo(target, part) error(%v)", readErr) err = readErr break } diff --git a/dao/share.go b/dao/share.go index 4c0fdd3..0bc75d1 100644 --- a/dao/share.go +++ b/dao/share.go @@ -18,12 +18,14 @@ import ( ) const ( - _listShareDirAPI = "https://cloud.189.cn/v2/listShareDirByShareIdAndFileId.action?" - _getDownloadUrlAPI = "https://cloud.189.cn/v2/getFileDownloadUrl.action?" + _listShareDirAPI = "https://cloud.189.cn/v2/listShareDirByShareIdAndFileId.action?" + _getShareFileInfoAPI = "https://cloud.189.cn/shareFileByVerifyCode.action?" + _getDownloadUrlAPI = "https://cloud.189.cn/v2/getFileDownloadUrl.action?" ) var ( _shareIdReg = regexp.MustCompile(`var\s+_shareId\s+?=\s+?'(\d+)';`) + _shareIdReg2 = regexp.MustCompile(``) _verifyCodeReg = regexp.MustCompile(`var\s+_verifyCode\s+?=\s+?'(\d+)';`) _shortCodeReg = regexp.MustCompile(`https://cloud.189.cn/t/((?:\w+){12})`) _shareNameReg = regexp.MustCompile(`\s+(.*?)\s+`) @@ -35,6 +37,7 @@ func (d *dao) GetShareInfo(ctx context.Context, url string) (share *model.ShareI if resp, err = d.httpCli.Get(url); err != nil { return } + defer resp.Body.Close() var body []byte if body, err = ioutil.ReadAll(resp.Body); err != nil { return @@ -47,21 +50,27 @@ func (d *dao) GetShareInfo(ctx context.Context, url string) (share *model.ShareI share.ShortCode = matchShortCode[1] var matchShareID []string if matchShareID = _shareIdReg.FindStringSubmatch(string(body)); len(matchShareID) <= 1 { - err = errors.New("没能找到shareId,需要作者更新脚本。。。") - return + if matchShareID = _shareIdReg2.FindStringSubmatch(string(body)); len(matchShareID) <= 1 { + err = errors.New("没能找到shareId,需要作者更新脚本。。。") + return + } + share.Name = "share" + share.IsFile = true } share.ShareID = matchShareID[1] - var matchVerifyCode []string - if matchVerifyCode = _verifyCodeReg.FindStringSubmatch(string(body)); len(matchVerifyCode) <= 1 { - err = errors.New("没能找到verifyCode,需要作者更新脚本。。。") - return - } - share.VerifyCode = matchVerifyCode[1] - var matchShareName []string - if matchShareName = _shareNameReg.FindStringSubmatch(string(body)); len(matchShareName) <= 1 { - return + if !share.IsFile { + var matchVerifyCode []string + if matchVerifyCode = _verifyCodeReg.FindStringSubmatch(string(body)); len(matchVerifyCode) <= 1 { + err = errors.New("没能找到verifyCode,需要作者更新脚本。。。") + return + } + share.VerifyCode = matchVerifyCode[1] + var matchShareName []string + if matchShareName = _shareNameReg.FindStringSubmatch(string(body)); len(matchShareName) <= 1 { + return + } + share.Name = strings.Split(matchShareName[1], " ")[0] } - share.Name = strings.Split(matchShareName[1], " ")[0] return } @@ -88,6 +97,7 @@ func (d *dao) GetShareDirList(ctx context.Context, share *model.ShareInfo, pn, p log.Error("httpCli.Get(%s) 请求失败!error(%v)", _listShareDirAPI, err) return } + defer resp.Body.Close() var body []byte if body, err = ioutil.ReadAll(resp.Body); err != nil { log.Error("ioutil.ReadAll error(%v)", err) @@ -124,13 +134,56 @@ func (d *dao) GetShareDirAll(ctx context.Context, share *model.ShareInfo, fileID } } +func (d *dao) GetShareFileInfo(ctx context.Context, share *model.ShareInfo) (info *model.Dir, err error) { + var params = url.Values{} + params.Set("accessCode", share.AccessCode) + params.Set("shortCode", share.ShortCode) + params.Set("noCache", utils.GenNoCacheNum()) + var resp *http.Response + if resp, err = d.httpCli.Get(_getShareFileInfoAPI + params.Encode()); err != nil { + log.Error("httpCli.Get(%s) 请求失败!error(%v)", _getShareFileInfoAPI, err) + return + } + defer resp.Body.Close() + var body []byte + if body, err = ioutil.ReadAll(resp.Body); err != nil { + log.Error("ioutil.ReadAll error(%v)", err) + return + } + var res struct { + *model.Dir + ErrorVO *struct { + ErrorCode string `json:"errorCode"` + ErrorMsg string `json:"errorMsg"` + } `json:"errorVO"` + } + if err = json.Unmarshal(body, &res); err != nil { + log.Error("json.Unmarshal() error(%v)", err) + return + } + if res.ErrorVO != nil { + err = errors.New(res.ErrorVO.ErrorMsg) + return + } + if res.Dir == nil { + err = errors.New("请求失败!可能是访问码不正确。") + return + } + info = res.Dir + return +} + func (d *dao) GetDownloadURLFromShare(ctx context.Context, share *model.ShareInfo, fileId, subFileId string) (URL string, err error) { var params = url.Values{} params.Set("shortCode", share.ShortCode) - params.Set("fileId", fileId) - params.Set("subFileId", subFileId) params.Set("noCache", utils.GenNoCacheNum()) - params.Set("accessCode", share.AccessCode) + if !share.IsFile { + params.Set("fileId", fileId) + params.Set("subFileId", subFileId) + params.Set("accessCode", share.AccessCode) + } else { + params.Set("fileId", subFileId) + } var req *http.Request if req, err = http.NewRequest("GET", _getDownloadUrlAPI+params.Encode(), nil); err != nil { log.Error("http.NewRequest(GET %s) error(%v)", _getDownloadUrlAPI, err) diff --git a/model/share.go b/model/share.go index 406f3a9..29e680d 100644 --- a/model/share.go +++ b/model/share.go @@ -6,6 +6,7 @@ type ShareInfo struct { ShareID string VerifyCode string Name string + IsFile bool } func (share *ShareInfo) GetShortName() string {