github.com/qjfoidnh/BaiduPCS-Go@v0.0.0-20231011165705-caa18a3765f3/baidupcs/baidupcs.go (about) 1 // Package baidupcs BaiduPCS RESTful API 工具包 2 package baidupcs 3 4 import ( 5 "errors" 6 "net/http" 7 "net/http/cookiejar" 8 "net/url" 9 "strconv" 10 11 "github.com/qjfoidnh/BaiduPCS-Go/baidupcs/expires/cachemap" 12 "github.com/qjfoidnh/BaiduPCS-Go/baidupcs/internal/panhome" 13 "github.com/qjfoidnh/BaiduPCS-Go/baidupcs/pcserror" 14 "github.com/qjfoidnh/BaiduPCS-Go/pcsverbose" 15 "github.com/qjfoidnh/BaiduPCS-Go/requester" 16 ) 17 18 const ( 19 // OperationGetUK 获取UK 20 OperationGetUK = "获取UK" 21 // OperationGetBDSToken 22 OperationGetBDSToken = "获取bdstoken" 23 // OperationGetCursorDiff 24 OperationGetCursorDiff = "获取cursor后文件列表diff信息" 25 // OperationQuotaInfo 获取当前用户空间配额信息 26 OperationQuotaInfo = "获取当前用户空间配额信息" 27 // OperationFilesDirectoriesMeta 获取文件/目录的元信息 28 OperationFilesDirectoriesMeta = "获取文件/目录的元信息" 29 // OperationFilesDirectoriesList 获取目录下的文件列表 30 OperationFilesDirectoriesList = "获取目录下的文件列表" 31 // OperationSearch 搜索 32 OperationSearch = "搜索" 33 // OperationRemove 删除文件/目录 34 OperationRemove = "删除文件/目录" 35 // OperationMkdir 创建目录 36 OperationMkdir = "创建目录" 37 // OperationRename 重命名文件/目录 38 OperationRename = "重命名文件/目录" 39 // OperationCopy 拷贝文件/目录 40 OperationCopy = "拷贝文件/目录" 41 // OperationMove 移动文件/目录 42 OperationMove = "移动文件/目录" 43 // OperationRapidUpload 秒传文件 44 OperationRapidUpload = "秒传文件" 45 // OperationUpload 上传单个文件 46 OperationUpload = "上传单个文件" 47 // OperationUploadTmpFile 分片上传—文件分片及上传 48 OperationUploadTmpFile = "分片上传—文件分片及上传" 49 // OperationUploadCreateSuperFile 分片上传—合并分片文件 50 OperationUploadCreateSuperFile = "分片上传—合并分片文件" 51 // OperationUploadPrecreate 分片上传—Precreate 52 OperationUploadPrecreate = "分片上传—Precreate" 53 // OperationUploadSuperfile2 分片上传—Superfile2 54 OperationUploadSuperfile2 = "分片上传—Superfile2" 55 // OperationDownloadFile 下载单个文件 56 OperationDownloadFile = "下载单个文件" 57 // OperationDownloadStreamFile 下载流式文件 58 OperationDownloadStreamFile = "下载流式文件" 59 // OperationLocateDownload 获取下载链接 60 OperationLocateDownload = "获取下载链接" 61 // OperationLocatePanAPIDownload 从百度网盘首页获取下载链接 62 OperationLocatePanAPIDownload = "获取下载链接2" 63 // OperationCloudDlAddTask 添加离线下载任务 64 OperationCloudDlAddTask = "添加离线下载任务" 65 // OperationCloudDlQueryTask 精确查询离线下载任务 66 OperationCloudDlQueryTask = "精确查询离线下载任务" 67 // OperationCloudDlListTask 查询离线下载任务列表 68 OperationCloudDlListTask = "查询离线下载任务列表" 69 // OperationCloudDlCancelTask 取消离线下载任务 70 OperationCloudDlCancelTask = "取消离线下载任务" 71 // OperationCloudDlDeleteTask 删除离线下载任务 72 OperationCloudDlDeleteTask = "删除离线下载任务" 73 // OperationCloudDlClearTask 清空离线下载任务记录 74 OperationCloudDlClearTask = "清空离线下载任务记录" 75 // OperationShareSet 创建分享链接 76 OperationShareSet = "创建分享链接" 77 // OperationShareCancel 取消分享 78 OperationShareCancel = "取消分享" 79 // OperationShareList 列出分享列表 80 OperationShareList = "列出分享列表" 81 // OperationShareSURLInfo 获取分享详细信息 82 OperationShareSURLInfo = "获取分享详细信息" 83 // OperationShareFileSavetoLocal 分享链接转存到网盘 84 OperationShareFileSavetoLocal = "分享链接转存到网盘" 85 // OperationRapidLinkSavetoLocal 秒传链接转存到网盘 86 OperationRapidLinkSavetoLocal = "秒传链接转存到网盘" 87 // OperationRecycleList 列出回收站文件列表 88 OperationRecycleList = "列出回收站文件列表" 89 // OperationRecycleRestore 还原回收站文件或目录 90 OperationRecycleRestore = "还原回收站文件或目录" 91 // OperationRecycleDelete 删除回收站文件或目录 92 OperationRecycleDelete = "删除回收站文件或目录" 93 // OperationRecycleClear 清空回收站 94 OperationRecycleClear = "清空回收站" 95 96 // OperationExportFileInfo 导出文件信息 97 OperationExportFileInfo = "导出文件信息" 98 // OperationGetRapidUploadInfo 获取文件秒传信息 99 OperationGetRapidUploadInfo = "获取文件秒传信息" 100 // OperationFixMD5 修复文件md5 101 OperationFixMD5 = "修复文件md5" 102 // OperrationMatchPathByShellPattern 通配符匹配文件路径 103 OperrationMatchPathByShellPattern = "通配符匹配文件路径" 104 105 // PCSBaiduCom pcs api地址 106 PCSBaiduCom = "pcs.baidu.com" 107 // PanBaiduCom 网盘首页api地址 108 PanBaiduCom = "pan.baidu.com" 109 // YunBaiduCom 网盘首页api地址2 110 YunBaiduCom = "yun.baidu.com" 111 // PanAppID 百度网盘appid 112 PanAppID = "250528" 113 // NetdiskUA 网盘客户端ua 114 NetdiskUA = "netdisk;P2SP;3.0.0.8;netdisk;11.12.3;ANG-AN00;android-android;10.0;JSbridge4.4.0;jointBridge;1.1.0;" 115 // DotBaiduCom .baidu.com 116 DotBaiduCom = ".baidu.com" 117 // PathSeparator 路径分隔符 118 PathSeparator = "/" 119 ) 120 121 var ( 122 baiduPCSVerbose = pcsverbose.New("BAIDUPCS") 123 124 baiduComURL = &url.URL{ 125 Scheme: "http", 126 Host: "pan.baidu.com", 127 } 128 129 baiduPcsComURL = &url.URL{ 130 Scheme: "http", 131 Host: "baidupcs.com", 132 } 133 ) 134 135 type ( 136 // BaiduPCS 百度 PCS API 详情 137 BaiduPCS struct { 138 appID int // app_id 139 isHTTPS bool // 是否启用https 140 uid uint64 // 百度uid 141 client *requester.HTTPClient // http 客户端 142 accessToken string // accessToken 143 pcsUA string 144 pcsAddr string 145 panUA string 146 isSetPanUA bool 147 ph *panhome.PanHome 148 cacheOpMap cachemap.CacheOpMap 149 } 150 151 userInfoJSON struct { 152 *pcserror.PanErrorInfo 153 Records []struct { 154 Uk int64 `json:"uk"` 155 } `json:"records"` 156 } 157 158 userVarJSON struct { 159 *pcserror.PanErrorInfo 160 Result struct { 161 BDSToken string `json:"bdstoken"` 162 } `json:"result"` 163 } 164 ) 165 166 //UpdatePCSCookies 去除重名Cookies, 同名cookeis只保留最新的 167 func (pcs *BaiduPCS) UpdatePCSCookies(reverse bool) { 168 cookies := pcs.GetClient().Jar.Cookies(baiduComURL) 169 new_cookies := make([]*http.Cookie, 0) 170 usedKeys := make(map[string]string) 171 if reverse { 172 for i := len(cookies) - 1; i >= 0; i-- { 173 cookie := cookies[i] 174 _, exists := usedKeys[cookie.Name] 175 if !exists { 176 new_cookies = append(new_cookies, &http.Cookie{ 177 Name: cookie.Name, 178 Value: cookie.Value, 179 Domain: DotBaiduCom, 180 }) 181 usedKeys[cookie.Name] = "" 182 } 183 } 184 for i, j := 0, len(new_cookies)-1; i < j; i, j = i+1, j-1 { 185 new_cookies[i], new_cookies[j] = new_cookies[j], new_cookies[i] //逆序 186 } 187 } else { 188 for i := 0; i < len(cookies); i++ { 189 cookie := cookies[i] 190 _, exists := usedKeys[cookie.Name] 191 if !exists { 192 new_cookies = append(new_cookies, &http.Cookie{ 193 Name: cookie.Name, 194 Value: cookie.Value, 195 Domain: DotBaiduCom, 196 }) 197 usedKeys[cookie.Name] = "" 198 } 199 } 200 } 201 client := pcs.GetClient() 202 client.ResetCookiejar() 203 // fmt.Println(len(new_cookies)) 204 // for _, c := range new_cookies { 205 // fmt.Println(c.Value) 206 // } 207 client.Jar.SetCookies(baiduComURL, new_cookies) 208 209 } 210 211 // NewPCS 提供app_id, 百度BDUSS, 返回 BaiduPCS 对象 212 func NewPCS(appID int, bduss string) *BaiduPCS { 213 client := requester.NewHTTPClient() 214 client.ResetCookiejar() 215 client.Jar.SetCookies(baiduComURL, []*http.Cookie{ 216 &http.Cookie{ 217 Name: "BDUSS", 218 Value: bduss, 219 Domain: DotBaiduCom, 220 }, 221 }) 222 223 return &BaiduPCS{ 224 appID: appID, 225 client: client, 226 } 227 } 228 229 // NewPCSWithClient 提供app_id, 自定义客户端, 返回 BaiduPCS 对象 230 func NewPCSWithClient(appID int, client *requester.HTTPClient) *BaiduPCS { 231 pcs := &BaiduPCS{ 232 appID: appID, 233 client: client, 234 } 235 return pcs 236 } 237 238 // NewPCSWithCookieStr 提供app_id, cookie 字符串, 返回 BaiduPCS 对象 239 func NewPCSWithCookieStr(appID int, cookieStr string) *BaiduPCS { 240 pcs := &BaiduPCS{ 241 appID: appID, 242 client: requester.NewHTTPClient(), 243 } 244 245 cookies := requester.ParseCookieStr(cookieStr) 246 for _, cookie := range cookies { 247 cookie.Domain = DotBaiduCom 248 } 249 250 jar, _ := cookiejar.New(nil) 251 jar.SetCookies(baiduComURL, cookies) 252 pcs.client.SetCookiejar(jar) 253 254 return pcs 255 } 256 257 func (pcs *BaiduPCS) lazyInit() { 258 if pcs.client == nil { 259 pcs.client = requester.NewHTTPClient() 260 } 261 if pcs.ph == nil { 262 pcs.ph = panhome.NewPanHome(pcs.client) 263 } 264 if !pcs.isSetPanUA { 265 pcs.panUA = NetdiskUA 266 } 267 } 268 269 // GetClient 获取当前的http client 270 func (pcs *BaiduPCS) GetClient() *requester.HTTPClient { 271 pcs.lazyInit() 272 return pcs.client 273 } 274 275 // GetBDUSS 获取BDUSS 276 func (pcs *BaiduPCS) GetBDUSS() (bduss string) { 277 if pcs.client == nil || pcs.client.Jar == nil { 278 return "" 279 } 280 cookies := pcs.client.Jar.Cookies(baiduComURL) 281 for _, cookie := range cookies { 282 if cookie.Name == "BDUSS" { 283 return cookie.Value 284 } 285 } 286 return "" 287 } 288 289 // GetBAIDUID 获取BAIDUID 290 func (pcs *BaiduPCS) GetBAIDUID() (baiduid string) { 291 if pcs.client == nil || pcs.client.Jar == nil { 292 return "" 293 } 294 cookies := pcs.client.Jar.Cookies(baiduComURL) 295 for _, cookie := range cookies { 296 if cookie.Name == "BAIDUID" { 297 return cookie.Value 298 } 299 } 300 return "" 301 } 302 303 // SetAPPID 设置app_id 304 func (pcs *BaiduPCS) SetAPPID(appID int) { 305 pcs.appID = appID 306 } 307 308 // SetUID 设置百度UID 309 // 只有locatedownload才需要设置此项 310 func (pcs *BaiduPCS) SetUID(uid uint64) { 311 pcs.uid = uid 312 } 313 314 // SetaccessToken 设置秒传转存用的accesstoken 315 func (pcs *BaiduPCS) SetaccessToken(accessToken string) { 316 pcs.accessToken = accessToken 317 } 318 319 // SetStoken 设置stoken 320 func (pcs *BaiduPCS) SetStoken(stoken string) { 321 pcs.lazyInit() 322 if pcs.client.Jar == nil { 323 pcs.client.ResetCookiejar() 324 } 325 326 pcs.client.Jar.SetCookies(baiduComURL, []*http.Cookie{ 327 &http.Cookie{ 328 Name: "STOKEN", 329 Value: stoken, 330 Domain: DotBaiduCom, 331 }, 332 }) 333 } 334 335 // SetSboxtkn 设置sboxtkn 336 func (pcs *BaiduPCS) SetSboxtkn(sboxtkn string) { 337 pcs.lazyInit() 338 if pcs.client.Jar == nil { 339 pcs.client.ResetCookiejar() 340 } 341 342 pcs.client.Jar.SetCookies(baiduComURL, []*http.Cookie{ 343 &http.Cookie{ 344 Name: "SBOXTKN", 345 Value: sboxtkn, 346 Domain: DotBaiduCom, 347 }, 348 }) 349 } 350 351 // SetPCSUserAgent 设置 PCS User-Agent 352 func (pcs *BaiduPCS) SetPCSUserAgent(ua string) { 353 pcs.pcsUA = ua 354 } 355 356 // SetPCSAddr 设置 PCS 服务器地址 357 func (pcs *BaiduPCS) SetPCSAddr(addr string) { 358 pcs.pcsAddr = addr 359 } 360 361 // SetPanUserAgent 设置 Pan User-Agent 362 func (pcs *BaiduPCS) SetPanUserAgent(ua string) { 363 pcs.panUA = ua 364 pcs.isSetPanUA = true 365 } 366 367 // SetHTTPS 是否启用https连接 368 func (pcs *BaiduPCS) SetHTTPS(https bool) { 369 pcs.isHTTPS = https 370 } 371 372 // URL 返回 url 373 func (pcs *BaiduPCS) URL() *url.URL { 374 host := pcs.pcsAddr 375 if host == "" { 376 host = PCSBaiduCom 377 } 378 return &url.URL{ 379 Scheme: GetHTTPScheme(pcs.isHTTPS), 380 Host: host, 381 } 382 } 383 384 func (pcs *BaiduPCS) getPanUAHeader() (header map[string]string) { 385 return map[string]string{ 386 "User-Agent": pcs.panUA, 387 } 388 } 389 390 func (pcs *BaiduPCS) generatePCSURL(subPath, method string, param ...map[string]string) *url.URL { 391 pcsURL := pcs.URL() 392 pcsURL.Path = "/rest/2.0/pcs/" + subPath 393 394 uv := pcsURL.Query() 395 uv.Set("app_id", strconv.Itoa(pcs.appID)) 396 uv.Set("method", method) 397 for k := range param { 398 for k2 := range param[k] { 399 uv.Set(k2, param[k][k2]) 400 } 401 } 402 403 pcsURL.RawQuery = uv.Encode() 404 return pcsURL 405 } 406 407 func (pcs *BaiduPCS) generatePCSURL2(subPath, method string, param ...map[string]string) *url.URL { 408 pcsURL2 := &url.URL{ 409 Scheme: GetHTTPScheme(pcs.isHTTPS), 410 Host: PanBaiduCom, 411 Path: "/rest/2.0/" + subPath, 412 } 413 414 uv := pcsURL2.Query() 415 uv.Set("method", method) 416 for k := range param { 417 for k2 := range param[k] { 418 uv.Set(k2, param[k][k2]) 419 } 420 } 421 422 pcsURL2.RawQuery = uv.Encode() 423 return pcsURL2 424 } 425 426 func (pcs *BaiduPCS) generatePanURL(subPath string, param map[string]string) *url.URL { 427 panURL := url.URL{ 428 Scheme: GetHTTPScheme(pcs.isHTTPS), 429 Host: PanBaiduCom, 430 Path: "/api/" + subPath, 431 } 432 433 if param != nil { 434 uv := url.Values{} 435 for k := range param { 436 uv.Set(k, param[k]) 437 } 438 panURL.RawQuery = uv.Encode() 439 } 440 return &panURL 441 } 442 443 // UK 获取用户 UK 444 func (pcs *BaiduPCS) UK() (uk int64, pcsError pcserror.Error) { 445 dataReadCloser, pcsError := pcs.PrepareUK() 446 if pcsError != nil { 447 return 448 } 449 450 defer dataReadCloser.Close() 451 452 errInfo := pcserror.NewPanErrorInfo(OperationGetUK) 453 jsonData := userInfoJSON{ 454 PanErrorInfo: errInfo, 455 } 456 457 pcsError = pcserror.HandleJSONParse(OperationGetUK, dataReadCloser, &jsonData) 458 if pcsError != nil { 459 return 460 } 461 462 if len(jsonData.Records) != 1 { 463 errInfo.ErrType = pcserror.ErrTypeOthers 464 errInfo.Err = errors.New("Unknown remote data") 465 return 0, errInfo 466 } 467 468 return jsonData.Records[0].Uk, nil 469 } 470 471 func (pcs *BaiduPCS) BDSToken() (bdstoken string, pcsError pcserror.Error) { 472 dataReadCloser, pcsError := pcs.PrepareBDStoken() 473 if pcsError != nil { 474 return 475 } 476 477 defer dataReadCloser.Close() 478 479 errInfo := pcserror.NewPanErrorInfo(OperationGetBDSToken) 480 jsonData := userVarJSON{ 481 PanErrorInfo: errInfo, 482 } 483 484 pcsError = pcserror.HandleJSONParse(OperationGetBDSToken, dataReadCloser, &jsonData) 485 if pcsError != nil { 486 return 487 } 488 489 if jsonData.Result.BDSToken == "" { 490 errInfo.ErrType = pcserror.ErrTypeOthers 491 errInfo.Err = errors.New("Unknown remote data") 492 return "", errInfo 493 } 494 495 return jsonData.Result.BDSToken, nil 496 }