diff --git a/internal/pcscommand/download.go b/internal/pcscommand/download.go index 47710f87..c4500ce0 100644 --- a/internal/pcscommand/download.go +++ b/internal/pcscommand/download.go @@ -1,11 +1,13 @@ package pcscommand import ( + "encoding/hex" "errors" "fmt" "github.com/iikira/BaiduPCS-Go/baidupcs" "github.com/iikira/BaiduPCS-Go/internal/pcsconfig" "github.com/iikira/BaiduPCS-Go/pcstable" + "github.com/iikira/BaiduPCS-Go/pcsutil/checksum" "github.com/iikira/BaiduPCS-Go/pcsutil/converter" "github.com/iikira/BaiduPCS-Go/pcsutil/waitgroup" "github.com/iikira/BaiduPCS-Go/requester" @@ -29,28 +31,38 @@ const ( StrDownloadInitError = "初始化下载发生错误" ) -// dtask 下载任务 -type dtask struct { - ListTask - path string // 下载的路径 - savePath string // 保存的路径 - downloadInfo *baidupcs.FileDirectory // 文件或目录详情 -} +var ( + // ErrNotSupportChecksum 文件不支持校验 + ErrNotSupportChecksum = errors.New("该文件不支持校验") + // ErrChecksumFailed 文件校验失败 + ErrChecksumFailed = errors.New("该文件校验失败, 文件md5值与服务器记录的不匹配") +) -//DownloadOptions 下载可选参数 -type DownloadOptions struct { - IsTest bool - IsPrintStatus bool - IsExecutedPermission bool - IsOverwrite bool - IsShareDownload bool - IsLocateDownload bool - IsStreaming bool - SaveTo string - Parallel int - Load int - Out io.Writer -} +type ( + // dtask 下载任务 + dtask struct { + ListTask + path string // 下载的路径 + savePath string // 保存的路径 + downloadInfo *baidupcs.FileDirectory // 文件或目录详情 + } + + //DownloadOptions 下载可选参数 + DownloadOptions struct { + IsTest bool + IsPrintStatus bool + IsExecutedPermission bool + IsOverwrite bool + IsShareDownload bool + IsLocateDownload bool + IsStreaming bool + SaveTo string + Parallel int + Load int + NoCheck bool + Out io.Writer + } +) func downloadPrintFormat(load int) string { if load <= 1 { @@ -184,6 +196,27 @@ func download(id int, downloadURL, savePath string, loadBalansers []string, clie return nil } +// checkFileValid 检测文件有效性 +func checkFileValid(filePath string, fileInfo *baidupcs.FileDirectory) error { + if len(fileInfo.BlockList) != 1 { + return ErrNotSupportChecksum + } + + f := checksum.NewLocalFileInfo(filePath, int(256*converter.KB)) + err := f.OpenPath() + if err != nil { + return err + } + + defer f.Close() + + f.Md5Sum() + if strings.Compare(hex.EncodeToString(f.MD5), fileInfo.MD5) != 0 { + return ErrChecksumFailed + } + return nil +} + // RunDownload 执行下载网盘内文件 func RunDownload(paths []string, options *DownloadOptions) { if options == nil { @@ -258,6 +291,8 @@ func RunDownload(paths []string, options *DownloadOptions) { // 不重试的情况 switch { + case err == ErrNotSupportChecksum: + fallthrough case strings.Compare(errManifest, "下载文件错误") == 0 && strings.Contains(err.Error(), StrDownloadInitError): fmt.Fprintf(options.Out, "[%d] %s, %s\n", task.ID, errManifest, err) return @@ -420,6 +455,18 @@ func RunDownload(paths []string, options *DownloadOptions) { return } + if !cfg.IsTest && !options.NoCheck { + if task.downloadInfo.Size >= 128*converter.MB { + fmt.Fprintf(options.Out, "[%d] 开始检验文件有效性, 稍后...\n", task.ID) + } + err = checkFileValid(task.savePath, task.downloadInfo) + if err != nil { + handleTaskErr(task, "检验文件有效性出错", err) + } else { + fmt.Fprintf(options.Out, "[%d] 检验文件有效性成功\n", task.ID) + } + } + atomic.AddInt64(&totalSize, task.downloadInfo.Size) }() } diff --git a/internal/pcscommand/share.go b/internal/pcscommand/share.go index 0be8b0a9..973fecaa 100644 --- a/internal/pcscommand/share.go +++ b/internal/pcscommand/share.go @@ -5,7 +5,6 @@ import ( "github.com/iikira/BaiduPCS-Go/baidupcs" "github.com/iikira/BaiduPCS-Go/internal/pcsconfig" "github.com/iikira/BaiduPCS-Go/pcstable" - "github.com/iikira/BaiduPCS-Go/requester" "github.com/iikira/baidu-tools/pan" "net/url" "os" @@ -125,8 +124,7 @@ func getShareDLink(pcspath string) (dlink string) { func getLink(shareID int64, shareLink, passwd, rootSharePath, filePath string) (dlink string) { sInfo := pan.NewSharedInfo(shareLink) - sInfo.Client = requester.NewHTTPClient() - sInfo.Client.SetHTTPSecure(pcsconfig.Config.EnableHTTPS()) + sInfo.Client = pcsconfig.Config.HTTPClient() if passwd != "" { err := sInfo.Auth(passwd) diff --git a/internal/pcscommand/upload.go b/internal/pcscommand/upload.go index bed4375c..a1a5fe9c 100644 --- a/internal/pcscommand/upload.go +++ b/internal/pcscommand/upload.go @@ -237,15 +237,15 @@ func RunUpload(localPaths []string, savePath string, opt *UploadOptions) { func() { fmt.Printf("[%d] 准备上传: %s\n", task.ID, task.uploadInfo.Path) - if !task.uploadInfo.OpenPath() { - fmt.Printf("[%d] 文件不可读, 跳过...\n", task.ID) + err = task.uploadInfo.OpenPath() + if err != nil { + fmt.Printf("[%d] 文件不可读, 错误信息: %s, 跳过...\n", task.ID, err) return } defer task.uploadInfo.Close() // 关闭文件 // 步骤控制 var ( - err error panDir, panFile = path.Split(task.savePath) ) diff --git a/main.go b/main.go index 15119448..f158c348 100644 --- a/main.go +++ b/main.go @@ -954,6 +954,7 @@ func main() { 通过 BaiduPCS-Go config set -savedir , 自定义保存的目录. 已支持目录下载. 已支持多个文件或目录下载. + 已支持下载完成后自动校验文件, 但并不是所有的文件都支持校验! 自动跳过下载重名的文件! 示例: @@ -1002,6 +1003,7 @@ func main() { IsStreaming: c.Bool("stream"), SaveTo: saveTo, Parallel: c.Int("p"), + NoCheck: c.Bool("nocheck"), Load: c.Int("l"), } @@ -1058,6 +1060,10 @@ func main() { Name: "l", Usage: "指定同时进行下载文件的数量", }, + cli.BoolFlag{ + Name: "nocheck", + Usage: "下载文件完成后不检测文件的有效性", + }, cli.BoolFlag{ Name: "bg", Usage: "加入后台下载", diff --git a/pcsutil/checksum/checksum.go b/pcsutil/checksum/checksum.go index b4d23ad7..e8d6b946 100644 --- a/pcsutil/checksum/checksum.go +++ b/pcsutil/checksum/checksum.go @@ -53,7 +53,7 @@ func NewLocalFileInfo(localPath string, bufSize int) *LocalFile { } // OpenPath 检查文件状态并获取文件的大小 (Length) -func (lf *LocalFile) OpenPath() bool { +func (lf *LocalFile) OpenPath() error { if lf.File != nil { lf.File.Close() } @@ -61,13 +61,17 @@ func (lf *LocalFile) OpenPath() bool { var err error lf.File, err = os.Open(lf.Path) if err != nil { - return false + return err + } + + info, err := lf.File.Stat() + if err != nil { + return err } - info, _ := lf.File.Stat() lf.Length = info.Size() lf.ModTime = info.ModTime().Unix() - return true + return nil } // Close 关闭文件