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  }