github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/baidupcs/baidupcs.go (about)

     1  // Package baidupcs BaiduPCS RESTful API 工具包
     2  package baidupcs
     3  
     4  import (
     5  	"errors"
     6  	"github.com/fzfile/BaiduPCS-Go/baidupcs/expires/cachemap"
     7  	"github.com/fzfile/BaiduPCS-Go/baidupcs/internal/panhome"
     8  	"github.com/fzfile/BaiduPCS-Go/baidupcs/pcserror"
     9  	"github.com/fzfile/BaiduPCS-Go/pcsverbose"
    10  	"github.com/fzfile/BaiduPCS-Go/requester"
    11  	"net/http"
    12  	"net/http/cookiejar"
    13  	"net/url"
    14  	"strconv"
    15  )
    16  
    17  const (
    18  	// OperationGetUK 获取UK
    19  	OperationGetUK = "获取UK"
    20  	// OperationQuotaInfo 获取当前用户空间配额信息
    21  	OperationQuotaInfo = "获取当前用户空间配额信息"
    22  	// OperationFilesDirectoriesMeta 获取文件/目录的元信息
    23  	OperationFilesDirectoriesMeta = "获取文件/目录的元信息"
    24  	// OperationFilesDirectoriesList 获取目录下的文件列表
    25  	OperationFilesDirectoriesList = "获取目录下的文件列表"
    26  	// OperationSearch 搜索
    27  	OperationSearch = "搜索"
    28  	// OperationRemove 删除文件/目录
    29  	OperationRemove = "删除文件/目录"
    30  	// OperationMkdir 创建目录
    31  	OperationMkdir = "创建目录"
    32  	// OperationRename 重命名文件/目录
    33  	OperationRename = "重命名文件/目录"
    34  	// OperationCopy 拷贝文件/目录
    35  	OperationCopy = "拷贝文件/目录"
    36  	// OperationMove 移动文件/目录
    37  	OperationMove = "移动文件/目录"
    38  	// OperationRapidUpload 秒传文件
    39  	OperationRapidUpload = "秒传文件"
    40  	// OperationUpload 上传单个文件
    41  	OperationUpload = "上传单个文件"
    42  	// OperationUploadTmpFile 分片上传—文件分片及上传
    43  	OperationUploadTmpFile = "分片上传—文件分片及上传"
    44  	// OperationUploadCreateSuperFile 分片上传—合并分片文件
    45  	OperationUploadCreateSuperFile = "分片上传—合并分片文件"
    46  	// OperationUploadPrecreate 分片上传—Precreate
    47  	OperationUploadPrecreate = "分片上传—Precreate"
    48  	// OperationUploadSuperfile2 分片上传—Superfile2
    49  	OperationUploadSuperfile2 = "分片上传—Superfile2"
    50  	// OperationDownloadFile 下载单个文件
    51  	OperationDownloadFile = "下载单个文件"
    52  	// OperationDownloadStreamFile 下载流式文件
    53  	OperationDownloadStreamFile = "下载流式文件"
    54  	// OperationLocateDownload 获取下载链接
    55  	OperationLocateDownload = "获取下载链接"
    56  	// OperationLocatePanAPIDownload 从百度网盘首页获取下载链接
    57  	OperationLocatePanAPIDownload = "获取下载链接2"
    58  	// OperationCloudDlAddTask 添加离线下载任务
    59  	OperationCloudDlAddTask = "添加离线下载任务"
    60  	// OperationCloudDlQueryTask 精确查询离线下载任务
    61  	OperationCloudDlQueryTask = "精确查询离线下载任务"
    62  	// OperationCloudDlListTask 查询离线下载任务列表
    63  	OperationCloudDlListTask = "查询离线下载任务列表"
    64  	// OperationCloudDlCancelTask 取消离线下载任务
    65  	OperationCloudDlCancelTask = "取消离线下载任务"
    66  	// OperationCloudDlDeleteTask 删除离线下载任务
    67  	OperationCloudDlDeleteTask = "删除离线下载任务"
    68  	// OperationCloudDlClearTask 清空离线下载任务记录
    69  	OperationCloudDlClearTask = "清空离线下载任务记录"
    70  	// OperationShareSet 创建分享链接
    71  	OperationShareSet = "创建分享链接"
    72  	// OperationShareCancel 取消分享
    73  	OperationShareCancel = "取消分享"
    74  	// OperationShareList 列出分享列表
    75  	OperationShareList = "列出分享列表"
    76  	// OperationShareSURLInfo 获取分享详细信息
    77  	OperationShareSURLInfo = "获取分享详细信息"
    78  	// OperationRecycleList 列出回收站文件列表
    79  	OperationRecycleList = "列出回收站文件列表"
    80  	// OperationRecycleRestore 还原回收站文件或目录
    81  	OperationRecycleRestore = "还原回收站文件或目录"
    82  	// OperationRecycleDelete 删除回收站文件或目录
    83  	OperationRecycleDelete = "删除回收站文件或目录"
    84  	// OperationRecycleClear 清空回收站
    85  	OperationRecycleClear = "清空回收站"
    86  
    87  	// OperationExportFileInfo 导出文件信息
    88  	OperationExportFileInfo = "导出文件信息"
    89  	// OperationGetRapidUploadInfo 获取文件秒传信息
    90  	OperationGetRapidUploadInfo = "获取文件秒传信息"
    91  	// OperationFixMD5 修复文件md5
    92  	OperationFixMD5 = "修复文件md5"
    93  	// OperrationMatchPathByShellPattern 通配符匹配文件路径
    94  	OperrationMatchPathByShellPattern = "通配符匹配文件路径"
    95  
    96  	// PCSBaiduCom pcs api地址
    97  	PCSBaiduCom = "pcs.baidu.com"
    98  	// PanBaiduCom 网盘首页api地址
    99  	PanBaiduCom = "pan.baidu.com"
   100  	// YunBaiduCom 网盘首页api地址2
   101  	YunBaiduCom = "yun.baidu.com"
   102  	// PanAppID 百度网盘appid
   103  	PanAppID = "250528"
   104  	// NetdiskUA 网盘客户端ua
   105  	NetdiskUA = "netdisk;2.2.51.6;netdisk;10.0.63;PC;android-android"
   106  	// DotBaiduCom .baidu.com
   107  	DotBaiduCom = ".baidu.com"
   108  	// PathSeparator 路径分隔符
   109  	PathSeparator = "/"
   110  )
   111  
   112  var (
   113  	baiduPCSVerbose = pcsverbose.New("BAIDUPCS")
   114  
   115  	baiduComURL = &url.URL{
   116  		Scheme: "http",
   117  		Host:   "baidu.com",
   118  	}
   119  
   120  	baiduPcsComURL = &url.URL{
   121  		Scheme: "http",
   122  		Host:   "baidupcs.com",
   123  	}
   124  )
   125  
   126  type (
   127  	// BaiduPCS 百度 PCS API 详情
   128  	BaiduPCS struct {
   129  		appID      int                   // app_id
   130  		isHTTPS    bool                  // 是否启用https
   131  		uid        uint64                // 百度uid
   132  		client     *requester.HTTPClient // http 客户端
   133  		pcsUA      string
   134  		panUA      string
   135  		isSetPanUA bool
   136  		ph         *panhome.PanHome
   137  		cacheOpMap cachemap.CacheOpMap
   138  	}
   139  
   140  	userInfoJSON struct {
   141  		*pcserror.PanErrorInfo
   142  		Records []struct {
   143  			Uk int64 `json:"uk"`
   144  		} `json:"records"`
   145  	}
   146  )
   147  
   148  // NewPCS 提供app_id, 百度BDUSS, 返回 BaiduPCS 对象
   149  func NewPCS(appID int, bduss string) *BaiduPCS {
   150  	client := requester.NewHTTPClient()
   151  	client.ResetCookiejar()
   152  	client.Jar.SetCookies(baiduComURL, []*http.Cookie{
   153  		&http.Cookie{
   154  			Name:   "BDUSS",
   155  			Value:  bduss,
   156  			Domain: DotBaiduCom,
   157  		},
   158  	})
   159  
   160  	return &BaiduPCS{
   161  		appID:  appID,
   162  		client: client,
   163  	}
   164  }
   165  
   166  // NewPCSWithClient 提供app_id, 自定义客户端, 返回 BaiduPCS 对象
   167  func NewPCSWithClient(appID int, client *requester.HTTPClient) *BaiduPCS {
   168  	pcs := &BaiduPCS{
   169  		appID:  appID,
   170  		client: client,
   171  	}
   172  	return pcs
   173  }
   174  
   175  // NewPCSWithCookieStr 提供app_id, cookie 字符串, 返回 BaiduPCS 对象
   176  func NewPCSWithCookieStr(appID int, cookieStr string) *BaiduPCS {
   177  	pcs := &BaiduPCS{
   178  		appID:  appID,
   179  		client: requester.NewHTTPClient(),
   180  	}
   181  
   182  	cookies := requester.ParseCookieStr(cookieStr)
   183  	for _, cookie := range cookies {
   184  		cookie.Domain = DotBaiduCom
   185  	}
   186  
   187  	jar, _ := cookiejar.New(nil)
   188  	jar.SetCookies(baiduComURL, cookies)
   189  	pcs.client.SetCookiejar(jar)
   190  
   191  	return pcs
   192  }
   193  
   194  func (pcs *BaiduPCS) lazyInit() {
   195  	if pcs.client == nil {
   196  		pcs.client = requester.NewHTTPClient()
   197  	}
   198  	if pcs.ph == nil {
   199  		pcs.ph = panhome.NewPanHome(pcs.client)
   200  	}
   201  	if !pcs.isSetPanUA {
   202  		pcs.panUA = NetdiskUA
   203  	}
   204  }
   205  
   206  // GetClient 获取当前的http client
   207  func (pcs *BaiduPCS) GetClient() *requester.HTTPClient {
   208  	pcs.lazyInit()
   209  	return pcs.client
   210  }
   211  
   212  // GetBDUSS 获取BDUSS
   213  func (pcs *BaiduPCS) GetBDUSS() (bduss string) {
   214  	if pcs.client == nil || pcs.client.Jar == nil {
   215  		return ""
   216  	}
   217  	cookies := pcs.client.Jar.Cookies(baiduComURL)
   218  	for _, cookie := range cookies {
   219  		if cookie.Name == "BDUSS" {
   220  			return cookie.Value
   221  		}
   222  	}
   223  	return ""
   224  }
   225  
   226  // SetAPPID 设置app_id
   227  func (pcs *BaiduPCS) SetAPPID(appID int) {
   228  	pcs.appID = appID
   229  }
   230  
   231  // SetUID 设置百度UID
   232  // 只有locatedownload才需要设置此项
   233  func (pcs *BaiduPCS) SetUID(uid uint64) {
   234  	pcs.uid = uid
   235  }
   236  
   237  // SetStoken 设置stoken
   238  func (pcs *BaiduPCS) SetStoken(stoken string) {
   239  	pcs.lazyInit()
   240  	if pcs.client.Jar == nil {
   241  		pcs.client.ResetCookiejar()
   242  	}
   243  
   244  	pcs.client.Jar.SetCookies(baiduComURL, []*http.Cookie{
   245  		&http.Cookie{
   246  			Name:   "STOKEN",
   247  			Value:  stoken,
   248  			Domain: DotBaiduCom,
   249  		},
   250  	})
   251  }
   252  
   253  // SetPCSUserAgent 设置 PCS User-Agent
   254  func (pcs *BaiduPCS) SetPCSUserAgent(ua string) {
   255  	pcs.pcsUA = ua
   256  }
   257  
   258  // SetPanUserAgent 设置 Pan User-Agent
   259  func (pcs *BaiduPCS) SetPanUserAgent(ua string) {
   260  	pcs.panUA = ua
   261  	pcs.isSetPanUA = true
   262  }
   263  
   264  // SetHTTPS 是否启用https连接
   265  func (pcs *BaiduPCS) SetHTTPS(https bool) {
   266  	pcs.isHTTPS = https
   267  }
   268  
   269  // URL 返回 url
   270  func (pcs *BaiduPCS) URL() *url.URL {
   271  	return &url.URL{
   272  		Scheme: GetHTTPScheme(pcs.isHTTPS),
   273  		Host:   PCSBaiduCom,
   274  	}
   275  }
   276  
   277  func (pcs *BaiduPCS) getPanUAHeader() (header map[string]string) {
   278  	return map[string]string{
   279  		"User-Agent": pcs.panUA,
   280  	}
   281  }
   282  
   283  func (pcs *BaiduPCS) generatePCSURL(subPath, method string, param ...map[string]string) *url.URL {
   284  	pcsURL := pcs.URL()
   285  	pcsURL.Path = "/rest/2.0/pcs/" + subPath
   286  
   287  	uv := pcsURL.Query()
   288  	uv.Set("app_id", strconv.Itoa(pcs.appID))
   289  	uv.Set("method", method)
   290  	for k := range param {
   291  		for k2 := range param[k] {
   292  			uv.Set(k2, param[k][k2])
   293  		}
   294  	}
   295  
   296  	pcsURL.RawQuery = uv.Encode()
   297  	return pcsURL
   298  }
   299  
   300  func (pcs *BaiduPCS) generatePCSURL2(subPath, method string, param ...map[string]string) *url.URL {
   301  	pcsURL2 := &url.URL{
   302  		Scheme: GetHTTPScheme(pcs.isHTTPS),
   303  		Host:   PanBaiduCom,
   304  		Path:   "/rest/2.0/" + subPath,
   305  	}
   306  
   307  	uv := pcsURL2.Query()
   308  	uv.Set("app_id", PanAppID)
   309  	uv.Set("method", method)
   310  	for k := range param {
   311  		for k2 := range param[k] {
   312  			uv.Set(k2, param[k][k2])
   313  		}
   314  	}
   315  
   316  	pcsURL2.RawQuery = uv.Encode()
   317  	return pcsURL2
   318  }
   319  
   320  func (pcs *BaiduPCS) generatePanURL(subPath string, param map[string]string) *url.URL {
   321  	panURL := url.URL{
   322  		Scheme: GetHTTPScheme(pcs.isHTTPS),
   323  		Host:   PanBaiduCom,
   324  		Path:   "/api/" + subPath,
   325  	}
   326  
   327  	if param != nil {
   328  		uv := url.Values{}
   329  		for k := range param {
   330  			uv.Set(k, param[k])
   331  		}
   332  		panURL.RawQuery = uv.Encode()
   333  	}
   334  	return &panURL
   335  }
   336  
   337  // UK 获取用户 UK
   338  func (pcs *BaiduPCS) UK() (uk int64, pcsError pcserror.Error) {
   339  	dataReadCloser, pcsError := pcs.PrepareUK()
   340  	if pcsError != nil {
   341  		return
   342  	}
   343  
   344  	defer dataReadCloser.Close()
   345  
   346  	errInfo := pcserror.NewPanErrorInfo(OperationGetUK)
   347  	jsonData := userInfoJSON{
   348  		PanErrorInfo: errInfo,
   349  	}
   350  
   351  	pcsError = pcserror.HandleJSONParse(OperationGetUK, dataReadCloser, &jsonData)
   352  	if pcsError != nil {
   353  		return
   354  	}
   355  
   356  	if len(jsonData.Records) != 1 {
   357  		errInfo.ErrType = pcserror.ErrTypeOthers
   358  		errInfo.Err = errors.New("Unknown remote data")
   359  		return 0, errInfo
   360  	}
   361  
   362  	return jsonData.Records[0].Uk, nil
   363  }