github.com/qjfoidnh/BaiduPCS-Go@v0.0.0-20231011165705-caa18a3765f3/main.go (about) 1 package main 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "os" 7 "os/exec" 8 "path" 9 "path/filepath" 10 "runtime" 11 "sort" 12 "strconv" 13 "strings" 14 "unicode" 15 16 "github.com/olekukonko/tablewriter" 17 "github.com/peterh/liner" 18 "github.com/qjfoidnh/BaiduPCS-Go/baidupcs" 19 "github.com/qjfoidnh/BaiduPCS-Go/internal/pcscommand" 20 "github.com/qjfoidnh/BaiduPCS-Go/internal/pcsconfig" 21 "github.com/qjfoidnh/BaiduPCS-Go/internal/pcsfunctions/pcsdownload" 22 _ "github.com/qjfoidnh/BaiduPCS-Go/internal/pcsinit" 23 "github.com/qjfoidnh/BaiduPCS-Go/internal/pcsupdate" 24 "github.com/qjfoidnh/BaiduPCS-Go/pcsliner" 25 "github.com/qjfoidnh/BaiduPCS-Go/pcsliner/args" 26 "github.com/qjfoidnh/BaiduPCS-Go/pcstable" 27 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil" 28 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/checksum" 29 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/converter" 30 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/escaper" 31 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/getip" 32 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/pcstime" 33 "github.com/qjfoidnh/BaiduPCS-Go/pcsverbose" 34 "github.com/urfave/cli" 35 ) 36 37 const ( 38 // NameShortDisplayNum 文件名缩略显示长度 39 NameShortDisplayNum = 16 40 41 cryptoDescription = ` 42 可用的方法 <method>: 43 aes-128-ctr, aes-192-ctr, aes-256-ctr, 44 aes-128-cfb, aes-192-cfb, aes-256-cfb, 45 aes-128-ofb, aes-192-ofb, aes-256-ofb. 46 47 密钥 <key>: 48 aes-128 对应key长度为16, aes-192 对应key长度为24, aes-256 对应key长度为32, 49 如果key长度不符合, 则自动修剪key, 舍弃超出长度的部分, 长度不足的部分用'\0'填充. 50 51 GZIP <disable-gzip>: 52 在文件加密之前, 启用GZIP压缩文件; 文件解密之后启用GZIP解压缩文件, 默认启用, 53 如果不启用, 则无法检测文件是否解密成功, 解密文件时会保留源文件, 避免解密失败造成文件数据丢失.` 54 ) 55 56 var ( 57 // Version 版本号 58 //Version = "v3.9.4-devel" 59 Version = "v3.9.5-devel" 60 61 historyFilePath = filepath.Join(pcsconfig.GetConfigDir(), "pcs_command_history.txt") 62 reloadFn = func(c *cli.Context) error { 63 err := pcsconfig.Config.Reload() 64 if err != nil { 65 fmt.Printf("重载配置错误: %s\n", err) 66 } 67 return nil 68 } 69 saveFunc = func(c *cli.Context) error { 70 err := pcsconfig.Config.Save() 71 if err != nil { 72 fmt.Printf("保存配置错误: %s\n", err) 73 } 74 return nil 75 } 76 77 isCli bool 78 ) 79 80 func init() { 81 pcsutil.ChWorkDir() 82 83 err := pcsconfig.Config.Init() 84 switch err { 85 case nil: 86 case pcsconfig.ErrConfigFileNoPermission, pcsconfig.ErrConfigContentsParseError: 87 fmt.Fprintf(os.Stderr, "FATAL ERROR: config file error: %s\n", err) 88 os.Exit(1) 89 default: 90 fmt.Printf("WARNING: config init error: %s\n", err) 91 } 92 } 93 94 func main() { 95 defer pcsconfig.Config.Close() 96 97 app := cli.NewApp() 98 app.Name = "BaiduPCS-Go" 99 app.Version = Version 100 app.Author = "qjfoidnh/BaiduPCS-Go: https://github.com/qjfoidnh/BaiduPCS-Go" 101 app.Copyright = "(c) 2016-2020 iikira." 102 app.Usage = "百度网盘客户端 for " + runtime.GOOS + "/" + runtime.GOARCH 103 app.Description = `BaiduPCS-Go 使用Go语言编写的百度网盘命令行客户端, 为操作百度网盘, 提供实用功能. 104 具体功能, 参见 COMMANDS 列表 105 106 特色: 107 网盘内列出文件和目录, 支持通配符匹配路径; 108 下载网盘内文件, 支持网盘内目录 (文件夹) 下载, 支持多个文件或目录下载, 支持断点续传和高并发高速下载. 109 110 --------------------------------------------------- 111 前往 https://github.com/qjfoidnh/BaiduPCS-Go 以获取更多帮助信息! 112 前往 https://github.com/qjfoidnh/BaiduPCS-Go/releases 以获取程序更新信息! 113 --------------------------------------------------- 114 115 交流反馈: 116 提交Issue: https://github.com/qjfoidnh/BaiduPCS-Go/issues 117 邮箱: qjfoidnh@126.com` 118 119 app.Flags = []cli.Flag{ 120 cli.BoolFlag{ 121 Name: "verbose", 122 Usage: "启用调试", 123 EnvVar: pcsverbose.EnvVerbose, 124 Destination: &pcsverbose.IsVerbose, 125 }, 126 } 127 app.Action = func(c *cli.Context) { 128 if c.NArg() != 0 { 129 fmt.Printf("未找到命令: %s\n运行命令 %s help 获取帮助\n", c.Args().Get(0), app.Name) 130 return 131 } 132 133 isCli = true 134 pcsverbose.Verbosef("VERBOSE: 这是一条调试信息\n\n") 135 136 var ( 137 line = pcsliner.NewLiner() 138 err error 139 ) 140 141 line.History, err = pcsliner.NewLineHistory(historyFilePath) 142 if err != nil { 143 fmt.Printf("警告: 读取历史命令文件错误, %s\n", err) 144 } 145 146 line.ReadHistory() 147 defer func() { 148 line.DoWriteHistory() 149 line.Close() 150 }() 151 152 // tab 自动补全命令 153 line.State.SetCompleter(func(line string) (s []string) { 154 var ( 155 lineArgs = args.Parse(line) 156 numArgs = len(lineArgs) 157 acceptCompleteFileCommands = []string{ 158 "cd", "cp", "download", "export", "fixmd5", "locate", "ls", "meta", "mkdir", "mv", "rapidupload", "rm", "setastoken", "share", "transfer", "tree", "upload", 159 } 160 closed = strings.LastIndex(line, " ") == len(line)-1 161 ) 162 163 for _, cmd := range app.Commands { 164 for _, name := range cmd.Names() { 165 if !strings.HasPrefix(name, line) { 166 continue 167 } 168 169 s = append(s, name+" ") 170 } 171 } 172 173 switch numArgs { 174 case 0: 175 return 176 case 1: 177 if !closed { 178 return 179 } 180 } 181 182 thisCmd := app.Command(lineArgs[0]) 183 if thisCmd == nil { 184 return 185 } 186 187 if !pcsutil.ContainsString(acceptCompleteFileCommands, thisCmd.FullName()) { 188 return 189 } 190 191 var ( 192 activeUser = pcsconfig.Config.ActiveUser() 193 pcs = pcsconfig.Config.ActiveUserBaiduPCS() 194 runeFunc = unicode.IsSpace 195 pcsRuneFunc = func(r rune) bool { 196 switch r { 197 case '\'', '"': 198 return true 199 } 200 return unicode.IsSpace(r) 201 } 202 targetPath string 203 ) 204 205 if !closed { 206 targetPath = lineArgs[numArgs-1] 207 escaper.EscapeStringsByRuneFunc(lineArgs[:numArgs-1], runeFunc) // 转义 208 } else { 209 escaper.EscapeStringsByRuneFunc(lineArgs, runeFunc) 210 } 211 212 switch { 213 case targetPath == "." || strings.HasSuffix(targetPath, "/."): 214 s = append(s, line+"/") 215 return 216 case targetPath == ".." || strings.HasSuffix(targetPath, "/.."): 217 s = append(s, line+"/") 218 return 219 } 220 221 var ( 222 targetDir string 223 isAbs = path.IsAbs(targetPath) 224 isDir = strings.LastIndex(targetPath, "/") == len(targetPath)-1 225 ) 226 227 if isAbs { 228 targetDir = path.Dir(targetPath) 229 } else { 230 targetDir = path.Join(activeUser.Workdir, targetPath) 231 if !isDir { 232 targetDir = path.Dir(targetDir) 233 } 234 } 235 files, err := pcs.CacheFilesDirectoriesList(targetDir, baidupcs.DefaultOrderOptions) 236 if err != nil { 237 return 238 } 239 240 // fmt.Println("-", targetDir, targetPath, "-") 241 242 for _, file := range files { 243 if file == nil { 244 continue 245 } 246 247 var ( 248 appendLine string 249 ) 250 251 // 已经有的情况 252 if !closed { 253 if !strings.HasPrefix(file.Path, path.Clean(path.Join(targetDir, path.Base(targetPath)))) { 254 if path.Base(targetDir) == path.Base(targetPath) { 255 appendLine = strings.Join(append(lineArgs[:numArgs-1], escaper.EscapeByRuneFunc(path.Join(targetPath, file.Filename), pcsRuneFunc)), " ") 256 goto handle 257 } 258 // fmt.Println(file.Path, targetDir, targetPath) 259 continue 260 } 261 // fmt.Println(path.Clean(path.Join(path.Dir(targetPath), file.Filename)), targetPath, file.Filename) 262 appendLine = strings.Join(append(lineArgs[:numArgs-1], escaper.EscapeByRuneFunc(path.Clean(path.Join(path.Dir(targetPath), file.Filename)), pcsRuneFunc)), " ") 263 goto handle 264 } 265 // 没有的情况 266 appendLine = strings.Join(append(lineArgs, escaper.EscapeByRuneFunc(file.Filename, pcsRuneFunc)), " ") 267 goto handle 268 269 handle: 270 if file.Isdir { 271 s = append(s, appendLine+"/") 272 continue 273 } 274 s = append(s, appendLine+" ") 275 continue 276 } 277 278 return 279 }) 280 281 fmt.Printf("提示: 方向键上下可切换历史命令.\n") 282 fmt.Printf("提示: Ctrl + A / E 跳转命令 首 / 尾.\n") 283 fmt.Printf("提示: 输入 help 获取帮助.\n") 284 285 for { 286 var ( 287 prompt string 288 activeUser = pcsconfig.Config.ActiveUser() 289 ) 290 291 if activeUser.Name != "" { 292 // 格式: BaiduPCS-Go:<工作目录> <百度ID>$ 293 // 工作目录太长时, 会自动缩略 294 prompt = app.Name + ":" + converter.ShortDisplay(path.Base(activeUser.Workdir), NameShortDisplayNum) + " " + activeUser.Name + "$ " 295 } else { 296 // BaiduPCS-Go > 297 prompt = app.Name + " > " 298 } 299 300 commandLine, err := line.State.Prompt(prompt) 301 switch err { 302 case liner.ErrPromptAborted: 303 return 304 case nil: 305 // continue 306 default: 307 fmt.Println(err) 308 return 309 } 310 311 line.State.AppendHistory(commandLine) 312 313 cmdArgs := args.Parse(commandLine) 314 if len(cmdArgs) == 0 { 315 continue 316 } 317 318 s := []string{os.Args[0]} 319 s = append(s, cmdArgs...) 320 321 // 恢复原始终端状态 322 // 防止运行命令时程序被结束, 终端出现异常 323 line.Pause() 324 c.App.Run(s) 325 line.Resume() 326 } 327 } 328 329 app.Commands = []cli.Command{ 330 { 331 Name: "run", 332 Usage: "执行系统命令", 333 Category: "其他", 334 Action: func(c *cli.Context) error { 335 if c.NArg() == 0 { 336 cli.ShowCommandHelp(c, c.Command.Name) 337 return nil 338 } 339 340 cmd := exec.Command(c.Args().First(), c.Args().Tail()...) 341 cmd.Stdout = os.Stdout 342 cmd.Stdin = os.Stdin 343 cmd.Stderr = os.Stderr 344 345 err := cmd.Run() 346 if err != nil { 347 fmt.Println(err) 348 } 349 350 return nil 351 }, 352 }, 353 { 354 Name: "env", 355 Usage: "显示程序环境变量", 356 Description: ` 357 BAIDUPCS_GO_CONFIG_DIR: 配置文件路径, 358 BAIDUPCS_GO_VERBOSE: 是否启用调试. 359 `, 360 Category: "其他", 361 Action: func(c *cli.Context) error { 362 envStr := "%s=\"%s\"\n" 363 envVar, ok := os.LookupEnv(pcsverbose.EnvVerbose) 364 if ok { 365 fmt.Printf(envStr, pcsverbose.EnvVerbose, envVar) 366 } else { 367 fmt.Printf(envStr, pcsverbose.EnvVerbose, "0") 368 } 369 370 envVar, ok = os.LookupEnv(pcsconfig.EnvConfigDir) 371 if ok { 372 fmt.Printf(envStr, pcsconfig.EnvConfigDir, envVar) 373 } else { 374 fmt.Printf(envStr, pcsconfig.EnvConfigDir, pcsconfig.GetConfigDir()) 375 } 376 377 return nil 378 }, 379 }, 380 { 381 Name: "update", 382 Usage: "检测程序更新", 383 Category: "其他", 384 Action: func(c *cli.Context) error { 385 if c.IsSet("y") { 386 if !c.Bool("y") { 387 return nil 388 } 389 } 390 pcsupdate.CheckUpdate(app.Version, c.Bool("y")) 391 return nil 392 }, 393 Flags: []cli.Flag{ 394 cli.BoolFlag{ 395 Name: "y", 396 Usage: "确认更新", 397 }, 398 }, 399 }, 400 { 401 Name: "login", 402 Usage: "登录百度账号", 403 Description: ` 404 示例: 405 BaiduPCS-Go login 406 BaiduPCS-Go login -username=liuhua 407 BaiduPCS-Go login -bduss=123456789 -stoken=atahsrweoog 408 BaiduPCS-Go login -cookies="BDUSS=xxxxx; BAIDUID=yyyyyy; STOKEN=zzzzz; ...." 409 410 常规登录: 411 按提示一步一步来即可. 412 413 百度BDUSS获取方法: 414 百度搜索: 获取百度BDUSS 415 416 百度Cookies获取办法: 417 以Chrome为例,登录到自己的百度网盘主页,F12,然后切换到Network标签,刷新页面,Network标签下会刷出一大堆东西 418 找到第一条,点击,看到右侧出现的详情,往下翻到Cookies: xxxx; xxxxx; xxx...这样的字段,从冒号后(没有空格)一直复制到字段末尾`, 419 Category: "百度帐号", 420 Before: reloadFn, 421 After: saveFunc, 422 Action: func(c *cli.Context) error { 423 var bduss, ptoken, stoken, cookies string 424 if c.IsSet("cookies") { 425 cookies = c.String("cookies") 426 } else if c.IsSet("bduss") { 427 bduss = c.String("bduss") 428 ptoken = c.String("ptoken") 429 stoken = c.String("stoken") 430 } else if c.NArg() == 0 { 431 var err error 432 bduss, ptoken, stoken, cookies, err = pcscommand.RunLogin(c.String("username"), c.String("password")) 433 if err != nil { 434 fmt.Println(err) 435 return err 436 } 437 } else { 438 cli.ShowCommandHelp(c, c.Command.Name) 439 return nil 440 } 441 442 baidu, err := pcsconfig.Config.SetupUserByBDUSS(bduss, ptoken, stoken, cookies) 443 if err != nil { 444 fmt.Println(err) 445 return nil 446 } 447 448 fmt.Println("百度帐号登录成功:", baidu.Name) 449 return nil 450 }, 451 Flags: []cli.Flag{ 452 cli.StringFlag{ 453 Name: "username", 454 Usage: "登录百度帐号的用户名(手机号/邮箱/用户名)", 455 }, 456 cli.StringFlag{ 457 Name: "password", 458 Usage: "登录百度帐号的用户名的密码", 459 }, 460 cli.StringFlag{ 461 Name: "bduss", 462 Usage: "使用百度 BDUSS 来登录百度帐号", 463 }, 464 cli.StringFlag{ 465 Name: "ptoken", 466 Usage: "百度 PTOKEN, 配合 -bduss 参数使用 (可选)", 467 }, 468 cli.StringFlag{ 469 Name: "stoken", 470 Usage: "百度 STOKEN, 配合 -bduss 参数使用 (可选, 欲使用转存功能则必选)", 471 }, 472 cli.StringFlag{ 473 Name: "cookies", 474 Usage: "使用百度 Cookies 来登录百度账号", 475 }, 476 }, 477 }, 478 { 479 Name: "su", 480 Usage: "切换百度帐号", 481 Description: ` 482 切换已登录的百度帐号: 483 如果运行该条命令没有提供参数, 程序将会列出所有的百度帐号, 供选择切换. 484 485 示例: 486 BaiduPCS-Go su 487 BaiduPCS-Go su <uid or name> 488 `, 489 Category: "百度帐号", 490 Before: reloadFn, 491 After: saveFunc, 492 Action: func(c *cli.Context) error { 493 if c.NArg() >= 2 { 494 cli.ShowCommandHelp(c, c.Command.Name) 495 return nil 496 } 497 498 numLogins := pcsconfig.Config.NumLogins() 499 500 if numLogins == 0 { 501 fmt.Printf("未设置任何百度帐号, 不能切换\n") 502 return nil 503 } 504 505 var ( 506 inputData = c.Args().Get(0) 507 uid uint64 508 ) 509 510 if c.NArg() == 1 { 511 // 直接切换 512 uid, _ = strconv.ParseUint(inputData, 10, 64) 513 } else if c.NArg() == 0 { 514 // 输出所有帐号供选择切换 515 cli.HandleAction(app.Command("loglist").Action, c) 516 517 // 提示输入 index 518 var index string 519 fmt.Printf("输入要切换帐号的 # 值 > ") 520 _, err := fmt.Scanln(&index) 521 if err != nil { 522 return nil 523 } 524 525 if n, err := strconv.Atoi(index); err == nil && n >= 0 && n < numLogins { 526 uid = pcsconfig.Config.BaiduUserList[n].UID 527 } else { 528 fmt.Printf("切换用户失败, 请检查 # 值是否正确\n") 529 return nil 530 } 531 } else { 532 cli.ShowCommandHelp(c, c.Command.Name) 533 } 534 535 switchedUser, err := pcsconfig.Config.SwitchUser(&pcsconfig.BaiduBase{ 536 Name: inputData, 537 }) 538 if err != nil { 539 switchedUser, err = pcsconfig.Config.SwitchUser(&pcsconfig.BaiduBase{ 540 UID: uid, 541 }) 542 if err != nil { 543 fmt.Printf("切换用户失败, %s\n", err) 544 return nil 545 } 546 } 547 548 fmt.Printf("切换用户: %s\n", switchedUser.Name) 549 return nil 550 }, 551 }, 552 { 553 Name: "logout", 554 Usage: "退出百度帐号", 555 Description: "退出当前登录的百度帐号", 556 Category: "百度帐号", 557 Before: reloadFn, 558 After: saveFunc, 559 Action: func(c *cli.Context) error { 560 if pcsconfig.Config.NumLogins() == 0 { 561 fmt.Println("未设置任何百度帐号, 不能退出") 562 return nil 563 } 564 565 var ( 566 confirm string 567 activeUser = pcsconfig.Config.ActiveUser() 568 ) 569 570 if !c.Bool("y") { 571 fmt.Printf("确认退出百度帐号: %s ? (y/n) > ", activeUser.Name) 572 _, err := fmt.Scanln(&confirm) 573 if err != nil || (confirm != "y" && confirm != "Y") { 574 return err 575 } 576 } 577 578 deletedUser, err := pcsconfig.Config.DeleteUser(&pcsconfig.BaiduBase{ 579 UID: activeUser.UID, 580 }) 581 if err != nil { 582 fmt.Printf("退出用户 %s, 失败, 错误: %s\n", activeUser.Name, err) 583 } 584 585 fmt.Printf("退出用户成功, %s\n", deletedUser.Name) 586 return nil 587 }, 588 Flags: []cli.Flag{ 589 cli.BoolFlag{ 590 Name: "y", 591 Usage: "确认退出帐号", 592 }, 593 }, 594 }, 595 { 596 Name: "loglist", 597 Usage: "列出帐号列表", 598 Description: "列出所有已登录的百度帐号", 599 Category: "百度帐号", 600 Before: reloadFn, 601 Action: func(c *cli.Context) error { 602 fmt.Println(pcsconfig.Config.BaiduUserList.String()) 603 return nil 604 }, 605 }, 606 { 607 Name: "setastoken", 608 Usage: "设定当前账号的accessToken", 609 Description: ` 610 设定当前登录帐号的accessToken: 611 若不使用秒传链接转存, 可不设定; accessToken申请及获取教程: 612 https://github.com/qjfoidnh/BaiduPCS-Go/wiki/accessToken%E8%8E%B7%E5%8F%96%E6%95%99%E7%A8%8B 613 注意accessToken的有效期为一个月, 过期后请按教程指导更新token 614 615 示例: 616 BaiduPCS-Go setastoken 156.182v9052tgf1006c89891bsfb2401974.YmKOAwBD9yGaG2s4p5NNkX4CXeIbJxx4hAxotfS.PyuHEs 617 `, 618 Category: "百度帐号", 619 Before: reloadFn, 620 After: saveFunc, 621 Action: func(c *cli.Context) error { 622 activeUser := pcsconfig.Config.ActiveUser() 623 if activeUser.UID == 0 { 624 fmt.Println("请先登录") 625 return nil 626 } 627 if c.NArg() >= 2 { 628 cli.ShowCommandHelp(c, c.Command.Name) 629 return nil 630 } else if c.NArg() == 0 { 631 cli.ShowCommandHelp(c, c.Command.Name) 632 return nil 633 } 634 activeUser.AccessToken = c.Args().Get(0) 635 pcsconfig.Config.ActiveUserBaiduPCS().SetaccessToken(c.Args().Get(0)) 636 fmt.Printf("当前用户名: %s 成功设置accessToken: %s\n", activeUser.Name, activeUser.AccessToken) 637 return nil 638 }, 639 }, 640 { 641 Name: "who", 642 Usage: "获取当前帐号", 643 Description: "获取当前帐号的信息", 644 Category: "百度帐号", 645 Before: reloadFn, 646 Action: func(c *cli.Context) error { 647 activeUser := pcsconfig.Config.ActiveUser() 648 fmt.Printf("当前帐号 uid: %d, 用户名: %s, 性别: %s, 年龄: %.1f\n", activeUser.UID, activeUser.Name, activeUser.Sex, activeUser.Age) 649 return nil 650 }, 651 }, 652 { 653 Name: "quota", 654 Usage: "获取网盘配额", 655 Description: "获取网盘的总储存空间, 和已使用的储存空间", 656 Category: "百度网盘", 657 Before: reloadFn, 658 Action: func(c *cli.Context) error { 659 pcscommand.RunGetQuota() 660 return nil 661 }, 662 }, 663 { 664 Name: "cd", 665 Category: "百度网盘", 666 Usage: "切换工作目录", 667 Description: ` 668 BaiduPCS-Go cd <目录, 绝对路径或相对路径> 669 670 示例: 671 672 切换 /我的资源 工作目录: 673 BaiduPCS-Go cd /我的资源 674 675 切换上级目录: 676 BaiduPCS-Go cd .. 677 678 切换根目录: 679 BaiduPCS-Go cd / 680 681 切换 /我的资源 工作目录, 并自动列出 /我的资源 下的文件和目录 682 BaiduPCS-Go cd -l 我的资源 683 684 使用通配符: 685 BaiduPCS-Go cd /我的* 686 `, 687 Before: reloadFn, 688 After: saveFunc, 689 Action: func(c *cli.Context) error { 690 if c.NArg() == 0 { 691 cli.ShowCommandHelp(c, c.Command.Name) 692 return nil 693 } 694 695 pcscommand.RunChangeDirectory(c.Args().Get(0), c.Bool("l")) 696 697 return nil 698 }, 699 Flags: []cli.Flag{ 700 cli.BoolFlag{ 701 Name: "l", 702 Usage: "切换工作目录后自动列出工作目录下的文件和目录", 703 }, 704 }, 705 }, 706 { 707 Name: "ls", 708 Aliases: []string{"l", "ll"}, 709 Usage: "列出目录", 710 UsageText: app.Name + " ls <目录>", 711 Description: ` 712 列出当前工作目录内的文件和目录, 或指定目录内的文件和目录 713 714 示例: 715 716 列出 我的资源 内的文件和目录 717 BaiduPCS-Go ls 我的资源 718 719 绝对路径 720 BaiduPCS-Go ls /我的资源 721 722 降序排序 723 BaiduPCS-Go ls -desc 我的资源 724 725 按文件大小降序排序 726 BaiduPCS-Go ls -size -desc 我的资源 727 728 使用通配符 729 BaiduPCS-Go ls /我的* 730 `, 731 Category: "百度网盘", 732 Before: reloadFn, 733 Action: func(c *cli.Context) error { 734 orderOptions := &baidupcs.OrderOptions{} 735 switch { 736 case c.IsSet("asc"): 737 orderOptions.Order = baidupcs.OrderAsc 738 case c.IsSet("desc"): 739 orderOptions.Order = baidupcs.OrderDesc 740 default: 741 orderOptions.Order = baidupcs.OrderAsc 742 } 743 744 switch { 745 case c.IsSet("time"): 746 orderOptions.By = baidupcs.OrderByTime 747 case c.IsSet("name"): 748 orderOptions.By = baidupcs.OrderByName 749 case c.IsSet("size"): 750 orderOptions.By = baidupcs.OrderBySize 751 default: 752 orderOptions.By = baidupcs.OrderByName 753 } 754 755 pcscommand.RunLs(c.Args().Get(0), &pcscommand.LsOptions{ 756 Total: c.Bool("l") || c.Parent().Args().Get(0) == "ll", 757 }, orderOptions) 758 759 return nil 760 }, 761 Flags: []cli.Flag{ 762 cli.BoolFlag{ 763 Name: "l", 764 Usage: "详细显示", 765 }, 766 cli.BoolFlag{ 767 Name: "asc", 768 Usage: "升序排序", 769 }, 770 cli.BoolFlag{ 771 Name: "desc", 772 Usage: "降序排序", 773 }, 774 cli.BoolFlag{ 775 Name: "time", 776 Usage: "根据时间排序", 777 }, 778 cli.BoolFlag{ 779 Name: "name", 780 Usage: "根据文件名排序", 781 }, 782 cli.BoolFlag{ 783 Name: "size", 784 Usage: "根据大小排序", 785 }, 786 }, 787 }, 788 { 789 Name: "search", 790 Aliases: []string{"s"}, 791 Usage: "搜索文件", 792 UsageText: app.Name + " search [-path=<需要检索的目录>] [-r] 关键字", 793 Description: ` 794 按文件名搜索文件(不支持查找目录)。 795 默认在当前工作目录搜索. 796 797 示例: 798 799 搜索根目录的文件 800 BaiduPCS-Go search -path=/ 关键字 801 802 搜索当前工作目录的文件 803 BaiduPCS-Go search 关键字 804 805 递归搜索当前工作目录的文件 806 BaiduPCS-Go search -r 关键字 807 `, 808 Category: "百度网盘", 809 Before: reloadFn, 810 Action: func(c *cli.Context) error { 811 if c.NArg() < 1 { 812 cli.ShowCommandHelp(c, c.Command.Name) 813 return nil 814 } 815 816 pcscommand.RunSearch(c.String("path"), c.Args().Get(0), &pcscommand.SearchOptions{ 817 Total: c.Bool("l"), 818 Recurse: c.Bool("r"), 819 }) 820 821 return nil 822 }, 823 Flags: []cli.Flag{ 824 cli.BoolFlag{ 825 Name: "l", 826 Usage: "详细显示", 827 }, 828 cli.BoolFlag{ 829 Name: "r", 830 Usage: "递归搜索", 831 }, 832 cli.StringFlag{ 833 Name: "path", 834 Usage: "需要检索的目录", 835 Value: ".", 836 }, 837 }, 838 }, 839 { 840 Name: "tree", 841 Aliases: []string{"t"}, 842 Usage: "列出目录的树形图", 843 UsageText: app.Name + " tree <目录>", 844 Description: ` 845 列出目录树形图。 846 默认从当前工作目录开始列出. 847 848 示例: 849 850 从根目录开始列出 851 BaiduPCS-Go tree / 852 853 只列出两层深度 854 BaiduPCS-Go tree --depth 2 855 856 同时显示文件名和fsid 857 BaiduPCS-Go tree --fsid 858 `, 859 Category: "百度网盘", 860 Before: reloadFn, 861 Action: func(c *cli.Context) error { 862 pcscommand.RunTree(c.Args().Get(0), 0, &pcscommand.TreeOptions{ 863 Depth: c.Int("depth"), 864 ShowFsid: c.Bool("fsid"), 865 }) 866 return nil 867 }, 868 Flags: []cli.Flag{ 869 cli.IntFlag{ 870 Name: "depth", 871 Usage: "显示深度", 872 Value: -1, 873 }, 874 cli.BoolFlag{ 875 Name: "fsid", 876 Usage: "带fsid显示", 877 }, 878 }, 879 }, 880 { 881 Name: "pwd", 882 Usage: "输出工作目录", 883 UsageText: app.Name + " pwd", 884 Category: "百度网盘", 885 Before: reloadFn, 886 Action: func(c *cli.Context) error { 887 fmt.Println(pcsconfig.Config.ActiveUser().Workdir) 888 return nil 889 }, 890 }, 891 { 892 Name: "meta", 893 Usage: "获取文件/目录的元信息", 894 UsageText: app.Name + " meta <文件/目录1> <文件/目录2> <文件/目录3> ...", 895 Description: "默认获取工作目录元信息", 896 Category: "百度网盘", 897 Before: reloadFn, 898 Action: func(c *cli.Context) error { 899 var ( 900 ca = c.Args() 901 as []string 902 ) 903 if len(ca) == 0 { 904 as = []string{""} 905 } else { 906 as = ca 907 } 908 909 pcscommand.RunGetMeta(as...) 910 return nil 911 }, 912 }, 913 { 914 Name: "rm", 915 Usage: "删除文件/目录", 916 UsageText: app.Name + " rm <文件/目录的路径1> <文件/目录2> <文件/目录3> ...", 917 Description: ` 918 注意: 删除多个文件和目录时, 请确保每一个文件和目录都存在, 否则删除操作会失败. 919 被删除的文件或目录可在网盘文件回收站找回. 920 921 示例: 922 923 删除 /我的资源/1.mp4 924 BaiduPCS-Go rm /我的资源/1.mp4 925 926 删除 /我的资源/1.mp4 和 /我的资源/2.mp4 927 BaiduPCS-Go rm /我的资源/1.mp4 /我的资源/2.mp4 928 929 删除 /我的资源 内的所有文件和目录, 但不删除该目录 930 BaiduPCS-Go rm /我的资源/* 931 932 删除 /我的资源 整个目录 !! 933 BaiduPCS-Go rm /我的资源 934 `, 935 Category: "百度网盘", 936 Before: reloadFn, 937 Action: func(c *cli.Context) error { 938 if c.NArg() == 0 { 939 cli.ShowCommandHelp(c, c.Command.Name) 940 return nil 941 } 942 943 pcscommand.RunRemove(c.Args()...) 944 return nil 945 }, 946 }, 947 { 948 Name: "mkdir", 949 Usage: "创建目录", 950 UsageText: app.Name + " mkdir <目录>", 951 Category: "百度网盘", 952 Before: reloadFn, 953 Action: func(c *cli.Context) error { 954 if c.NArg() == 0 { 955 cli.ShowCommandHelp(c, c.Command.Name) 956 return nil 957 } 958 959 pcscommand.RunMkdir(c.Args().Get(0)) 960 return nil 961 }, 962 }, 963 { 964 Name: "cp", 965 Usage: "拷贝文件/目录", 966 UsageText: `BaiduPCS-Go cp <文件/目录> <目标文件/目录> 967 BaiduPCS-Go cp <文件/目录1> <文件/目录2> <文件/目录3> ... <目标目录>`, 968 Description: ` 969 注意: 拷贝多个文件和目录时, 请确保每一个文件和目录都存在, 否则拷贝操作会失败. 970 971 示例: 972 973 将 /我的资源/1.mp4 复制到 根目录 / 974 BaiduPCS-Go cp /我的资源/1.mp4 / 975 976 将 /我的资源/1.mp4 和 /我的资源/2.mp4 复制到 根目录 / 977 BaiduPCS-Go cp /我的资源/1.mp4 /我的资源/2.mp4 / 978 `, 979 Category: "百度网盘", 980 Before: reloadFn, 981 Action: func(c *cli.Context) error { 982 if c.NArg() <= 1 { 983 cli.ShowCommandHelp(c, c.Command.Name) 984 return nil 985 } 986 987 pcscommand.RunCopy(c.Args()...) 988 return nil 989 }, 990 }, 991 { 992 Name: "mv", 993 Usage: "移动/重命名文件/目录", 994 UsageText: `移动: 995 BaiduPCS-Go mv <文件/目录1> <文件/目录2> <文件/目录3> ... <目标目录> 996 997 重命名: 998 BaiduPCS-Go mv <文件/目录> <重命名的文件/目录>`, 999 Description: ` 1000 注意: 移动多个文件和目录时, 请确保每一个文件和目录都存在, 否则移动操作会失败. 1001 1002 示例: 1003 1004 将 /我的资源/1.mp4 移动到 根目录 / 1005 BaiduPCS-Go mv /我的资源/1.mp4 / 1006 1007 将 /我的资源/1.mp4 重命名为 /我的资源/3.mp4 1008 BaiduPCS-Go mv /我的资源/1.mp4 /我的资源/3.mp4 1009 `, 1010 Category: "百度网盘", 1011 Before: reloadFn, 1012 Action: func(c *cli.Context) error { 1013 if c.NArg() <= 1 { 1014 cli.ShowCommandHelp(c, c.Command.Name) 1015 return nil 1016 } 1017 1018 pcscommand.RunMove(c.Args()...) 1019 return nil 1020 }, 1021 }, 1022 { 1023 Name: "download", 1024 Aliases: []string{"d"}, 1025 Usage: "下载文件/目录", 1026 UsageText: app.Name + " download <文件/目录路径1> <文件/目录2> <文件/目录3> ...", 1027 Description: ` 1028 下载的文件默认保存到, 程序所在目录的 download/ 目录. 1029 通过 BaiduPCS-Go config set -savedir <savedir>, 自定义保存的目录. 1030 支持多个文件或目录下载. 1031 支持下载完成后自动校验文件, 但并不是所有的文件都支持校验! 1032 自动跳过下载重名的文件! 1033 1034 下载模式说明: 1035 pcs: 通过百度网盘的 PCS API 下载, locate模式提示user is not authorized可尝试此模式 1036 stream: 通过百度网盘的 PCS API, 以流式文件的方式下载, 效果同 pcs 1037 locate: 默认的下载模式。从百度网盘 Android 客户端, 获取下载链接的方式来下载 1038 1039 示例: 1040 1041 设置保存目录, 保存到 D:\Downloads 1042 注意区别反斜杠 "\" 和 斜杠 "/" !!! 1043 BaiduPCS-Go config set -savedir D:\\Downloads 1044 或者 1045 BaiduPCS-Go config set -savedir D:/Downloads 1046 1047 下载 /我的资源/1.mp4 1048 BaiduPCS-Go d /我的资源/1.mp4 1049 1050 下载 /我的资源 整个目录!! 1051 BaiduPCS-Go d /我的资源 1052 1053 下载网盘内的全部文件!! 1054 BaiduPCS-Go d / 1055 BaiduPCS-Go d * 1056 `, 1057 Category: "百度网盘", 1058 Before: reloadFn, 1059 Action: func(c *cli.Context) error { 1060 if c.NArg() == 0 { 1061 cli.ShowCommandHelp(c, c.Command.Name) 1062 return nil 1063 } 1064 1065 // 处理saveTo 1066 var ( 1067 saveTo string 1068 ) 1069 if c.Bool("save") { 1070 saveTo = "." 1071 } else if c.String("saveto") != "" { 1072 saveTo = filepath.Clean(c.String("saveto")) 1073 } 1074 1075 // 处理解析downloadMode 1076 var ( 1077 downloadMode pcsdownload.DownloadMode 1078 ) 1079 switch c.String("mode") { 1080 case "pcs": 1081 downloadMode = pcsdownload.DownloadModePCS 1082 case "stream": 1083 downloadMode = pcsdownload.DownloadModeStreaming 1084 case "locate": 1085 downloadMode = pcsdownload.DownloadModeLocate 1086 default: 1087 fmt.Println("下载方式解析失败") 1088 cli.ShowCommandHelp(c, c.Command.Name) 1089 return nil 1090 } 1091 1092 do := &pcscommand.DownloadOptions{ 1093 IsTest: c.Bool("test"), 1094 IsPrintStatus: c.Bool("status"), 1095 IsExecutedPermission: c.Bool("x"), 1096 IsOverwrite: c.Bool("ow"), 1097 DownloadMode: downloadMode, 1098 SaveTo: saveTo, 1099 Parallel: c.Int("p"), 1100 Load: c.Int("l"), 1101 MaxRetry: c.Int("retry"), 1102 NoCheck: c.Bool("nocheck"), 1103 LinkPrefer: c.Int("dindex"), 1104 ModifyMTime: c.Bool("mtime"), 1105 FullPath: c.Bool("fullpath"), 1106 } 1107 1108 pcscommand.RunDownload(c.Args(), do) 1109 1110 return nil 1111 }, 1112 Flags: []cli.Flag{ 1113 cli.BoolFlag{ 1114 Name: "test", 1115 Usage: "测试下载, 此操作不会保存文件到本地", 1116 }, 1117 cli.BoolFlag{ 1118 Name: "ow", 1119 Usage: "overwrite, 覆盖已存在的文件", 1120 }, 1121 cli.BoolFlag{ 1122 Name: "status", 1123 Usage: "输出所有线程的工作状态", 1124 }, 1125 cli.BoolFlag{ 1126 Name: "save", 1127 Usage: "将下载的文件直接保存到当前工作目录", 1128 }, 1129 cli.StringFlag{ 1130 Name: "saveto", 1131 Usage: "将下载的文件直接保存到指定的目录", 1132 }, 1133 cli.BoolFlag{ 1134 Name: "x", 1135 Usage: "为文件加上执行权限, (windows系统无效)", 1136 }, 1137 cli.StringFlag{ 1138 Name: "mode", 1139 Usage: "下载模式, 可选值: pcs, stream, locate, 默认为 locate, 相关说明见上面的帮助", 1140 Value: "locate", 1141 }, 1142 cli.IntFlag{ 1143 Name: "p", 1144 Usage: "指定下载线程数", 1145 }, 1146 cli.IntFlag{ 1147 Name: "l", 1148 Usage: "指定同时进行下载文件的数量", 1149 }, 1150 cli.IntFlag{ 1151 Name: "retry", 1152 Usage: "下载失败最大重试次数", 1153 Value: pcsdownload.DefaultDownloadMaxRetry, 1154 }, 1155 cli.BoolFlag{ 1156 Name: "nocheck", 1157 Usage: "下载文件完成后不校验文件", 1158 }, 1159 cli.BoolFlag{ 1160 Name: "mtime", 1161 Usage: "将本地文件的修改时间设置为服务器上的修改时间", 1162 }, 1163 cli.IntFlag{ 1164 Name: "dindex", 1165 Usage: "使用备选下载链接中的第几个,默认第一个", 1166 }, 1167 cli.BoolFlag{ 1168 Name: "fullpath", 1169 Usage: "以网盘完整路径保存到本地", 1170 }, 1171 }, 1172 }, 1173 { 1174 Name: "upload", 1175 Aliases: []string{"u"}, 1176 Usage: "上传文件/目录", 1177 UsageText: app.Name + " upload <本地文件/目录的路径1> <文件/目录2> <文件/目录3> ... <目标目录>", 1178 Description: ` 1179 上传默认采用分片上传的方式, 上传的文件将会保存到, <目标目录>. 1180 当上传的文件名和网盘的目录名称相同时, 不会覆盖目录, 防止丢失数据. 1181 1182 注意: 1183 1184 分片上传之后, 服务器可能会记录到错误的文件md5, 可使用 fixmd5 命令尝试修复文件的MD5值, 修复md5不一定能成功, 但文件的完整性是没问题的. 1185 fixmd5 命令使用方法: 1186 BaiduPCS-Go fixmd5 -h 1187 1188 禁用分片上传可以保证服务器记录到正确的md5. 1189 禁用分片上传时只能使用单线程上传, 指定的单个文件上传最大线程数将会无效. 1190 1191 示例: 1192 1193 1. 将本地的 C:\Users\Administrator\Desktop\1.mp4 上传到网盘 /视频 目录 1194 注意区别反斜杠 "\" 和 斜杠 "/" !!! 1195 BaiduPCS-Go upload C:/Users/Administrator/Desktop/1.mp4 /视频 1196 1197 2. 将本地的 C:\Users\Administrator\Desktop\1.mp4 和 C:\Users\Administrator\Desktop\2.mp4 上传到网盘 /视频 目录 1198 BaiduPCS-Go upload C:/Users/Administrator/Desktop/1.mp4 C:/Users/Administrator/Desktop/2.mp4 /视频 1199 1200 3. 将本地的 C:\Users\Administrator\Desktop 整个目录上传到网盘 /视频 目录 1201 BaiduPCS-Go upload C:/Users/Administrator/Desktop /视频 1202 1203 4. 使用相对路径 1204 BaiduPCS-Go upload 1.mp4 /视频 1205 `, 1206 Category: "百度网盘", 1207 Before: reloadFn, 1208 Action: func(c *cli.Context) error { 1209 if c.NArg() < 2 { 1210 cli.ShowCommandHelp(c, c.Command.Name) 1211 return nil 1212 } 1213 1214 subArgs := c.Args() 1215 pcscommand.RunUpload(subArgs[:c.NArg()-1], subArgs[c.NArg()-1], &pcscommand.UploadOptions{ 1216 Parallel: c.Int("p"), 1217 MaxRetry: c.Int("retry"), 1218 Load: c.Int("l"), 1219 NoRapidUpload: c.Bool("norapid"), 1220 NoSplitFile: c.Bool("nosplit"), 1221 Policy: c.String("policy"), 1222 }) 1223 return nil 1224 }, 1225 Flags: []cli.Flag{ 1226 cli.IntFlag{ 1227 Name: "p", 1228 Usage: "指定单个文件上传的最大线程数", 1229 }, 1230 cli.IntFlag{ 1231 Name: "retry", 1232 Usage: "上传失败最大重试次数", 1233 Value: pcscommand.DefaultUploadMaxRetry, 1234 }, 1235 cli.IntFlag{ 1236 Name: "l", 1237 Usage: "指定同时上传的最大文件数", 1238 }, 1239 cli.BoolFlag{ 1240 Name: "norapid", 1241 Usage: "不检测秒传", 1242 }, 1243 cli.BoolFlag{ 1244 Name: "nosplit", 1245 Usage: "禁用分片上传", 1246 }, 1247 cli.StringFlag{ 1248 Name: "policy", 1249 Usage: "对同名文件的处理策略", 1250 }, 1251 }, 1252 }, 1253 { 1254 Name: "locate", 1255 Aliases: []string{"lt"}, 1256 Usage: "获取下载直链", 1257 UsageText: app.Name + " locate <文件1> <文件2> ...", 1258 Description: fmt.Sprintf(` 1259 获取下载直链 1260 1261 若该功能无法正常使用, 提示"user is not authorized, hitcode:xxx", 尝试更换 User-Agent 为 %s: 1262 BaiduPCS-Go config set -user_agent "%s" 1263 `, baidupcs.NetdiskUA, baidupcs.NetdiskUA), 1264 Category: "百度网盘", 1265 Before: reloadFn, 1266 Action: func(c *cli.Context) error { 1267 if c.NArg() < 1 { 1268 cli.ShowCommandHelp(c, c.Command.Name) 1269 return nil 1270 } 1271 1272 opt := &pcscommand.LocateDownloadOption{ 1273 FromPan: c.Bool("pan"), 1274 } 1275 1276 pcscommand.RunLocateDownload(c.Args(), opt) 1277 return nil 1278 }, 1279 Flags: []cli.Flag{ 1280 cli.BoolFlag{ 1281 Name: "pan", 1282 Usage: "从百度网盘首页获取下载链接", 1283 }, 1284 }, 1285 }, 1286 { 1287 Name: "rapidupload", 1288 Aliases: []string{"ru"}, 1289 Usage: "手动秒传文件", 1290 UsageText: app.Name + " rapidupload -length=<文件的大小> -md5=<文件的md5值> -slicemd5=<文件前256KB切片的md5值(可选)> -crc32=<文件的crc32值(可选)> <保存的网盘路径, 需包含文件名>", 1291 Description: ` 1292 使用此功能秒传文件, 前提是知道文件的大小, md5, 前256KB切片的 md5 (可选), crc32 (可选), 且百度网盘中存在一模一样的文件. 1293 上传的文件将会保存到网盘的目标目录. 1294 遇到同名文件将会自动覆盖! 1295 1296 可能无法秒传 20GB 以上的文件!! 1297 1298 示例: 1299 1300 1. 如果秒传成功, 则保存到网盘路径 /test 1301 BaiduPCS-Go rapidupload -length=56276137 -md5=fbe082d80e90f90f0fb1f94adbbcfa7f -slicemd5=38c6a75b0ec4499271d4ea38a667ab61 -crc32=314332359 /test 1302 `, 1303 Category: "百度网盘", 1304 Before: reloadFn, 1305 Action: func(c *cli.Context) error { 1306 if c.NArg() <= 0 || !c.IsSet("md5") || !c.IsSet("length") || !c.IsSet("slicemd5") { 1307 cli.ShowCommandHelp(c, c.Command.Name) 1308 return nil 1309 } 1310 pcscommand.RunRapidUpload(c.Args().Get(0), c.String("md5"), c.String("slicemd5"), c.Int64("length")) 1311 return nil 1312 }, 1313 Flags: []cli.Flag{ 1314 cli.StringFlag{ 1315 Name: "md5", 1316 Usage: "文件的 md5 值", 1317 }, 1318 cli.StringFlag{ 1319 Name: "slicemd5", 1320 Usage: "文件前 256KB 切片的 md5 值 (可选)", 1321 }, 1322 cli.StringFlag{ 1323 Name: "crc32", 1324 Usage: "文件的 crc32 值 (可选)", 1325 }, 1326 cli.Int64Flag{ 1327 Name: "length", 1328 Usage: "文件的大小", 1329 }, 1330 }, 1331 }, 1332 { 1333 Name: "createsuperfile", 1334 Aliases: []string{"csf"}, 1335 Usage: "手动分片上传—合并分片文件", 1336 UsageText: app.Name + " createsuperfile -path=<保存的网盘路径, 需包含文件名> block1 block2 ... ", 1337 Description: ` 1338 block1, block2 ... 为文件分片的md5值 1339 上传的文件将会保存到网盘的目标目录. 1340 遇到同名文件默认覆盖, 可以--policy参数指定, 支持newcopy, skip, overwrite, fail四种模式 1341 1342 示例: 1343 1344 BaiduPCS-Go createsuperfile -path=1.mp4 ec87a838931d4d5d2e94a04644788a55 ec87a838931d4d5d2e94a04644788a55 1345 `, 1346 Category: "百度网盘", 1347 Before: reloadFn, 1348 Action: func(c *cli.Context) error { 1349 if c.NArg() < 1 { 1350 cli.ShowCommandHelp(c, c.Command.Name) 1351 return nil 1352 } 1353 1354 pcscommand.RunCreateSuperFile(c.String("policy"), c.String("path"), c.Args()...) 1355 return nil 1356 }, 1357 Flags: []cli.Flag{ 1358 cli.StringFlag{ 1359 Name: "path", 1360 Usage: "保存的网盘路径", 1361 Value: "superfile", 1362 }, 1363 cli.StringFlag{ 1364 Name: "policy", 1365 Usage: "同名文件处理策略", 1366 Value: "overwrite", 1367 }, 1368 }, 1369 }, 1370 { 1371 Name: "fixmd5", 1372 Usage: "修复文件MD5", 1373 UsageText: app.Name + " fixmd5 <文件1> <文件2> <文件3> ...", 1374 Description: ` 1375 尝试修复文件的MD5值, 以便于校验文件的完整性和导出文件. 1376 1377 使用分片上传文件, 当文件分片数大于1时, 百度网盘服务端最终计算所得的md5值和本地的不一致, 这可能是百度网盘的bug. 1378 不过把上传的文件下载到本地后,对比md5值是匹配的, 也就是文件在传输中没有发生损坏. 1379 1380 对于MD5值可能有误的文件, 程序会在获取文件的元信息时, 给出MD5值 "可能不正确" 的提示, 表示此文件可以尝试进行MD5值修复. 1381 修复文件MD5不一定能成功, 原因可能是服务器未刷新, 可过几天后再尝试. 1382 修复文件MD5的原理为秒传文件, 即修复文件MD5成功后, 文件的创建日期, 修改日期, fs_id, 版本历史等信息将会被覆盖, 修复的MD5值将覆盖原先的MD5值, 但不影响文件的完整性. 1383 1384 注意: 无法修复 20GB 以上文件的 md5!! 1385 1386 示例: 1387 1388 1. 修复 /我的资源/1.mp4 的 MD5 值 1389 BaiduPCS-Go fixmd5 /我的资源/1.mp4 1390 `, 1391 Category: "百度网盘", 1392 Before: reloadFn, 1393 Action: func(c *cli.Context) error { 1394 if c.NArg() <= 0 { 1395 cli.ShowCommandHelp(c, c.Command.Name) 1396 return nil 1397 } 1398 1399 pcscommand.RunFixMD5(c.Args()...) 1400 return nil 1401 }, 1402 }, 1403 { 1404 Name: "sumfile", 1405 Aliases: []string{"sf"}, 1406 Usage: "获取本地文件的秒传信息(目前秒传功能已失效)", 1407 UsageText: app.Name + " sumfile <本地文件的路径1> <本地文件的路径2> ...", 1408 Description: ` 1409 获取本地文件的大小, md5, 前256KB切片的md5, crc32, 曾经可用于秒传文件. 1410 1411 示例: 1412 1413 获取 C:\Users\Administrator\Desktop\1.mp4 的秒传信息 1414 BaiduPCS-Go sumfile C:/Users/Administrator/Desktop/1.mp4 1415 `, 1416 Category: "其他", 1417 Before: reloadFn, 1418 Action: func(c *cli.Context) error { 1419 if c.NArg() <= 0 { 1420 cli.ShowCommandHelp(c, c.Command.Name) 1421 return nil 1422 } 1423 1424 for k, filePath := range c.Args() { 1425 lp, err := checksum.GetFileSum(filePath, checksum.CHECKSUM_MD5|checksum.CHECKSUM_SLICE_MD5|checksum.CHECKSUM_CRC32) 1426 if err != nil { 1427 fmt.Printf("[%d] %s\n", k+1, err) 1428 continue 1429 } 1430 1431 fmt.Printf("[%d] - [%s]:\n", k+1, filePath) 1432 1433 strLength, strMd5, strSliceMd5, strCrc32 := strconv.FormatInt(lp.Length, 10), hex.EncodeToString(lp.MD5), hex.EncodeToString(lp.SliceMD5), strconv.FormatUint(uint64(lp.CRC32), 10) 1434 fileName := filepath.Base(filePath) 1435 regFileName := strings.Replace(fileName, " ", "_", -1) 1436 regFileName = strings.Replace(regFileName, "#", "_", -1) 1437 tb := pcstable.NewTable(os.Stdout) 1438 tb.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT}) 1439 tb.AppendBulk([][]string{ 1440 []string{"文件大小", strLength}, 1441 []string{"md5", strMd5}, 1442 []string{"前256KB切片的md5", strSliceMd5}, 1443 []string{"crc32", strCrc32}, 1444 []string{"秒传命令", app.Name + " rapidupload -length=" + strLength + " -md5=" + strMd5 + " -slicemd5=" + strSliceMd5 + " -crc32=" + strCrc32 + " " + fileName}, 1445 []string{"通用秒传链接", strMd5 + "#" + strSliceMd5 + "#" + strLength + "#" + regFileName}, 1446 }) 1447 tb.Render() 1448 fmt.Printf("\n") 1449 } 1450 1451 return nil 1452 }, 1453 }, 1454 { 1455 Name: "transfer", 1456 Usage: "转存文件/目录", 1457 UsageText: app.Name + " transfer <分享链接> <提取码>(如果有)", 1458 Category: "百度网盘", 1459 Before: reloadFn, 1460 Description: ` 1461 转存文件/目录 1462 如果没有提取码或为整合式链接,则第二个位置留空;只能转存到当前网盘目录下, 1463 分享链接支持常规百度云链接, 支持长短秒传链接 1464 1465 实例: 1466 BaiduPCS-Go transfer pan.baidu.com/s/1VYzSl7465sdrQXe8GT5RdQ 704e 1467 BaiduPCS-Go transfer https://pan.baidu.com/s/1VYzSl7465sdrQXe8GT5RdQ 704e 1468 BaiduPCS-Go transfer https://pan.baidu.com/s/1VYzSl7465sdrQXe8GT5RdQ?pwd=704e 1469 1470 `, 1471 Action: func(c *cli.Context) error { 1472 if c.NArg() < 1 || c.NArg() > 2 { 1473 cli.ShowCommandHelp(c, c.Command.Name) 1474 return nil 1475 } 1476 opt := &baidupcs.TransferOption{ 1477 Download: c.Bool("download"), 1478 Collect: c.Bool("collect"), 1479 Rname: c.Bool("rname"), 1480 } 1481 pcscommand.RunShareTransfer(c.Args(), opt) 1482 return nil 1483 }, 1484 Flags: []cli.Flag{ 1485 cli.BoolFlag{ 1486 Name: "download", 1487 Usage: "转存后直接下载到本地默认目录", 1488 }, 1489 cli.BoolFlag{ 1490 Name: "collect", 1491 Usage: "多文件整合到一个文件夹中转存", 1492 }, 1493 cli.BoolFlag{ 1494 Name: "rname", 1495 Usage: "秒传随机替换4位文件名提高成功率", 1496 }, 1497 }, 1498 }, 1499 { 1500 Name: "share", 1501 Usage: "分享文件/目录", 1502 UsageText: app.Name + " share", 1503 Category: "百度网盘", 1504 Before: reloadFn, 1505 Action: func(c *cli.Context) error { 1506 cli.ShowCommandHelp(c, c.Command.Name) 1507 return nil 1508 }, 1509 Subcommands: []cli.Command{ 1510 { 1511 Name: "set", 1512 Aliases: []string{"s"}, 1513 Usage: "设置分享文件/目录", 1514 UsageText: app.Name + " share set <文件/目录1> <文件/目录2> ...", 1515 Description: `支持任意有效天数, 支持自定义提取码.`, 1516 Action: func(c *cli.Context) error { 1517 if c.NArg() < 1 { 1518 cli.ShowCommandHelp(c, c.Command.Name) 1519 return nil 1520 } 1521 opt := &baidupcs.ShareOption{ 1522 Password: c.String("p"), 1523 Period: c.Int("period"), 1524 IsCombined: c.Bool("f"), 1525 } 1526 pcscommand.RunShareSet(c.Args(), opt) 1527 return nil 1528 }, 1529 Flags: []cli.Flag{ 1530 cli.StringFlag{ 1531 Name: "p", 1532 Usage: "提取码", 1533 Value: "", 1534 }, 1535 cli.IntFlag{ 1536 Name: "period", 1537 Usage: "有效天数, 0为永久", 1538 Value: 0, 1539 }, 1540 cli.BoolFlag{ 1541 Name: "f", 1542 Usage: "输出带密码的完整链接格式", 1543 }, 1544 }, 1545 }, 1546 { 1547 Name: "list", 1548 Aliases: []string{"l"}, 1549 Usage: "列出已分享文件/目录", 1550 UsageText: app.Name + " share list", 1551 Action: func(c *cli.Context) error { 1552 pcscommand.RunShareList(c.Int("page")) 1553 return nil 1554 }, 1555 Flags: []cli.Flag{ 1556 cli.IntFlag{ 1557 Name: "page", 1558 Usage: "分享列表的页数", 1559 Value: 1, 1560 }, 1561 }, 1562 }, 1563 { 1564 Name: "cancel", 1565 Aliases: []string{"c"}, 1566 Usage: "取消分享文件/目录", 1567 UsageText: app.Name + " share cancel <shareid_1> <shareid_2> ...", 1568 Description: `目前只支持通过分享id (shareid) 来取消分享.`, 1569 Action: func(c *cli.Context) error { 1570 if c.NArg() < 1 { 1571 cli.ShowCommandHelp(c, c.Command.Name) 1572 return nil 1573 } 1574 pcscommand.RunShareCancel(converter.SliceStringToInt64(c.Args())) 1575 return nil 1576 }, 1577 }, 1578 }, 1579 }, 1580 { 1581 Name: "export", 1582 Aliases: []string{"ep"}, 1583 Usage: "导出文件/目录", 1584 UsageText: app.Name + " export <文件/目录1> <文件/目录2> ...", 1585 Description: ` 1586 导出网盘内的文件或目录, 原理为秒传文件, 此操作会生成导出文件或目录的命令. 1587 1588 注意!!! : 1589 由于秒传已经失效, 导出信息已无法用做公开分享 1590 无法导出 20GB 以上的文件!! 1591 无法导出文件的版本历史等数据!! 1592 并不是所有的文件都能导出成功, 程序会列出无法导出的文件列表. 1593 1594 示例: 1595 1596 导出当前工作目录: 1597 BaiduPCS-Go export 1598 1599 导出所有文件和目录, 并设置新的根目录为 /root 1600 BaiduPCS-Go export -root=/root / 1601 1602 导出 /我的资源 1603 BaiduPCS-Go export /我的资源 1604 `, 1605 Category: "百度网盘", 1606 Before: reloadFn, 1607 Action: func(c *cli.Context) error { 1608 pcspaths := c.Args() 1609 if len(pcspaths) == 0 { 1610 pcspaths = []string{"."} 1611 } 1612 1613 pcscommand.RunExport(pcspaths, &pcscommand.ExportOptions{ 1614 RootPath: c.String("root"), 1615 SavePath: c.String("out"), 1616 MaxRetry: c.Int("retry"), 1617 Recursive: c.Bool("r"), 1618 LinkFormat: c.Bool("link"), 1619 StdOut: c.Bool("stdout"), 1620 }) 1621 return nil 1622 }, 1623 Flags: []cli.Flag{ 1624 cli.StringFlag{ 1625 Name: "root", 1626 Usage: "设置要导出文件或目录的根路径, 可以是相对路径", 1627 }, 1628 cli.StringFlag{ 1629 Name: "out", 1630 Usage: "导出文件信息的保存路径", 1631 }, 1632 cli.IntFlag{ 1633 Name: "retry", 1634 Usage: "导出失败的重试次数", 1635 Value: 3, 1636 }, 1637 cli.BoolFlag{ 1638 Name: "r", 1639 Usage: "递归导出", 1640 }, 1641 cli.BoolFlag{ 1642 Name: "link", 1643 Usage: "以通用秒传链接格式导出(将丢失路径信息)", 1644 }, 1645 cli.BoolFlag{ 1646 Name: "stdout", 1647 Usage: "导出信息不存文件, 直接打印至标准输出", 1648 }, 1649 }, 1650 }, 1651 { 1652 Name: "offlinedl", 1653 Aliases: []string{"clouddl", "od"}, 1654 Usage: "离线下载", 1655 Description: `支持http/https/ftp/电驴/磁力链协议 1656 离线下载同时进行的任务数量有限, 超出限制的部分将无法添加. 1657 1658 示例: 1659 1660 1. 将百度和腾讯主页, 离线下载到根目录 / 1661 BaiduPCS-Go offlinedl add -path=/ http://baidu.com http://qq.com 1662 1663 2. 添加磁力链接任务 1664 BaiduPCS-Go offlinedl add magnet:?xt=urn:btih:xxx 1665 1666 3. 查询任务ID为 12345 的离线下载任务状态 1667 BaiduPCS-Go offlinedl query 12345 1668 1669 4. 取消任务ID为 12345 的离线下载任务 1670 BaiduPCS-Go offlinedl cancel 12345`, 1671 Category: "百度网盘", 1672 Before: reloadFn, 1673 Action: func(c *cli.Context) error { 1674 cli.ShowCommandHelp(c, c.Command.Name) 1675 return nil 1676 }, 1677 Subcommands: []cli.Command{ 1678 { 1679 Name: "add", 1680 Aliases: []string{"a"}, 1681 Usage: "添加离线下载任务", 1682 UsageText: app.Name + " offlinedl add -path=<离线下载文件保存的路径> 资源地址1 地址2 ...", 1683 Action: func(c *cli.Context) error { 1684 if c.NArg() < 1 { 1685 cli.ShowCommandHelp(c, c.Command.Name) 1686 return nil 1687 } 1688 1689 pcscommand.RunCloudDlAddTask(c.Args(), c.String("path")) 1690 return nil 1691 }, 1692 Flags: []cli.Flag{ 1693 cli.StringFlag{ 1694 Name: "path", 1695 Usage: "离线下载文件保存的路径, 默认为工作目录", 1696 }, 1697 }, 1698 }, 1699 { 1700 Name: "query", 1701 Aliases: []string{"q"}, 1702 Usage: "精确查询离线下载任务", 1703 UsageText: app.Name + " offlinedl query 任务ID1 任务ID2 ...", 1704 Action: func(c *cli.Context) error { 1705 if c.NArg() < 1 { 1706 cli.ShowCommandHelp(c, c.Command.Name) 1707 return nil 1708 } 1709 1710 taskIDs := converter.SliceStringToInt64(c.Args()) 1711 1712 if len(taskIDs) == 0 { 1713 fmt.Printf("未找到合法的任务ID, task_id\n") 1714 return nil 1715 } 1716 1717 pcscommand.RunCloudDlQueryTask(taskIDs) 1718 return nil 1719 }, 1720 }, 1721 { 1722 Name: "list", 1723 Aliases: []string{"ls", "l"}, 1724 Usage: "查询离线下载任务列表", 1725 UsageText: app.Name + " offlinedl list", 1726 Action: func(c *cli.Context) error { 1727 pcscommand.RunCloudDlListTask() 1728 return nil 1729 }, 1730 }, 1731 { 1732 Name: "cancel", 1733 Aliases: []string{"c"}, 1734 Usage: "取消离线下载任务", 1735 UsageText: app.Name + " offlinedl cancel 任务ID1 任务ID2 ...", 1736 Action: func(c *cli.Context) error { 1737 if c.NArg() < 1 { 1738 cli.ShowCommandHelp(c, c.Command.Name) 1739 return nil 1740 } 1741 1742 taskIDs := converter.SliceStringToInt64(c.Args()) 1743 1744 if len(taskIDs) == 0 { 1745 fmt.Printf("未找到合法的任务ID, task_id\n") 1746 return nil 1747 } 1748 1749 pcscommand.RunCloudDlCancelTask(taskIDs) 1750 return nil 1751 }, 1752 }, 1753 { 1754 Name: "delete", 1755 Aliases: []string{"del", "d"}, 1756 Usage: "删除离线下载任务", 1757 UsageText: app.Name + " offlinedl delete 任务ID1 任务ID2 ...", 1758 Action: func(c *cli.Context) error { 1759 isClear := c.Bool("all") 1760 if c.NArg() < 1 && !isClear { 1761 cli.ShowCommandHelp(c, c.Command.Name) 1762 return nil 1763 } 1764 1765 // 清空离线下载任务记录 1766 if isClear { 1767 pcscommand.RunCloudDlClearTask() 1768 return nil 1769 } 1770 1771 // 删除特定的离线下载任务记录 1772 taskIDs := converter.SliceStringToInt64(c.Args()) 1773 if len(taskIDs) == 0 { 1774 fmt.Printf("未找到合法的任务ID, task_id\n") 1775 return nil 1776 } 1777 1778 pcscommand.RunCloudDlDeleteTask(taskIDs) 1779 return nil 1780 }, 1781 Flags: []cli.Flag{ 1782 cli.BoolFlag{ 1783 Name: "all", 1784 Usage: "清空离线下载任务记录, 程序不会进行二次确认, 谨慎操作!!!", 1785 }, 1786 }, 1787 }, 1788 }, 1789 }, 1790 { 1791 Name: "recycle", 1792 Usage: "回收站", 1793 Description: ` 1794 回收站操作. 1795 1796 示例: 1797 1798 1. 从回收站还原两个文件, 其中的两个文件的 fs_id 分别为 1013792297798440 和 643596340463870 1799 BaiduPCS-Go recycle restore 1013792297798440 643596340463870 1800 1801 2. 从回收站删除两个文件, 其中的两个文件的 fs_id 分别为 1013792297798440 和 643596340463870 1802 BaiduPCS-Go recycle delete 1013792297798440 643596340463870 1803 1804 3. 清空回收站, 程序不会进行二次确认, 谨慎操作!!! 1805 BaiduPCS-Go recycle delete -all 1806 `, 1807 Category: "百度网盘", 1808 Before: reloadFn, 1809 Action: func(c *cli.Context) error { 1810 if c.NumFlags() <= 0 || c.NArg() <= 0 { 1811 cli.ShowCommandHelp(c, c.Command.Name) 1812 } 1813 return nil 1814 }, 1815 Subcommands: []cli.Command{ 1816 { 1817 Name: "list", 1818 Aliases: []string{"ls", "l"}, 1819 Usage: baidupcs.OperationRecycleList, 1820 UsageText: app.Name + " recycle list", 1821 Action: func(c *cli.Context) error { 1822 pcscommand.RunRecycleList(c.Int("page")) 1823 return nil 1824 }, 1825 Flags: []cli.Flag{ 1826 cli.IntFlag{ 1827 Name: "page", 1828 Usage: "回收站文件列表页数", 1829 Value: 1, 1830 }, 1831 }, 1832 }, 1833 { 1834 Name: "restore", 1835 Aliases: []string{"r"}, 1836 Usage: baidupcs.OperationRecycleRestore, 1837 UsageText: app.Name + " recycle restore <fs_id 1> <fs_id 2> <fs_id 3> ...", 1838 Description: `根据文件/目录的 fs_id, 还原回收站指定的文件或目录`, 1839 Action: func(c *cli.Context) error { 1840 if c.NArg() <= 0 { 1841 cli.ShowCommandHelp(c, c.Command.Name) 1842 return nil 1843 } 1844 pcscommand.RunRecycleRestore(c.Args()...) 1845 return nil 1846 }, 1847 }, 1848 { 1849 Name: "delete", 1850 Aliases: []string{"d"}, 1851 Usage: baidupcs.OperationRecycleDelete + "/" + baidupcs.OperationRecycleClear, 1852 UsageText: app.Name + " recycle delete [-all] <fs_id 1> <fs_id 2> <fs_id 3> ...", 1853 Description: `根据文件/目录的 fs_id 或 -all 参数, 删除回收站指定的文件或目录或清空回收站`, 1854 Action: func(c *cli.Context) error { 1855 if c.Bool("all") { 1856 // 清空回收站 1857 pcscommand.RunRecycleClear() 1858 return nil 1859 } 1860 1861 if c.NArg() <= 0 { 1862 cli.ShowCommandHelp(c, c.Command.Name) 1863 return nil 1864 } 1865 pcscommand.RunRecycleDelete(c.Args()...) 1866 return nil 1867 }, 1868 Flags: []cli.Flag{ 1869 cli.BoolFlag{ 1870 Name: "all", 1871 Usage: "清空回收站, 程序不会进行二次确认, 谨慎操作!!!", 1872 }, 1873 }, 1874 }, 1875 }, 1876 }, 1877 { 1878 Name: "config", 1879 Usage: "显示和修改程序配置项", 1880 Description: "显示和修改程序配置项", 1881 Category: "配置", 1882 Before: reloadFn, 1883 After: saveFunc, 1884 Action: func(c *cli.Context) error { 1885 fmt.Printf("----\n运行 %s config set 可进行设置配置\n\n当前配置:\n", app.Name) 1886 pcsconfig.Config.PrintTable() 1887 return nil 1888 }, 1889 Subcommands: []cli.Command{ 1890 { 1891 Name: "set", 1892 Usage: "修改程序配置项", 1893 UsageText: app.Name + " config set [arguments...]", 1894 Description: ` 1895 注意: 1896 可通过设置环境变量 BAIDUPCS_GO_CONFIG_DIR, 指定配置文件存放的目录. 1897 1898 谨慎修改 appid, user_agent, pcs_ua, pan_ua 的值, 否则访问网盘服务器时, 可能会出现错误 1899 cache_size 的值支持可选设置单位了, 单位不区分大小写, b 和 B 均表示字节的意思, 如 64KB, 1MB, 32kb, 65536b, 65536 1900 max_download_rate, max_upload_rate 的值支持可选设置单位了, 单位为每秒的传输速率, 后缀'/s' 可省略, 如 2MB/s, 2MB, 2m, 2mb 均为一个意思 1901 1902 例子: 1903 BaiduPCS-Go config set -appid=266719 1904 BaiduPCS-Go config set -enable_https=false 1905 BaiduPCS-Go config set -user_agent="netdisk;2.2.51.6;netdisk;10.0.63;PC;android-android" 1906 BaiduPCS-Go config set -cache_size 64KB 1907 BaiduPCS-Go config set -cache_size 16384 -max_parallel 200 -savedir D:/download`, 1908 Action: func(c *cli.Context) error { 1909 if c.NumFlags() <= 0 || c.NArg() > 0 { 1910 cli.ShowCommandHelp(c, c.Command.Name) 1911 return nil 1912 } 1913 1914 if c.IsSet("appid") { 1915 pcsconfig.Config.SetAppID(c.Int("appid")) 1916 } 1917 if c.IsSet("enable_https") { 1918 pcsconfig.Config.SetEnableHTTPS(c.Bool("enable_https")) 1919 } 1920 if c.IsSet("ignore_illegal") { 1921 pcsconfig.Config.SetIgnoreIllegal(c.Bool("ignore_illegal")) 1922 } 1923 if c.IsSet("force_login_username") { 1924 pcsconfig.Config.SetForceLogin(c.String("force_login_username")) 1925 } 1926 if c.IsSet("no_check") { 1927 pcsconfig.Config.SetNoCheck(c.Bool("no_check")) 1928 } 1929 if c.IsSet("upload_policy") { 1930 pcsconfig.Config.SetUploadPolicy(c.String("upload_policy")) 1931 } 1932 if c.IsSet("user_agent") { 1933 pcsconfig.Config.SetUserAgent(c.String("user_agent")) 1934 } 1935 if c.IsSet("pcs_ua") { 1936 pcsconfig.Config.SetPCSUA(c.String("pcs_ua")) 1937 } 1938 if c.IsSet("pcs_addr") { 1939 match := pcsconfig.Config.SETPCSAddr(c.String("pcs_addr")) 1940 if !match { 1941 fmt.Println("设置 pcs_addr 错误: pcs服务器地址不合法") 1942 return nil 1943 } 1944 } 1945 if c.IsSet("pan_ua") { 1946 pcsconfig.Config.SetPanUA(c.String("pan_ua")) 1947 } 1948 if c.IsSet("cache_size") { 1949 err := pcsconfig.Config.SetCacheSizeByStr(c.String("cache_size")) 1950 if err != nil { 1951 fmt.Printf("设置 cache_size 错误: %s\n", err) 1952 return nil 1953 } 1954 } 1955 if c.IsSet("max_parallel") { 1956 pcsconfig.Config.MaxParallel = c.Int("max_parallel") 1957 } 1958 if c.IsSet("max_upload_parallel") { 1959 pcsconfig.Config.MaxUploadParallel = c.Int("max_upload_parallel") 1960 } 1961 if c.IsSet("max_download_load") { 1962 pcsconfig.Config.MaxDownloadLoad = c.Int("max_download_load") 1963 } 1964 if c.IsSet("max_upload_load") { 1965 pcsconfig.Config.MaxUploadLoad = c.Int("max_upload_load") 1966 } 1967 if c.IsSet("max_download_rate") { 1968 err := pcsconfig.Config.SetMaxDownloadRateByStr(c.String("max_download_rate")) 1969 if err != nil { 1970 fmt.Printf("设置 max_download_rate 错误: %s\n", err) 1971 return nil 1972 } 1973 } 1974 if c.IsSet("max_upload_rate") { 1975 err := pcsconfig.Config.SetMaxUploadRateByStr(c.String("max_upload_rate")) 1976 if err != nil { 1977 fmt.Printf("设置 max_upload_rate 错误: %s\n", err) 1978 return nil 1979 } 1980 } 1981 if c.IsSet("savedir") { 1982 pcsconfig.Config.SaveDir = c.String("savedir") 1983 } 1984 if c.IsSet("proxy") { 1985 pcsconfig.Config.SetProxy(c.String("proxy")) 1986 } 1987 if c.IsSet("local_addrs") { 1988 pcsconfig.Config.SetLocalAddrs(c.String("local_addrs")) 1989 } 1990 1991 err := pcsconfig.Config.Save() 1992 if err != nil { 1993 fmt.Println(err) 1994 return err 1995 } 1996 1997 pcsconfig.Config.PrintTable() 1998 fmt.Printf("\n保存配置成功!\n\n") 1999 2000 return nil 2001 }, 2002 Flags: []cli.Flag{ 2003 cli.IntFlag{ 2004 Name: "appid", 2005 Usage: "百度 PCS 应用ID", 2006 }, 2007 cli.StringFlag{ 2008 Name: "cache_size", 2009 Usage: "下载缓存", 2010 }, 2011 cli.IntFlag{ 2012 Name: "max_parallel", 2013 Usage: "下载网络全部连接的最大并发量", 2014 }, 2015 cli.IntFlag{ 2016 Name: "max_upload_parallel", 2017 Usage: "上传网络单个连接的最大并发量", 2018 }, 2019 cli.IntFlag{ 2020 Name: "max_download_load", 2021 Usage: "同时进行下载文件的最大数量", 2022 }, 2023 cli.IntFlag{ 2024 Name: "max_upload_load", 2025 Usage: "同时进行上传文件的最大数量", 2026 }, 2027 cli.StringFlag{ 2028 Name: "max_download_rate", 2029 Usage: "限制最大下载速度, 0代表不限制", 2030 }, 2031 cli.StringFlag{ 2032 Name: "max_upload_rate", 2033 Usage: "限制最大上传速度, 0代表不限制", 2034 }, 2035 cli.StringFlag{ 2036 Name: "savedir", 2037 Usage: "下载文件的储存目录", 2038 }, 2039 cli.BoolFlag{ 2040 Name: "enable_https", 2041 Usage: "启用 https", 2042 }, 2043 cli.BoolFlag{ 2044 Name: "ignore_illegal", 2045 Usage: "忽略上传时文件名中的非法字符", 2046 }, 2047 cli.StringFlag{ 2048 Name: "force_login_username", 2049 Usage: "强制登录指定用户名, 只适用于tieba接口失效的情况", 2050 }, 2051 cli.BoolFlag{ 2052 Name: "no_check", 2053 Usage: "关闭下载文件md5校验", 2054 }, 2055 cli.StringFlag{ 2056 Name: "upload_policy", 2057 Usage: "设置上传遇到同名文件时的策略", 2058 }, 2059 cli.StringFlag{ 2060 Name: "user_agent", 2061 Usage: "浏览器标识", 2062 }, 2063 cli.StringFlag{ 2064 Name: "pcs_ua", 2065 Usage: "PCS 浏览器标识", 2066 }, 2067 cli.StringFlag{ 2068 Name: "pcs_addr", 2069 Usage: "PCS 服务器地址", 2070 }, 2071 cli.StringFlag{ 2072 Name: "pan_ua", 2073 Usage: "Pan 浏览器标识", 2074 }, 2075 cli.StringFlag{ 2076 Name: "proxy", 2077 Usage: "设置代理, 支持 http/socks5 代理", 2078 }, 2079 cli.StringFlag{ 2080 Name: "local_addrs", 2081 Usage: "设置本地网卡地址, 多个地址用逗号隔开", 2082 }, 2083 }, 2084 }, 2085 { 2086 Name: "reset", 2087 Usage: "恢复默认配置项", 2088 UsageText: app.Name + " config reset", 2089 Description: "", 2090 Action: func(c *cli.Context) error { 2091 pcsconfig.Config.InitDefaultConfig() 2092 err := pcsconfig.Config.Save() 2093 if err != nil { 2094 fmt.Println(err) 2095 return err 2096 } 2097 pcsconfig.Config.PrintTable() 2098 fmt.Println("恢复默认配置成功") 2099 return nil 2100 }, 2101 }, 2102 }, 2103 }, 2104 { 2105 Name: "match", 2106 Usage: "测试通配符", 2107 UsageText: app.Name + " match <通配符表达式>", 2108 Description: ` 2109 测试通配符匹配路径, 操作成功则输出所有匹配到的路径. 2110 2111 示例: 2112 2113 1. 匹配 /我的资源 目录下所有mp4格式的文件 2114 BaiduPCS-Go match /我的资源/*.mp4 2115 `, 2116 Category: "百度网盘", 2117 Before: reloadFn, 2118 Action: func(c *cli.Context) error { 2119 if c.NArg() != 1 { 2120 cli.ShowCommandHelp(c, c.Command.Name) 2121 return nil 2122 } 2123 2124 pcscommand.RunTestShellPattern(c.Args()[0]) 2125 return nil 2126 }, 2127 }, 2128 { 2129 Name: "tool", 2130 Usage: "工具箱", 2131 Action: func(c *cli.Context) error { 2132 cli.ShowCommandHelp(c, c.Command.Name) 2133 return nil 2134 }, 2135 Subcommands: []cli.Command{ 2136 { 2137 Name: "showtime", 2138 Usage: "显示当前时间(北京时间)", 2139 Action: func(c *cli.Context) error { 2140 fmt.Printf(pcstime.BeijingTimeOption("printLog")) 2141 return nil 2142 }, 2143 }, 2144 { 2145 Name: "getip", 2146 Usage: "获取IP地址", 2147 Action: func(c *cli.Context) error { 2148 fmt.Printf("内网IP地址: \n") 2149 for _, address := range pcsutil.ListAddresses() { 2150 fmt.Printf("%s\n", address) 2151 } 2152 fmt.Printf("\n") 2153 2154 ipAddr, err := getip.IPInfoFromTechainBaiduByClient(pcsconfig.Config.HTTPClient()) 2155 if err != nil { 2156 fmt.Printf("获取公网IP错误: %s\n", err) 2157 return nil 2158 } 2159 2160 fmt.Printf("公网IP地址: %s\n", ipAddr) 2161 return nil 2162 }, 2163 }, 2164 { 2165 Name: "enc", 2166 Usage: "加密文件", 2167 UsageText: app.Name + " enc -method=<method> -key=<key> [files...]", 2168 Description: cryptoDescription, 2169 Action: func(c *cli.Context) error { 2170 if c.NArg() <= 0 { 2171 cli.ShowCommandHelp(c, c.Command.Name) 2172 return nil 2173 } 2174 2175 for _, filePath := range c.Args() { 2176 encryptedFilePath, err := pcsutil.EncryptFile(c.String("method"), []byte(c.String("key")), filePath, !c.Bool("disable-gzip")) 2177 if err != nil { 2178 fmt.Printf("%s\n", err) 2179 continue 2180 } 2181 2182 fmt.Printf("加密成功, %s -> %s\n", filePath, encryptedFilePath) 2183 } 2184 2185 return nil 2186 }, 2187 Flags: []cli.Flag{ 2188 cli.StringFlag{ 2189 Name: "method", 2190 Usage: "加密方法", 2191 Value: "aes-128-ctr", 2192 }, 2193 cli.StringFlag{ 2194 Name: "key", 2195 Usage: "加密密钥", 2196 Value: app.Name, 2197 }, 2198 cli.BoolFlag{ 2199 Name: "disable-gzip", 2200 Usage: "不启用GZIP", 2201 }, 2202 }, 2203 }, 2204 { 2205 Name: "dec", 2206 Usage: "解密文件", 2207 UsageText: app.Name + " dec -method=<method> -key=<key> [files...]", 2208 Description: cryptoDescription, 2209 Action: func(c *cli.Context) error { 2210 if c.NArg() <= 0 { 2211 cli.ShowCommandHelp(c, c.Command.Name) 2212 return nil 2213 } 2214 2215 for _, filePath := range c.Args() { 2216 decryptedFilePath, err := pcsutil.DecryptFile(c.String("method"), []byte(c.String("key")), filePath, !c.Bool("disable-gzip")) 2217 if err != nil { 2218 fmt.Printf("%s\n", err) 2219 continue 2220 } 2221 2222 fmt.Printf("解密成功, %s -> %s\n", filePath, decryptedFilePath) 2223 } 2224 2225 return nil 2226 }, 2227 Flags: []cli.Flag{ 2228 cli.StringFlag{ 2229 Name: "method", 2230 Usage: "加密方法", 2231 Value: "aes-128-ctr", 2232 }, 2233 cli.StringFlag{ 2234 Name: "key", 2235 Usage: "加密密钥", 2236 Value: app.Name, 2237 }, 2238 cli.BoolFlag{ 2239 Name: "disable-gzip", 2240 Usage: "不启用GZIP", 2241 }, 2242 }, 2243 }, 2244 }, 2245 }, 2246 { 2247 Name: "clear", 2248 Aliases: []string{"cls"}, 2249 Usage: "清空控制台", 2250 UsageText: app.Name + " clear", 2251 Description: "清空控制台屏幕", 2252 Category: "其他", 2253 Action: func(c *cli.Context) error { 2254 pcsliner.ClearScreen() 2255 return nil 2256 }, 2257 }, 2258 { 2259 Name: "quit", 2260 Aliases: []string{"exit"}, 2261 Usage: "退出程序", 2262 Action: func(c *cli.Context) error { 2263 return cli.NewExitError("", 0) 2264 }, 2265 Hidden: true, 2266 HideHelp: true, 2267 }, 2268 } 2269 2270 sort.Sort(cli.FlagsByName(app.Flags)) 2271 sort.Sort(cli.CommandsByName(app.Commands)) 2272 2273 app.Run(os.Args) 2274 }