diff --git a/drivers/139/driver.go b/drivers/139/driver.go index 69ab68f705e..9d8cbd523e6 100644 --- a/drivers/139/driver.go +++ b/drivers/139/driver.go @@ -35,25 +35,40 @@ func (d *Yun139) Init(ctx context.Context) error { if d.Authorization == "" { return fmt.Errorf("authorization is empty") } - decode, err := base64.StdEncoding.DecodeString(d.Authorization) - if err != nil { + switch d.Addition.Type { + case MetaPersonalNew: + if len(d.Addition.RootFolderID) == 0 { + d.RootFolderID = "/" + } + return nil + case MetaPersonal: + if len(d.Addition.RootFolderID) == 0 { + d.RootFolderID = "root" + } + fallthrough + case MetaFamily: + decode, err := base64.StdEncoding.DecodeString(d.Authorization) + if err != nil { + return err + } + decodeStr := string(decode) + splits := strings.Split(decodeStr, ":") + if len(splits) < 2 { + return fmt.Errorf("authorization is invalid, splits < 2") + } + d.Account = splits[1] + _, err = d.post("/orchestration/personalCloud/user/v1.0/qryUserExternInfo", base.Json{ + "qryUserExternInfoReq": base.Json{ + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, + }, + }, nil) return err + default: + return errs.NotImplement } - decodeStr := string(decode) - splits := strings.Split(decodeStr, ":") - if len(splits) < 2 { - return fmt.Errorf("authorization is invalid, splits < 2") - } - d.Account = splits[1] - _, err = d.post("/orchestration/personalCloud/user/v1.0/qryUserExternInfo", base.Json{ - "qryUserExternInfoReq": base.Json{ - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, - }, - }, - }, nil) - return err } func (d *Yun139) Drop(ctx context.Context) error { @@ -61,35 +76,65 @@ func (d *Yun139) Drop(ctx context.Context) error { } func (d *Yun139) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { - if d.isFamily() { - return d.familyGetFiles(dir.GetID()) - } else { + switch d.Addition.Type { + case MetaPersonalNew: + return d.personalGetFiles(dir.GetID()) + case MetaPersonal: return d.getFiles(dir.GetID()) + case MetaFamily: + return d.familyGetFiles(dir.GetID()) + default: + return nil, errs.NotImplement } } func (d *Yun139) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - u, err := d.getLink(file.GetID()) + var url string + var err error + switch d.Addition.Type { + case MetaPersonalNew: + url, err = d.personalGetLink(file.GetID()) + case MetaPersonal: + fallthrough + case MetaFamily: + url, err = d.getLink(file.GetID()) + default: + return nil, errs.NotImplement + } if err != nil { return nil, err } - return &model.Link{URL: u}, nil + return &model.Link{URL: url}, nil } func (d *Yun139) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { - data := base.Json{ - "createCatalogExtReq": base.Json{ - "parentCatalogID": parentDir.GetID(), - "newCatalogName": dirName, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, + var err error + switch d.Addition.Type { + case MetaPersonalNew: + data := base.Json{ + "parentFileId": parentDir.GetID(), + "name": dirName, + "description": "", + "type": "folder", + "fileRenameMode": "force_rename", + } + pathname := "/hcy/file/create" + _, err = d.personalPost(pathname, data, nil) + case MetaPersonal: + data := base.Json{ + "createCatalogExtReq": base.Json{ + "parentCatalogID": parentDir.GetID(), + "newCatalogName": dirName, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, }, - }, - } - pathname := "/orchestration/personalCloud/catalog/v1.0/createCatalogExt" - if d.isFamily() { - data = base.Json{ + } + pathname := "/orchestration/personalCloud/catalog/v1.0/createCatalogExt" + _, err = d.post(pathname, data, nil) + case MetaFamily: + data := base.Json{ "cloudID": d.CloudID, "commonAccountInfo": base.Json{ "account": d.Account, @@ -97,147 +142,198 @@ func (d *Yun139) MakeDir(ctx context.Context, parentDir model.Obj, dirName strin }, "docLibName": dirName, } - pathname = "/orchestration/familyCloud/cloudCatalog/v1.0/createCloudDoc" + pathname := "/orchestration/familyCloud/cloudCatalog/v1.0/createCloudDoc" + _, err = d.post(pathname, data, nil) + default: + err = errs.NotImplement } - _, err := d.post(pathname, data, nil) return err } func (d *Yun139) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) { - if d.isFamily() { - return nil, errs.NotImplement - } - var contentInfoList []string - var catalogInfoList []string - if srcObj.IsDir() { - catalogInfoList = append(catalogInfoList, srcObj.GetID()) - } else { - contentInfoList = append(contentInfoList, srcObj.GetID()) - } - data := base.Json{ - "createBatchOprTaskReq": base.Json{ - "taskType": 3, - "actionType": "304", - "taskInfo": base.Json{ - "contentInfoList": contentInfoList, - "catalogInfoList": catalogInfoList, - "newCatalogID": dstDir.GetID(), - }, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, + switch d.Addition.Type { + case MetaPersonalNew: + data := base.Json{ + "fileIds": []string{srcObj.GetID()}, + "toParentFileId": dstDir.GetID(), + } + pathname := "/hcy/file/batchMove" + _, err := d.personalPost(pathname, data, nil) + if err != nil { + return nil, err + } + return srcObj, nil + case MetaPersonal: + var contentInfoList []string + var catalogInfoList []string + if srcObj.IsDir() { + catalogInfoList = append(catalogInfoList, srcObj.GetID()) + } else { + contentInfoList = append(contentInfoList, srcObj.GetID()) + } + data := base.Json{ + "createBatchOprTaskReq": base.Json{ + "taskType": 3, + "actionType": "304", + "taskInfo": base.Json{ + "contentInfoList": contentInfoList, + "catalogInfoList": catalogInfoList, + "newCatalogID": dstDir.GetID(), + }, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, }, - }, - } - pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask" - _, err := d.post(pathname, data, nil) - if err != nil { - return nil, err + } + pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask" + _, err := d.post(pathname, data, nil) + if err != nil { + return nil, err + } + return srcObj, nil + default: + return nil, errs.NotImplement } - return srcObj, nil } func (d *Yun139) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - if d.isFamily() { - return errs.NotImplement - } - var data base.Json - var pathname string - if srcObj.IsDir() { - data = base.Json{ - "catalogID": srcObj.GetID(), - "catalogName": newName, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, - }, + var err error + switch d.Addition.Type { + case MetaPersonalNew: + data := base.Json{ + "fileId": srcObj.GetID(), + "name": newName, + "description": "", } - pathname = "/orchestration/personalCloud/catalog/v1.0/updateCatalogInfo" - } else { - data = base.Json{ - "contentID": srcObj.GetID(), - "contentName": newName, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, - }, + pathname := "/hcy/file/update" + _, err = d.personalPost(pathname, data, nil) + case MetaPersonal: + var data base.Json + var pathname string + if srcObj.IsDir() { + data = base.Json{ + "catalogID": srcObj.GetID(), + "catalogName": newName, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, + } + pathname = "/orchestration/personalCloud/catalog/v1.0/updateCatalogInfo" + } else { + data = base.Json{ + "contentID": srcObj.GetID(), + "contentName": newName, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, + } + pathname = "/orchestration/personalCloud/content/v1.0/updateContentInfo" } - pathname = "/orchestration/personalCloud/content/v1.0/updateContentInfo" + _, err = d.post(pathname, data, nil) + default: + err = errs.NotImplement } - _, err := d.post(pathname, data, nil) return err } func (d *Yun139) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - if d.isFamily() { - return errs.NotImplement - } - var contentInfoList []string - var catalogInfoList []string - if srcObj.IsDir() { - catalogInfoList = append(catalogInfoList, srcObj.GetID()) - } else { - contentInfoList = append(contentInfoList, srcObj.GetID()) - } - data := base.Json{ - "createBatchOprTaskReq": base.Json{ - "taskType": 3, - "actionType": 309, - "taskInfo": base.Json{ - "contentInfoList": contentInfoList, - "catalogInfoList": catalogInfoList, - "newCatalogID": dstDir.GetID(), - }, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, + var err error + switch d.Addition.Type { + case MetaPersonalNew: + data := base.Json{ + "fileIds": []string{srcObj.GetID()}, + "toParentFileId": dstDir.GetID(), + } + pathname := "/hcy/file/batchCopy" + _, err := d.personalPost(pathname, data, nil) + return err + case MetaPersonal: + var contentInfoList []string + var catalogInfoList []string + if srcObj.IsDir() { + catalogInfoList = append(catalogInfoList, srcObj.GetID()) + } else { + contentInfoList = append(contentInfoList, srcObj.GetID()) + } + data := base.Json{ + "createBatchOprTaskReq": base.Json{ + "taskType": 3, + "actionType": 309, + "taskInfo": base.Json{ + "contentInfoList": contentInfoList, + "catalogInfoList": catalogInfoList, + "newCatalogID": dstDir.GetID(), + }, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, }, - }, + } + pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask" + _, err = d.post(pathname, data, nil) + default: + err = errs.NotImplement } - pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask" - _, err := d.post(pathname, data, nil) return err } func (d *Yun139) Remove(ctx context.Context, obj model.Obj) error { - var contentInfoList []string - var catalogInfoList []string - if obj.IsDir() { - catalogInfoList = append(catalogInfoList, obj.GetID()) - } else { - contentInfoList = append(contentInfoList, obj.GetID()) - } - data := base.Json{ - "createBatchOprTaskReq": base.Json{ - "taskType": 2, - "actionType": 201, - "taskInfo": base.Json{ - "newCatalogID": "", - "contentInfoList": contentInfoList, - "catalogInfoList": catalogInfoList, - }, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, - }, - }, - } - pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask" - if d.isFamily() { - data = base.Json{ - "catalogList": catalogInfoList, - "contentList": contentInfoList, - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, + switch d.Addition.Type { + case MetaPersonalNew: + data := base.Json{ + "fileIds": []string{obj.GetID()}, + } + pathname := "/hcy/recyclebin/batchTrash" + _, err := d.personalPost(pathname, data, nil) + return err + case MetaPersonal: + fallthrough + case MetaFamily: + var contentInfoList []string + var catalogInfoList []string + if obj.IsDir() { + catalogInfoList = append(catalogInfoList, obj.GetID()) + } else { + contentInfoList = append(contentInfoList, obj.GetID()) + } + data := base.Json{ + "createBatchOprTaskReq": base.Json{ + "taskType": 2, + "actionType": 201, + "taskInfo": base.Json{ + "newCatalogID": "", + "contentInfoList": contentInfoList, + "catalogInfoList": catalogInfoList, + }, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, }, - "sourceCatalogType": 1002, - "taskType": 2, } - pathname = "/orchestration/familyCloud/batchOprTask/v1.0/createBatchOprTask" + pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask" + if d.isFamily() { + data = base.Json{ + "catalogList": catalogInfoList, + "contentList": contentInfoList, + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, + "sourceCatalogType": 1002, + "taskType": 2, + } + pathname = "/orchestration/familyCloud/batchOprTask/v1.0/createBatchOprTask" + } + _, err := d.post(pathname, data, nil) + return err + default: + return errs.NotImplement } - _, err := d.post(pathname, data, nil) - return err } const ( @@ -257,94 +353,208 @@ func getPartSize(size int64) int64 { } func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { - data := base.Json{ - "manualRename": 2, - "operation": 0, - "fileCount": 1, - "totalSize": 0, // 去除上传大小限制 - "uploadContentList": []base.Json{{ - "contentName": stream.GetName(), - "contentSize": 0, // 去除上传大小限制 - // "digest": "5a3231986ce7a6b46e408612d385bafa" - }}, - "parentCatalogID": dstDir.GetID(), - "newCatalogName": "", - "commonAccountInfo": base.Json{ - "account": d.Account, - "accountType": 1, - }, - } - pathname := "/orchestration/personalCloud/uploadAndDownload/v1.0/pcUploadFileRequest" - if d.isFamily() { - data = d.newJson(base.Json{ - "fileCount": 1, - "manualRename": 2, - "operation": 0, - "path": "", - "seqNo": "", - "totalSize": 0, - "uploadContentList": []base.Json{{ - "contentName": stream.GetName(), - "contentSize": 0, - // "digest": "5a3231986ce7a6b46e408612d385bafa" + switch d.Addition.Type { + case MetaPersonalNew: + var err error + fullHash := stream.GetHash().GetHash(utils.SHA256) + if len(fullHash) <= 0 { + tmpF, err := stream.CacheFullInTempFile() + if err != nil { + return err + } + fullHash, err = utils.HashFile(utils.SHA256, tmpF) + if err != nil { + return err + } + } + // return errs.NotImplement + data := base.Json{ + "contentHash": fullHash, + "contentHashAlgorithm": "SHA256", + "contentType": "application/octet-stream", + "parallelUpload": false, + "partInfos": []base.Json{{ + "parallelHashCtx": base.Json{ + "partOffset": 0, + }, + "partNumber": 1, + "partSize": stream.GetSize(), }}, - }) - pathname = "/orchestration/familyCloud/content/v1.0/getFileUploadURL" - return errs.NotImplement - } - var resp UploadResp - _, err := d.post(pathname, data, &resp) - if err != nil { - return err - } - - // Progress - p := driver.NewProgress(stream.GetSize(), up) - - var partSize = getPartSize(stream.GetSize()) - part := (stream.GetSize() + partSize - 1) / partSize - if part == 0 { - part = 1 - } - for i := int64(0); i < part; i++ { - if utils.IsCanceled(ctx) { - return ctx.Err() + "size": stream.GetSize(), + "parentFileId": dstDir.GetID(), + "name": stream.GetName(), + "type": "file", + "fileRenameMode": "auto_rename", + } + pathname := "/hcy/file/create" + var resp PersonalUploadResp + _, err = d.personalPost(pathname, data, &resp) + if err != nil { + return err } - start := i * partSize - byteSize := stream.GetSize() - start - if byteSize > partSize { - byteSize = partSize + if resp.Data.Exist || resp.Data.RapidUpload { + return nil } - limitReader := io.LimitReader(stream, byteSize) + // Progress + p := driver.NewProgress(stream.GetSize(), up) + // Update Progress - r := io.TeeReader(limitReader, p) - req, err := http.NewRequest("POST", resp.Data.UploadResult.RedirectionURL, r) + r := io.TeeReader(stream, p) + + req, err := http.NewRequest("PUT", resp.Data.PartInfos[0].UploadUrl, r) if err != nil { return err } - req = req.WithContext(ctx) - req.Header.Set("Content-Type", "text/plain;name="+unicode(stream.GetName())) - req.Header.Set("contentSize", strconv.FormatInt(stream.GetSize(), 10)) - req.Header.Set("range", fmt.Sprintf("bytes=%d-%d", start, start+byteSize-1)) - req.Header.Set("uploadtaskID", resp.Data.UploadResult.UploadTaskID) - req.Header.Set("rangeType", "0") - req.ContentLength = byteSize + req.Header.Set("Content-Type", "application/octet-stream") + req.Header.Set("Content-Length", fmt.Sprint(stream.GetSize())) + req.Header.Set("Origin", "https://yun.139.com") + req.Header.Set("Referer", "https://yun.139.com/") + req.ContentLength = stream.GetSize() res, err := base.HttpClient.Do(req) if err != nil { return err } + _ = res.Body.Close() log.Debugf("%+v", res) if res.StatusCode != http.StatusOK { return fmt.Errorf("unexpected status code: %d", res.StatusCode) } + + data = base.Json{ + "contentHash": fullHash, + "contentHashAlgorithm": "SHA256", + "fileId": resp.Data.FileId, + "uploadId": resp.Data.UploadId, + } + _, err = d.personalPost("/hcy/file/complete", data, nil) + if err != nil { + return err + } + return nil + case MetaPersonal: + fallthrough + case MetaFamily: + data := base.Json{ + "manualRename": 2, + "operation": 0, + "fileCount": 1, + "totalSize": 0, // 去除上传大小限制 + "uploadContentList": []base.Json{{ + "contentName": stream.GetName(), + "contentSize": 0, // 去除上传大小限制 + // "digest": "5a3231986ce7a6b46e408612d385bafa" + }}, + "parentCatalogID": dstDir.GetID(), + "newCatalogName": "", + "commonAccountInfo": base.Json{ + "account": d.Account, + "accountType": 1, + }, + } + pathname := "/orchestration/personalCloud/uploadAndDownload/v1.0/pcUploadFileRequest" + if d.isFamily() { + // data = d.newJson(base.Json{ + // "fileCount": 1, + // "manualRename": 2, + // "operation": 0, + // "path": "", + // "seqNo": "", + // "totalSize": 0, + // "uploadContentList": []base.Json{{ + // "contentName": stream.GetName(), + // "contentSize": 0, + // // "digest": "5a3231986ce7a6b46e408612d385bafa" + // }}, + // }) + // pathname = "/orchestration/familyCloud/content/v1.0/getFileUploadURL" + return errs.NotImplement + } + var resp UploadResp + _, err := d.post(pathname, data, &resp) + if err != nil { + return err + } + + // Progress + p := driver.NewProgress(stream.GetSize(), up) + + var partSize = getPartSize(stream.GetSize()) + part := (stream.GetSize() + partSize - 1) / partSize + if part == 0 { + part = 1 + } + for i := int64(0); i < part; i++ { + if utils.IsCanceled(ctx) { + return ctx.Err() + } + + start := i * partSize + byteSize := stream.GetSize() - start + if byteSize > partSize { + byteSize = partSize + } + + limitReader := io.LimitReader(stream, byteSize) + // Update Progress + r := io.TeeReader(limitReader, p) + req, err := http.NewRequest("POST", resp.Data.UploadResult.RedirectionURL, r) + if err != nil { + return err + } + + req = req.WithContext(ctx) + req.Header.Set("Content-Type", "text/plain;name="+unicode(stream.GetName())) + req.Header.Set("contentSize", strconv.FormatInt(stream.GetSize(), 10)) + req.Header.Set("range", fmt.Sprintf("bytes=%d-%d", start, start+byteSize-1)) + req.Header.Set("uploadtaskID", resp.Data.UploadResult.UploadTaskID) + req.Header.Set("rangeType", "0") + req.ContentLength = byteSize + + res, err := base.HttpClient.Do(req) + if err != nil { + return err + } + _ = res.Body.Close() + log.Debugf("%+v", res) + if res.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code: %d", res.StatusCode) + } + } + + return nil + default: + return errs.NotImplement } +} - return nil +func (d *Yun139) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { + switch d.Addition.Type { + case MetaPersonalNew: + var resp base.Json + var uri string + data := base.Json{ + "category": "video", + "fileId": args.Obj.GetID(), + } + switch args.Method { + case "video_preview": + uri = "/hcy/videoPreview/getPreviewInfo" + default: + return nil, errs.NotSupport + } + _, err := d.personalPost(uri, data, &resp) + if err != nil { + return nil, err + } + return resp["data"], nil + default: + return nil, errs.NotImplement + } } var _ driver.Driver = (*Yun139)(nil) diff --git a/drivers/139/meta.go b/drivers/139/meta.go index 273ba14876d..416e63a796c 100644 --- a/drivers/139/meta.go +++ b/drivers/139/meta.go @@ -9,7 +9,7 @@ type Addition struct { //Account string `json:"account" required:"true"` Authorization string `json:"authorization" type:"text" required:"true"` driver.RootID - Type string `json:"type" type:"select" options:"personal,family" default:"personal"` + Type string `json:"type" type:"select" options:"personal,family,personal_new" default:"personal"` CloudID string `json:"cloud_id"` } diff --git a/drivers/139/types.go b/drivers/139/types.go index 217aeb9f497..841aa9d3871 100644 --- a/drivers/139/types.go +++ b/drivers/139/types.go @@ -1,5 +1,11 @@ package _139 +const ( + MetaPersonal string = "personal" + MetaFamily string = "family" + MetaPersonalNew string = "personal_new" +) + type BaseResp struct { Success bool `json:"success"` Code string `json:"code"` @@ -185,3 +191,42 @@ type QueryContentListResp struct { RecallContent interface{} `json:"recallContent"` } `json:"data"` } + +type PersonalThumbnail struct { + Style string `json:"style"` + Url string `json:"url"` +} + +type PersonalFileItem struct { + FileId string `json:"fileId"` + Name string `json:"name"` + Size int64 `json:"size"` + Type string `json:"type"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` + Thumbnails []PersonalThumbnail `json:"thumbnailUrls"` +} + +type PersonalListResp struct { + BaseResp + Data struct { + Items []PersonalFileItem `json:"items"` + NextPageCursor string `json:"nextPageCursor"` + } +} + +type PersonalPartInfo struct { + PartNumber int `json:"partNumber"` + UploadUrl string `json:"uploadUrl"` +} + +type PersonalUploadResp struct { + BaseResp + Data struct { + FileId string `json:"fileId"` + PartInfos []PersonalPartInfo `json:"partInfos"` + Exist bool `json:"exist"` + RapidUpload bool `json:"rapidUpload"` + UploadId string `json:"uploadId"` + } +} diff --git a/drivers/139/util.go b/drivers/139/util.go index 0f26b149955..a3627b6c8ae 100644 --- a/drivers/139/util.go +++ b/drivers/139/util.go @@ -252,3 +252,154 @@ func unicode(str string) string { textUnquoted := textQuoted[1 : len(textQuoted)-1] return textUnquoted } + +func (d *Yun139) personalRequest(pathname string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) { + url := "https://personal-kd-njs.yun.139.com" + pathname + req := base.RestyClient.R() + randStr := random.String(16) + ts := time.Now().Format("2006-01-02 15:04:05") + if callback != nil { + callback(req) + } + body, err := utils.Json.Marshal(req.Body) + if err != nil { + return nil, err + } + sign := calSign(string(body), ts, randStr) + svcType := "1" + if d.isFamily() { + svcType = "2" + } + req.SetHeaders(map[string]string{ + "Accept": "application/json, text/plain, */*", + "Authorization": "Basic " + d.Authorization, + "Caller": "web", + "Cms-Device": "default", + "Mcloud-Channel": "1000101", + "Mcloud-Client": "10701", + "Mcloud-Route": "001", + "Mcloud-Sign": fmt.Sprintf("%s,%s,%s", ts, randStr, sign), + "Mcloud-Version": "7.13.0", + "Origin": "https://yun.139.com", + "Referer": "https://yun.139.com/w/", + "x-DeviceInfo": "||9|7.13.0|chrome|120.0.0.0|||windows 10||zh-CN|||", + "x-huawei-channelSrc": "10000034", + "x-inner-ntwk": "2", + "x-m4c-caller": "PC", + "x-m4c-src": "10002", + "x-SvcType": svcType, + "X-Yun-Api-Version": "v1", + "X-Yun-App-Channel": "10000034", + "X-Yun-Channel-Source": "10000034", + "X-Yun-Client-Info": "||9|7.13.0|chrome|120.0.0.0|||windows 10||zh-CN|||dW5kZWZpbmVk||", + "X-Yun-Module-Type": "100", + "X-Yun-Svc-Type": "1", + }) + + var e BaseResp + req.SetResult(&e) + res, err := req.Execute(method, url) + if err != nil { + return nil, err + } + log.Debugln(res.String()) + if !e.Success { + return nil, errors.New(e.Message) + } + if resp != nil { + err = utils.Json.Unmarshal(res.Body(), resp) + if err != nil { + return nil, err + } + } + return res.Body(), nil +} +func (d *Yun139) personalPost(pathname string, data interface{}, resp interface{}) ([]byte, error) { + return d.personalRequest(pathname, http.MethodPost, func(req *resty.Request) { + req.SetBody(data) + }, resp) +} + +func getPersonalTime(t string) time.Time { + stamp, err := time.ParseInLocation("2006-01-02T15:04:05.999-07:00", t, utils.CNLoc) + if err != nil { + panic(err) + } + return stamp +} + +func (d *Yun139) personalGetFiles(fileId string) ([]model.Obj, error) { + files := make([]model.Obj, 0) + nextPageCursor := "" + for { + data := base.Json{ + "imageThumbnailStyleList": []string{"Small", "Large"}, + "orderBy": "updated_at", + "orderDirection": "DESC", + "pageInfo": base.Json{ + "pageCursor": nextPageCursor, + "pageSize": 100, + }, + "parentFileId": fileId, + } + var resp PersonalListResp + _, err := d.personalPost("/hcy/file/list", data, &resp) + if err != nil { + return nil, err + } + nextPageCursor = resp.Data.NextPageCursor + for _, item := range resp.Data.Items { + var isFolder = (item.Type == "folder") + var f model.Obj + if isFolder { + f = &model.Object{ + ID: item.FileId, + Name: item.Name, + Size: 0, + Modified: getPersonalTime(item.UpdatedAt), + Ctime: getPersonalTime(item.CreatedAt), + IsFolder: isFolder, + } + } else { + var Thumbnails = item.Thumbnails + var ThumbnailUrl string + if len(Thumbnails) > 0 { + ThumbnailUrl = Thumbnails[len(Thumbnails)-1].Url + } + f = &model.ObjThumb{ + Object: model.Object{ + ID: item.FileId, + Name: item.Name, + Size: item.Size, + Modified: getPersonalTime(item.UpdatedAt), + Ctime: getPersonalTime(item.CreatedAt), + IsFolder: isFolder, + }, + Thumbnail: model.Thumbnail{Thumbnail: ThumbnailUrl}, + } + } + files = append(files, f) + } + if len(nextPageCursor) == 0 { + break + } + } + return files, nil +} + +func (d *Yun139) personalGetLink(fileId string) (string, error) { + data := base.Json{ + "fileId": fileId, + } + res, err := d.personalPost("/hcy/file/getDownloadUrl", + data, nil) + if err != nil { + return "", err + } + var cdnUrl = jsoniter.Get(res, "data", "cdnUrl").ToString() + if cdnUrl != "" { + return cdnUrl, nil + } else { + return jsoniter.Get(res, "data", "url").ToString(), nil + } +}