Skip to content

Commit

Permalink
恢复秒传功能
Browse files Browse the repository at this point in the history
测试版本谨慎更新, 由使用新接口带来的一切风险及后果自担
  • Loading branch information
qjfoidnh committed Sep 6, 2023
1 parent 648296c commit 8c035ae
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 87 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ iikira/BaiduPCS-Go was largely inspired by [GangZhuo/BaiduPCS](https://github.co
[离线下载](#离线下载), 支持http/https/ftp/电驴/磁力链协议.

# 版本更新
**2023.09.06** v3.9.5-beta
- 恢复了秒传转存(支持长短链), 感谢油猴脚本开发者tousakarin的贡献
- 新秒传接口需要开发者授权, 稳定性未知, 该测试版本仅供有秒传强需求的用户试用, 请谨慎更新

**2023.09.05** v3.9.4
- fix #244, 修复断点上传时偶发崩溃
- 优化本地上传秒传失败时的处理逻辑
Expand Down
26 changes: 16 additions & 10 deletions baidupcs/baidupcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,17 @@ var (
type (
// BaiduPCS 百度 PCS API 详情
BaiduPCS struct {
appID int // app_id
isHTTPS bool // 是否启用https
uid uint64 // 百度uid
client *requester.HTTPClient // http 客户端
pcsUA string
pcsAddr string
panUA string
isSetPanUA bool
ph *panhome.PanHome
cacheOpMap cachemap.CacheOpMap
appID int // app_id
isHTTPS bool // 是否启用https
uid uint64 // 百度uid
client *requester.HTTPClient // http 客户端
accessToken string // accessToken
pcsUA string
pcsAddr string
panUA string
isSetPanUA bool
ph *panhome.PanHome
cacheOpMap cachemap.CacheOpMap
}

userInfoJSON struct {
Expand Down Expand Up @@ -310,6 +311,11 @@ func (pcs *BaiduPCS) SetUID(uid uint64) {
pcs.uid = uid
}

// SetaccessToken 设置秒传转存用的accesstoken
func (pcs *BaiduPCS) SetaccessToken(accessToken string) {
pcs.accessToken = accessToken
}

// SetStoken 设置stoken
func (pcs *BaiduPCS) SetStoken(stoken string) {
pcs.lazyInit()
Expand Down
6 changes: 4 additions & 2 deletions baidupcs/pcserror/panerrorinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func FindPanErr(errno int) (errmsg string) {
case -7:
return "该分享已删除或已取消"
case -8:
return "该分享已经过期"
return "已存在同名文件"
case -9:
return "文件不存在"
case -10:
Expand Down Expand Up @@ -149,7 +149,7 @@ func FindPanErr(errno int) (errmsg string) {
case -70:
return "你分享的文件中包含病毒或疑似病毒,为了你和他人的数据安全,换个文件分享吧"
case 2:
return "参数错误"
return "请稍后再试, 或更换保存路径"
case 3:
return "未登录或帐号无效"
case 4:
Expand All @@ -170,6 +170,8 @@ func FindPanErr(errno int) (errmsg string) {
return "该文件禁止分享"
case 132:
return "您的帐号可能存在安全风险,为了确保为您本人操作,请先进行安全验证。"
case 9019:
return "accesstoken未设置或过期, 请使用setastoken命令设置`"
default:
return "未知错误"
}
Expand Down
18 changes: 10 additions & 8 deletions baidupcs/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package baidupcs

import (
"bytes"
"fmt"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -302,15 +303,16 @@ func (pcs *BaiduPCS) PrepareMove(cpmvJSON ...*CpMvJSON) (dataReadCloser io.ReadC

// prepareRapidUpload 秒传文件, 不进行文件夹检查
func (pcs *BaiduPCS) prepareRapidUpload(targetPath, contentMD5, sliceMD5, crc32 string, length int64) (dataReadCloser io.ReadCloser, pcsError pcserror.Error) {
pcsURL := pcs.generatePanURL("rapidupload", nil)
baiduPCSVerbose.Infof("%s URL: %s\n", OperationRapidUpload, pcsURL)
post := map[string]string{
"rtype": "0",
"path": targetPath,
"content-md5": contentMD5,
"slice-md5": sliceMD5,
"content-length": strconv.FormatInt(length, 10),
bdstoken, pcsError := pcs.BDSToken()
if pcsError != nil {
return
}
pcsURL := pcs.generatePCSURL2("xpan/file", "create", map[string]string{
"access_token": pcs.accessToken,
"bdstoken": bdstoken,
})
baiduPCSVerbose.Infof("%s URL: %s\n", OperationRapidUpload, pcsURL)
post := fmt.Sprintf("&block_list=[\"%s\"]&path=%s&size=%d&isdir=0&rtype=0", contentMD5, targetPath, length)
baiduPCSVerbose.Infof("%s URL: %s, Post: %v\n", OperationRapidUpload, pcsURL, post)

dataReadCloser, pcsError = pcs.sendReqReturnReadCloser(reqTypePan, OperationRapidUpload, http.MethodPost, pcsURL.String(), post, nil)
Expand Down
12 changes: 12 additions & 0 deletions baidupcs/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ func (pcs *BaiduPCS) RapidUpload(targetPath, contentMD5, sliceMD5, dataContent,
return
}

// APIRapidUpload openapi秒传文件
func (pcs *BaiduPCS) APIRapidUpload(targetPath, contentMD5, sliceMD5, crc32 string, length int64) (pcsError pcserror.Error) {
defer func() {
if pcsError == nil {
// 更新缓存
pcs.deleteCache([]string{path.Dir(targetPath)})
}
}()
pcsError = pcs.rapidUpload(targetPath, strings.ToLower(contentMD5), strings.ToLower(sliceMD5), "", length)
return
}

func (pcs *BaiduPCS) rapidUpload(targetPath, contentMD5, sliceMD5, crc32 string, length int64) (pcsError pcserror.Error) {
dataReadCloser, pcsError := pcs.PrepareRapidUpload(targetPath, contentMD5, sliceMD5, crc32, length)
if pcsError != nil {
Expand Down
27 changes: 12 additions & 15 deletions internal/pcscommand/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package pcscommand
import (
"encoding/base64"
"fmt"
"github.com/qjfoidnh/BaiduPCS-Go/pcsutil/converter"
"path"
"regexp"
"strconv"
Expand All @@ -19,8 +18,8 @@ func RunShareTransfer(params []string, opt *baidupcs.TransferOption) {
if len(params) == 1 {
link = params[0]
if strings.Contains(link, "bdlink=") || !strings.Contains(link, "pan.baidu.com/") {
//RunRapidTransfer(link)
fmt.Printf("%s失败: %s\n", baidupcs.OperationShareFileSavetoLocal, "秒传已不再被支持")
RunRapidTransfer(link)
//fmt.Printf("%s失败: %s\n", baidupcs.OperationShareFileSavetoLocal, "秒传已不再被支持")
return
}
extracode = "none"
Expand Down Expand Up @@ -127,19 +126,17 @@ func RunRapidTransfer(link string) {
link = string(decodeBytes)
}
link = strings.TrimSpace(link)
substrs := strings.SplitN(link, "#", 7)
if len(substrs) == 7 {
substrs := strings.SplitN(link, "#", 4)
if len(substrs) == 4 {
md5, slicemd5 := substrs[0], substrs[1]
dataContent := substrs[3]
dataOffset, err := strconv.ParseInt(substrs[2], 10, 64)
totalSize, err := strconv.ParseInt(substrs[4], 10, 64)
dataTime, err := strconv.ParseInt(substrs[5], 10, 64)
if err != nil {
fmt.Printf("%s失败: %s\n", baidupcs.OperationRapidLinkSavetoLocal, "秒传链接格式错误")
return
}
filename := path.Join(GetActiveUser().Workdir, substrs[6])
RunRapidUpload(filename, md5, slicemd5, dataContent, "", dataOffset, totalSize, 4 * converter.KB, dataTime)
size, _ := strconv.ParseInt(substrs[2], 10, 64)
filename := path.Join(GetActiveUser().Workdir, substrs[3])
RunRapidUpload(filename, md5, slicemd5, size)
} else if len(substrs) == 3 {
md5 := substrs[0]
size, _ := strconv.ParseInt(substrs[1], 10, 64)
filename := path.Join(GetActiveUser().Workdir, substrs[2])
RunRapidUpload(filename, md5, "", size)
} else {
fmt.Printf("%s失败: %s\n", baidupcs.OperationRapidLinkSavetoLocal, "秒传链接格式错误")
}
Expand Down
4 changes: 2 additions & 2 deletions internal/pcscommand/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ func uploadPrintFormat(load int) string {
}

// RunRapidUpload 执行秒传文件, 前提是知道文件的大小, md5, 前256KB切片的 md5, crc32
func RunRapidUpload(targetPath, contentMD5, sliceMD5, dataContent, crc32 string, offset, length, totalSize, dataTime int64) {
func RunRapidUpload(targetPath, contentMD5, sliceMD5 string, length int64) {
dirname := path.Dir(targetPath)
err := matchPathByShellPatternOnce(&dirname)
if err != nil {
fmt.Printf("警告: %s, 获取网盘路径 %s 错误, %s\n", baidupcs.OperationRapidUpload, dirname, err)
}
err = GetBaiduPCS().RapidUpload(targetPath, contentMD5, sliceMD5, dataContent, "", offset, length, totalSize, dataTime)
err = GetBaiduPCS().APIRapidUpload(targetPath, contentMD5, sliceMD5, "", length)
if err != nil {
fmt.Printf("%s失败, 消息: %s\n", baidupcs.OperationRapidUpload, err)
return
Expand Down
3 changes: 3 additions & 0 deletions internal/pcsconfig/baidu.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type Baidu struct {
SBOXTKN string `json:"sboxtkn"`
COOKIES string `json:"cookies"`

AccessToken string `json:"accesstoken"`

Workdir string `json:"workdir"` // 工作目录
}

Expand All @@ -58,6 +60,7 @@ func (baidu *Baidu) BaiduPCS() *baidupcs.BaiduPCS {
pcs.SetPCSUserAgent(Config.PCSUA)
pcs.SetPanUserAgent(Config.PanUA)
pcs.SetUID(baidu.UID)
pcs.SetaccessToken(baidu.AccessToken)
return pcs
}

Expand Down
135 changes: 85 additions & 50 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ const (

var (
// Version 版本号
Version = "v3.9.4-devel"
//Version = "v3.9.4-devel"
Version = "v3.9.5-beta"

historyFilePath = filepath.Join(pcsconfig.GetConfigDir(), "pcs_command_history.txt")
reloadFn = func(c *cli.Context) error {
Expand Down Expand Up @@ -154,7 +155,7 @@ func main() {
lineArgs = args.Parse(line)
numArgs = len(lineArgs)
acceptCompleteFileCommands = []string{
"cd", "cp", "download", "export", "fixmd5", "locate", "ls", "meta", "mkdir", "mv", "rm", "share", "transfer", "tree", "upload",
"cd", "cp", "download", "export", "fixmd5", "locate", "ls", "meta", "mkdir", "mv", "rapidupload", "rm", "setastoken", "share", "transfer", "tree", "upload",
}
closed = strings.LastIndex(line, " ") == len(line)-1
)
Expand Down Expand Up @@ -602,6 +603,41 @@ func main() {
return nil
},
},
{
Name: "setastoken",
Usage: "设定当前账号的accessToken",
Description: `
设定当前登录帐号的accessToken:
若不使用秒传链接转存, 可不设定; accessToken获取网址如下:
https://openapi.baidu.com/oauth/2.0/authorize?response_type=token&client_id=L6g70tBRRIXLsY0Z3HwKqlRE&redirect_uri=oob&scope=netdisk
请在浏览器登录当前网盘账户后打开上述链接, 如果出现授权确认界面请确认授权, 然后复制跳转到的页面url, 找到access_token=xxxxxxx&这段, xxxxxxx即为accessToken
注意accessToken的有效期为一个月, 过期后请重复上述步骤更新token
示例:
BaiduPCS-Go accessToken 156.182v9052tgf1006c89891bsfb2401974.YmKOAwBD9yGaG2s4p5NNkX4CXeIbJxx4hAxotfS.PyuHEs
`,
Category: "百度帐号",
Before: reloadFn,
After: saveFunc,
Action: func(c *cli.Context) error {
activeUser := pcsconfig.Config.ActiveUser()
if activeUser.UID == 0 {
fmt.Println("请先登录")
return nil
}
if c.NArg() >= 2 {
cli.ShowCommandHelp(c, c.Command.Name)
return nil
} else if c.NArg() == 0 {
cli.ShowCommandHelp(c, c.Command.Name)
return nil
}
activeUser.AccessToken = c.Args().Get(0)
pcsconfig.Config.ActiveUserBaiduPCS().SetaccessToken(c.Args().Get(0))
fmt.Printf("当前用户名: %s 成功设置accessToken: %s\n", activeUser.Name, activeUser.AccessToken)
return nil
},
},
{
Name: "who",
Usage: "获取当前帐号",
Expand Down Expand Up @@ -1248,53 +1284,52 @@ func main() {
},
},
},
// {
// Name: "rapidupload",
// Aliases: []string{"ru"},
// Usage: "手动秒传文件",
// UsageText: app.Name + " rapidupload -length=<文件的大小> -md5=<文件的md5值> -slicemd5=<文件前256KB切片的md5值(可选)> -crc32=<文件的crc32值(可选)> <保存的网盘路径, 需包含文件名>",
// Description: `
// 使用此功能秒传文件, 前提是知道文件的大小, md5, 前256KB切片的 md5 (可选), crc32 (可选), 且百度网盘中存在一模一样的文件.
// 上传的文件将会保存到网盘的目标目录.
// 遇到同名文件将会自动覆盖!
//
// 可能无法秒传 20GB 以上的文件!!
//
// 示例:
//
// 1. 如果秒传成功, 则保存到网盘路径 /test
// BaiduPCS-Go rapidupload -length=56276137 -md5=fbe082d80e90f90f0fb1f94adbbcfa7f -slicemd5=38c6a75b0ec4499271d4ea38a667ab61 -crc32=314332359 /test
//`,
// Category: "百度网盘",
// Before: reloadFn,
// Action: func(c *cli.Context) error {
// if c.NArg() <= 0 || !c.IsSet("md5") || !c.IsSet("length") || !c.IsSet("slicemd5") {
// cli.ShowCommandHelp(c, c.Command.Name)
// return nil
// }
//
// pcscommand.RunRapidUpload(c.Args().Get(0), c.String("md5"), c.String("slicemd5"), c.String("datacontent"), "", c.Int64("offset"), c.Int64("length"))
// return nil
// },
// Flags: []cli.Flag{
// cli.StringFlag{
// Name: "md5",
// Usage: "文件的 md5 值",
// },
// cli.StringFlag{
// Name: "slicemd5",
// Usage: "文件前 256KB 切片的 md5 值",
// },
// cli.StringFlag{
// Name: "crc32",
// Usage: "文件的 crc32 值 (可选)",
// },
// cli.Int64Flag{
// Name: "length",
// Usage: "文件的大小",
// },
// },
// },
{
Name: "rapidupload",
Aliases: []string{"ru"},
Usage: "手动秒传文件",
UsageText: app.Name + " rapidupload -length=<文件的大小> -md5=<文件的md5值> -slicemd5=<文件前256KB切片的md5值(可选)> -crc32=<文件的crc32值(可选)> <保存的网盘路径, 需包含文件名>",
Description: `
使用此功能秒传文件, 前提是知道文件的大小, md5, 前256KB切片的 md5 (可选), crc32 (可选), 且百度网盘中存在一模一样的文件.
上传的文件将会保存到网盘的目标目录.
遇到同名文件将会自动覆盖!
可能无法秒传 20GB 以上的文件!!
示例:
1. 如果秒传成功, 则保存到网盘路径 /test
BaiduPCS-Go rapidupload -length=56276137 -md5=fbe082d80e90f90f0fb1f94adbbcfa7f -slicemd5=38c6a75b0ec4499271d4ea38a667ab61 -crc32=314332359 /test
`,
Category: "百度网盘",
Before: reloadFn,
Action: func(c *cli.Context) error {
if c.NArg() <= 0 || !c.IsSet("md5") || !c.IsSet("length") || !c.IsSet("slicemd5") {
cli.ShowCommandHelp(c, c.Command.Name)
return nil
}
pcscommand.RunRapidUpload(c.Args().Get(0), c.String("md5"), c.String("slicemd5"), c.Int64("length"))
return nil
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "md5",
Usage: "文件的 md5 值",
},
cli.StringFlag{
Name: "slicemd5",
Usage: "文件前 256KB 切片的 md5 值 (可选)",
},
cli.StringFlag{
Name: "crc32",
Usage: "文件的 crc32 值 (可选)",
},
cli.Int64Flag{
Name: "length",
Usage: "文件的大小",
},
},
},
{
Name: "createsuperfile",
Aliases: []string{"csf"},
Expand Down Expand Up @@ -1426,7 +1461,7 @@ func main() {
Description: `
转存文件/目录
如果没有提取码或为整合式链接,则第二个位置留空;只能转存到当前网盘目录下,
分享链接支持只常规百度云链接, 不再支持秒传
分享链接支持常规百度云链接, 支持长短秒传链接
实例:
BaiduPCS-Go transfer pan.baidu.com/s/1VYzSl7465sdrQXe8GT5RdQ 704e
Expand Down

0 comments on commit 8c035ae

Please sign in to comment.