github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/internal/pcscommand/download.go (about) 1 package pcscommand 2 3 import ( 4 "fmt" 5 "github.com/fzfile/BaiduPCS-Go/baidupcs" 6 "github.com/fzfile/BaiduPCS-Go/baidupcs/pcserror" 7 "github.com/fzfile/BaiduPCS-Go/internal/pcsconfig" 8 "github.com/fzfile/BaiduPCS-Go/internal/pcsfunctions/pcsdownload" 9 "github.com/fzfile/BaiduPCS-Go/pcstable" 10 "github.com/fzfile/BaiduPCS-Go/pcsutil/converter" 11 "github.com/fzfile/BaiduPCS-Go/pcsutil/taskframework" 12 "github.com/fzfile/BaiduPCS-Go/requester/downloader" 13 "github.com/fzfile/BaiduPCS-Go/requester/transfer" 14 "os" 15 "path/filepath" 16 "runtime" 17 ) 18 19 type ( 20 //DownloadOptions 下载可选参数 21 DownloadOptions struct { 22 IsTest bool 23 IsPrintStatus bool 24 IsExecutedPermission bool 25 IsOverwrite bool 26 DownloadMode pcsdownload.DownloadMode 27 SaveTo string 28 Parallel int 29 Load int 30 MaxRetry int 31 NoCheck bool 32 } 33 34 // LocateDownloadOption 获取下载链接可选参数 35 LocateDownloadOption struct { 36 FromPan bool 37 } 38 ) 39 40 func downloadPrintFormat(load int) string { 41 if load <= 1 { 42 return pcsdownload.DefaultPrintFormat 43 } 44 return "[%d] ↓ %s/%s %s/s in %s, left %s ...\n" 45 } 46 47 // RunDownload 执行下载网盘内文件 48 func RunDownload(paths []string, options *DownloadOptions) { 49 if options == nil { 50 options = &DownloadOptions{} 51 } 52 53 if options.Load <= 0 { 54 options.Load = pcsconfig.Config.MaxDownloadLoad 55 } 56 57 if options.MaxRetry < 0 { 58 options.MaxRetry = pcsdownload.DefaultDownloadMaxRetry 59 } 60 61 if runtime.GOOS == "windows" { 62 // windows下不加执行权限 63 options.IsExecutedPermission = false 64 } 65 66 // 设置下载配置 67 cfg := &downloader.Config{ 68 Mode: transfer.RangeGenMode_BlockSize, 69 CacheSize: pcsconfig.Config.CacheSize, 70 BlockSize: baidupcs.MaxDownloadRangeSize, 71 MaxRate: pcsconfig.Config.MaxDownloadRate, 72 InstanceStateStorageFormat: downloader.InstanceStateStorageFormatProto3, 73 IsTest: options.IsTest, 74 TryHTTP: !pcsconfig.Config.EnableHTTPS, 75 } 76 77 // 设置下载最大并发量 78 if options.Parallel < 1 { 79 options.Parallel = pcsconfig.Config.MaxParallel 80 } 81 82 paths, err := matchPathByShellPattern(paths...) 83 if err != nil { 84 fmt.Println(err) 85 return 86 } 87 88 fmt.Print("\n") 89 fmt.Printf("[0] 提示: 当前下载最大并发量为: %d, 下载缓存为: %d\n", options.Parallel, cfg.CacheSize) 90 91 var ( 92 pcs = GetBaiduPCS() 93 loadCount = 0 94 ) 95 96 // 预测要下载的文件数量 97 // TODO: pcscache 98 for k := range paths { 99 pcs.FilesDirectoriesRecurseList(paths[k], baidupcs.DefaultOrderOptions, func(depth int, _ string, fd *baidupcs.FileDirectory, pcsError pcserror.Error) bool { 100 if pcsError != nil { 101 pcsCommandVerbose.Warnf("%s\n", pcsError) 102 return true 103 } 104 105 // 忽略统计文件夹数量 106 if !fd.Isdir { 107 loadCount++ 108 if loadCount >= options.Load { 109 return false 110 } 111 } 112 return true 113 }) 114 115 if loadCount >= options.Load { 116 break 117 } 118 } 119 120 // 修改Load, 设置MaxParallel 121 if loadCount > 0 { 122 options.Load = loadCount 123 // 取平均值 124 cfg.MaxParallel = pcsconfig.AverageParallel(options.Parallel, loadCount) 125 } else { 126 cfg.MaxParallel = options.Parallel 127 } 128 129 var ( 130 executor = taskframework.TaskExecutor{ 131 IsFailedDeque: true, // 统计失败的列表 132 } 133 statistic = &pcsdownload.DownloadStatistic{} 134 ) 135 // 处理队列 136 for k := range paths { 137 newCfg := *cfg 138 unit := pcsdownload.DownloadTaskUnit{ 139 Cfg: &newCfg, // 复制一份新的cfg 140 PCS: pcs, 141 VerbosePrinter: pcsCommandVerbose, 142 PrintFormat: downloadPrintFormat(options.Load), 143 ParentTaskExecutor: &executor, 144 DownloadStatistic: statistic, 145 IsPrintStatus: options.IsPrintStatus, 146 IsExecutedPermission: options.IsExecutedPermission, 147 IsOverwrite: options.IsOverwrite, 148 NoCheck: options.NoCheck, 149 DownloadMode: options.DownloadMode, 150 PcsPath: paths[k], 151 } 152 153 // 设置储存的路径 154 if options.SaveTo != "" { 155 unit.SavePath = filepath.Join(options.SaveTo, filepath.Base(paths[k])) 156 } else { 157 // 使用默认的保存路径 158 unit.SavePath = GetActiveUser().GetSavePath(paths[k]) 159 } 160 info := executor.Append(&unit, options.MaxRetry) 161 fmt.Printf("[%s] 加入下载队列: %s\n", info.Id(), paths[k]) 162 } 163 164 // 开始计时 165 statistic.StartTimer() 166 167 // 开始执行 168 executor.Execute() 169 170 fmt.Printf("\n下载结束, 时间: %s, 数据总量: %s\n", statistic.Elapsed()/1e6*1e6, converter.ConvertFileSize(statistic.TotalSize())) 171 172 // 输出失败的文件列表 173 failedList := executor.FailedDeque() 174 if failedList.Size() != 0 { 175 fmt.Printf("以下文件下载失败: \n") 176 tb := pcstable.NewTable(os.Stdout) 177 for e := failedList.Shift(); e != nil; e = failedList.Shift() { 178 item := e.(*taskframework.TaskInfoItem) 179 tb.Append([]string{item.Info.Id(), item.Unit.(*pcsdownload.DownloadTaskUnit).PcsPath}) 180 } 181 tb.Render() 182 } 183 }