mirror of https://github.com/Xhofe/alist
✨ 139yun personal support
parent
db58dabd31
commit
036373032c
|
@ -0,0 +1,168 @@
|
|||
package _39
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/drivers/base"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
"github.com/go-resty/resty/v2"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (driver Cloud139) Request(pathname string, method int, headers, query, form map[string]string, data interface{}, resp interface{}, account *model.Account) ([]byte, error) {
|
||||
url := "https://yun.139.com" + pathname
|
||||
req := base.RestyClient.R()
|
||||
randStr := randomStr(16)
|
||||
ts := time.Now().Format("2006-01-02 15:04:05")
|
||||
body, err := utils.Json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sign := calSign(string(body), ts, randStr)
|
||||
req.SetHeaders(map[string]string{
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"CMS-DEVICE": "default",
|
||||
"Cookie": account.AccessToken,
|
||||
"mcloud-channel": "1000101",
|
||||
"mcloud-client": "10701",
|
||||
//"mcloud-route": "001",
|
||||
"mcloud-sign": fmt.Sprintf("%s,%s,%s", ts, randStr, sign),
|
||||
//"mcloud-skey":"",
|
||||
"mcloud-version": "6.6.0",
|
||||
"Origin": "https://yun.139.com",
|
||||
"Referer": "https://yun.139.com/w/",
|
||||
"x-DeviceInfo": "||9|6.6.0|chrome|95.0.4638.69|uwIy75obnsRPIwlJSd7D9GhUvFwG96ce||macos 10.15.2||zh-CN|||",
|
||||
"x-huawei-channelSrc": "10000034",
|
||||
"x-inner-ntwk": "2",
|
||||
"x-m4c-caller": "PC",
|
||||
"x-m4c-src": "10002",
|
||||
"x-SvcType": "1",
|
||||
})
|
||||
if headers != nil {
|
||||
req.SetHeaders(headers)
|
||||
}
|
||||
if query != nil {
|
||||
req.SetQueryParams(query)
|
||||
}
|
||||
if form != nil {
|
||||
req.SetFormData(form)
|
||||
}
|
||||
if data != nil {
|
||||
req.SetBody(data)
|
||||
}
|
||||
var e BaseResp
|
||||
//var err error
|
||||
var res *resty.Response
|
||||
req.SetResult(&e)
|
||||
switch method {
|
||||
case base.Get:
|
||||
res, err = req.Get(url)
|
||||
case base.Post:
|
||||
res, err = req.Post(url)
|
||||
case base.Delete:
|
||||
res, err = req.Delete(url)
|
||||
case base.Patch:
|
||||
res, err = req.Patch(url)
|
||||
case base.Put:
|
||||
res, err = req.Put(url)
|
||||
default:
|
||||
return nil, base.ErrNotSupport
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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 (driver Cloud139) Post(pathname string, data interface{}, resp interface{}, account *model.Account) ([]byte, error) {
|
||||
return driver.Request(pathname, base.Post, nil, nil, nil, data, resp, account)
|
||||
}
|
||||
|
||||
func (driver Cloud139) GetFiles(catalogID string, account *model.Account) ([]model.File, error) {
|
||||
start := 0
|
||||
limit := 100
|
||||
files := make([]model.File, 0)
|
||||
for {
|
||||
data := base.Json{
|
||||
"catalogID": catalogID,
|
||||
"sortDirection": 1,
|
||||
"startNumber": start + 1,
|
||||
"endNumber": start + limit,
|
||||
"filterType": 0,
|
||||
"catalogSortType": 0,
|
||||
"contentSortType": 0,
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": account.Username,
|
||||
"accountType": 1,
|
||||
},
|
||||
}
|
||||
var resp GetDiskResp
|
||||
_, err := driver.Post("/orchestration/personalCloud/catalog/v1.0/getDisk", data, &resp, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, catalog := range resp.Data.GetDiskResult.CatalogList {
|
||||
f := model.File{
|
||||
Id: catalog.CatalogID,
|
||||
Name: catalog.CatalogName,
|
||||
Size: 0,
|
||||
Type: conf.FOLDER,
|
||||
Driver: driver.Config().Name,
|
||||
UpdatedAt: getTime(catalog.UpdateTime),
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
for _, content := range resp.Data.GetDiskResult.ContentList {
|
||||
f := model.File{
|
||||
Id: content.ContentID,
|
||||
Name: content.ContentName,
|
||||
Size: int64(content.ContentSize),
|
||||
Type: utils.GetFileType(path.Ext(content.ContentName)),
|
||||
Driver: driver.Config().Name,
|
||||
UpdatedAt: getTime(content.UpdateTime),
|
||||
Thumbnail: content.ThumbnailURL,
|
||||
//Thumbnail: content.BigthumbnailURL,
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
if start+limit >= resp.Data.GetDiskResult.NodeCount {
|
||||
break
|
||||
}
|
||||
start += limit
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (driver Cloud139) GetLink(contentId string, account *model.Account) (string, error) {
|
||||
data := base.Json{
|
||||
"appName": "",
|
||||
"contentID": contentId,
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
}
|
||||
res, err := driver.Post("/orchestration/personalCloud/uploadAndDownload/v1.0/downloadRequest",
|
||||
data, nil, account)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return jsoniter.Get(res, "data", "downloadURL").ToString(), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
base.RegisterDriver(&Cloud139{})
|
||||
}
|
|
@ -0,0 +1,383 @@
|
|||
package _39
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/drivers/base"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Cloud139 struct{}
|
||||
|
||||
func (driver Cloud139) Config() base.DriverConfig {
|
||||
return base.DriverConfig{
|
||||
Name: "139Yun",
|
||||
LocalSort: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (driver Cloud139) Items() []base.Item {
|
||||
return []base.Item{
|
||||
{
|
||||
Name: "username",
|
||||
Label: "phone",
|
||||
Type: base.TypeString,
|
||||
Required: true,
|
||||
Description: "phone number",
|
||||
},
|
||||
{
|
||||
Name: "access_token",
|
||||
Label: "Cookie",
|
||||
Type: base.TypeString,
|
||||
Required: true,
|
||||
Description: "Unknown expiration time",
|
||||
},
|
||||
{
|
||||
Name: "internal_type",
|
||||
Label: "139yun type",
|
||||
Type: base.TypeSelect,
|
||||
Required: true,
|
||||
Values: "Personal,Family",
|
||||
},
|
||||
{
|
||||
Name: "root_folder",
|
||||
Label: "root folder file_id",
|
||||
Type: base.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (driver Cloud139) Save(account *model.Account, old *model.Account) error {
|
||||
_, err := driver.Request("/orchestration/personalCloud/user/v1.0/qryUserExternInfo", base.Post, nil, nil, nil, base.Json{
|
||||
"qryUserExternInfoReq": base.Json{
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": account.Username,
|
||||
"accountType": 1,
|
||||
},
|
||||
},
|
||||
}, nil, account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Cloud139) File(path string, account *model.Account) (*model.File, error) {
|
||||
path = utils.ParsePath(path)
|
||||
if path == "/" {
|
||||
return &model.File{
|
||||
Id: account.RootFolder,
|
||||
Name: account.Name,
|
||||
Size: 0,
|
||||
Type: conf.FOLDER,
|
||||
Driver: driver.Config().Name,
|
||||
UpdatedAt: account.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
dir, name := filepath.Split(path)
|
||||
files, err := driver.Files(dir, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.Name == name {
|
||||
return &file, nil
|
||||
}
|
||||
}
|
||||
return nil, base.ErrPathNotFound
|
||||
}
|
||||
|
||||
func (driver Cloud139) Files(path string, account *model.Account) ([]model.File, error) {
|
||||
path = utils.ParsePath(path)
|
||||
var files []model.File
|
||||
cache, err := base.GetCache(path, account)
|
||||
if err == nil {
|
||||
files, _ = cache.([]model.File)
|
||||
} else {
|
||||
file, err := driver.File(path, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files, err = driver.GetFiles(file.Id, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(files) > 0 {
|
||||
_ = base.SetCache(path, files, account)
|
||||
}
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (driver Cloud139) Link(args base.Args, account *model.Account) (*base.Link, error) {
|
||||
file, err := driver.File(args.Path, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := driver.GetLink(file.Id, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &base.Link{Url: u}, nil
|
||||
}
|
||||
|
||||
func (driver Cloud139) Path(path string, account *model.Account) (*model.File, []model.File, error) {
|
||||
path = utils.ParsePath(path)
|
||||
log.Debugf("139 path: %s", path)
|
||||
file, err := driver.File(path, account)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !file.IsDir() {
|
||||
return file, nil, nil
|
||||
}
|
||||
files, err := driver.Files(path, account)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return nil, files, nil
|
||||
}
|
||||
|
||||
func (driver Cloud139) Proxy(c *gin.Context, account *model.Account) {
|
||||
|
||||
}
|
||||
|
||||
func (driver Cloud139) Preview(path string, account *model.Account) (interface{}, error) {
|
||||
return nil, base.ErrNotSupport
|
||||
}
|
||||
|
||||
func (driver Cloud139) MakeDir(path string, account *model.Account) error {
|
||||
parentFile, err := driver.File(utils.Dir(path), account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := base.Json{
|
||||
"createCatalogExtReq": base.Json{
|
||||
"parentCatalogID": parentFile.Id,
|
||||
"newCatalogName": utils.Base(path),
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": account.Username,
|
||||
"accountType": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
pathname := "/orchestration/personalCloud/catalog/v1.0/createCatalogExt"
|
||||
_, err = driver.Post(pathname,
|
||||
data, nil, account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Cloud139) Move(src string, dst string, account *model.Account) error {
|
||||
srcFile, err := driver.File(src, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstParentFile, err := driver.File(utils.Dir(dst), account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var contentInfoList []string
|
||||
var catalogInfoList []string
|
||||
if srcFile.IsDir() {
|
||||
catalogInfoList = append(catalogInfoList, srcFile.Id)
|
||||
} else {
|
||||
contentInfoList = append(contentInfoList, srcFile.Id)
|
||||
}
|
||||
data := base.Json{
|
||||
"createBatchOprTaskReq": base.Json{
|
||||
"taskType": 3,
|
||||
"actionType": "304",
|
||||
"taskInfo": base.Json{
|
||||
"contentInfoList": contentInfoList,
|
||||
"catalogInfoList": catalogInfoList,
|
||||
"newCatalogID": dstParentFile.Id,
|
||||
},
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask"
|
||||
_, err = driver.Post(pathname, data, nil, account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Cloud139) Rename(src string, dst string, account *model.Account) error {
|
||||
srcFile, err := driver.File(src, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var data base.Json
|
||||
var pathname string
|
||||
if srcFile.IsDir() {
|
||||
data = base.Json{
|
||||
"catalogID": srcFile.Id,
|
||||
"catalogName": utils.Base(dst),
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
}
|
||||
pathname = "/orchestration/personalCloud/catalog/v1.0/updateCatalogInfo"
|
||||
} else {
|
||||
data = base.Json{
|
||||
"contentID": srcFile.Id,
|
||||
"contentName": utils.Base(dst),
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
}
|
||||
pathname = "/orchestration/personalCloud/catalog/v1.0/updateContentInfo"
|
||||
}
|
||||
_, err = driver.Post(pathname, data, nil, account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Cloud139) Copy(src string, dst string, account *model.Account) error {
|
||||
srcFile, err := driver.File(src, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstParentFile, err := driver.File(utils.Dir(dst), account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
argName := "contentInfoList"
|
||||
if srcFile.IsDir() {
|
||||
argName = "catalogInfoList"
|
||||
}
|
||||
data := base.Json{
|
||||
"createBatchOprTaskReq": base.Json{
|
||||
"taskType": 3,
|
||||
"actionType": 309,
|
||||
"taskInfo": base.Json{
|
||||
"contentInfoList": []string{},
|
||||
"catalogInfoList": []string{},
|
||||
"newCatalogID": dstParentFile.Id,
|
||||
argName: []string{srcFile.Id},
|
||||
},
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask"
|
||||
_, err = driver.Post(pathname, data, nil, account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Cloud139) Delete(path string, account *model.Account) error {
|
||||
file, err := driver.File(path, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
argName := "contentInfoList"
|
||||
if file.IsDir() {
|
||||
argName = "catalogInfoList"
|
||||
}
|
||||
data := base.Json{
|
||||
"createBatchOprTaskReq": base.Json{
|
||||
"taskType": 2,
|
||||
"actionType": 201,
|
||||
"taskInfo": base.Json{
|
||||
"newCatalogID": "",
|
||||
argName: []string{file.Id},
|
||||
},
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
pathname := "/orchestration/personalCloud/batchOprTask/v1.0/createBatchOprTask"
|
||||
_, err = driver.Post(pathname, data, nil, account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Cloud139) Upload(file *model.FileStream, account *model.Account) error {
|
||||
if file == nil {
|
||||
return base.ErrEmptyFile
|
||||
}
|
||||
parentFile, err := driver.File(file.ParentPath, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !parentFile.IsDir() {
|
||||
return base.ErrNotFolder
|
||||
}
|
||||
data := base.Json{
|
||||
"manualRename": 2,
|
||||
"operation": 0,
|
||||
"fileCount": 1,
|
||||
"totalSize": file.Size,
|
||||
"uploadContentList": []base.Json{{
|
||||
"contentName": file.Name,
|
||||
"contentSize": file.Size,
|
||||
// "digest": "5a3231986ce7a6b46e408612d385bafa"
|
||||
}},
|
||||
"parentCatalogID": parentFile.Id,
|
||||
"newCatalogName": "",
|
||||
"commonAccountInfo": base.Json{
|
||||
"account": "18627147660",
|
||||
"accountType": 1,
|
||||
},
|
||||
}
|
||||
pathname := "/orchestration/personalCloud/uploadAndDownload/v1.0/pcUploadFileRequest"
|
||||
var resp UploadResp
|
||||
_, err = driver.Post(pathname, data, &resp, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var Default uint64 = 10485760
|
||||
part := int(math.Ceil(float64(file.Size) / float64(Default)))
|
||||
var start uint64 = 0
|
||||
for i := 0; i < part; i++ {
|
||||
byteSize := file.Size - start
|
||||
if byteSize > Default {
|
||||
byteSize = Default
|
||||
}
|
||||
byteData := make([]byte, byteSize)
|
||||
_, err = io.ReadFull(file, byteData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("POST", resp.Data.UploadResult.RedirectionURL, bytes.NewBuffer(byteData))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headers := map[string]string{
|
||||
"Accept": "*/*",
|
||||
"Content-Type": "text/plain;name=" + unicode(file.Name),
|
||||
"contentSize": strconv.FormatUint(file.Size, 10),
|
||||
"range": fmt.Sprintf("bytes=%d-%d", start, start+byteSize-1),
|
||||
"content-length": strconv.FormatUint(byteSize, 10),
|
||||
"uploadtaskID": resp.Data.UploadResult.UploadTaskID,
|
||||
"rangeType": "0",
|
||||
"Referer": "https://yun.139.com/",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.44",
|
||||
"x-SvcType": "1",
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
res, err := base.HttpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf("%+v", res)
|
||||
start += byteSize
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ base.Driver = (*Cloud139)(nil)
|
|
@ -0,0 +1,132 @@
|
|||
package _39
|
||||
|
||||
type BaseResp struct {
|
||||
Success bool `json:"success"`
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type Catalog struct {
|
||||
CatalogID string `json:"catalogID"`
|
||||
CatalogName string `json:"catalogName"`
|
||||
CatalogType int `json:"catalogType"`
|
||||
CreateTime string `json:"createTime"`
|
||||
UpdateTime string `json:"updateTime"`
|
||||
IsShared bool `json:"isShared"`
|
||||
CatalogLevel int `json:"catalogLevel"`
|
||||
ShareDoneeCount int `json:"shareDoneeCount"`
|
||||
OpenType int `json:"openType"`
|
||||
ParentCatalogID string `json:"parentCatalogId"`
|
||||
DirEtag int `json:"dirEtag"`
|
||||
Tombstoned int `json:"tombstoned"`
|
||||
ProxyID interface{} `json:"proxyID"`
|
||||
Moved int `json:"moved"`
|
||||
IsFixedDir int `json:"isFixedDir"`
|
||||
IsSynced interface{} `json:"isSynced"`
|
||||
Owner string `json:"owner"`
|
||||
Modifier interface{} `json:"modifier"`
|
||||
Path string `json:"path"`
|
||||
ShareType int `json:"shareType"`
|
||||
SoftLink interface{} `json:"softLink"`
|
||||
ExtProp1 interface{} `json:"extProp1"`
|
||||
ExtProp2 interface{} `json:"extProp2"`
|
||||
ExtProp3 interface{} `json:"extProp3"`
|
||||
ExtProp4 interface{} `json:"extProp4"`
|
||||
ExtProp5 interface{} `json:"extProp5"`
|
||||
ETagOprType int `json:"ETagOprType"`
|
||||
}
|
||||
|
||||
type Content struct {
|
||||
ContentID string `json:"contentID"`
|
||||
ContentName string `json:"contentName"`
|
||||
ContentSuffix string `json:"contentSuffix"`
|
||||
ContentSize int `json:"contentSize"`
|
||||
ContentDesc string `json:"contentDesc"`
|
||||
ContentType int `json:"contentType"`
|
||||
ContentOrigin int `json:"contentOrigin"`
|
||||
UpdateTime string `json:"updateTime"`
|
||||
CommentCount int `json:"commentCount"`
|
||||
ThumbnailURL string `json:"thumbnailURL"`
|
||||
BigthumbnailURL string `json:"bigthumbnailURL"`
|
||||
PresentURL string `json:"presentURL"`
|
||||
PresentLURL string `json:"presentLURL"`
|
||||
PresentHURL string `json:"presentHURL"`
|
||||
ContentTAGList interface{} `json:"contentTAGList"`
|
||||
ShareDoneeCount int `json:"shareDoneeCount"`
|
||||
Safestate int `json:"safestate"`
|
||||
Transferstate int `json:"transferstate"`
|
||||
IsFocusContent int `json:"isFocusContent"`
|
||||
UpdateShareTime interface{} `json:"updateShareTime"`
|
||||
UploadTime string `json:"uploadTime"`
|
||||
OpenType int `json:"openType"`
|
||||
AuditResult int `json:"auditResult"`
|
||||
ParentCatalogID string `json:"parentCatalogId"`
|
||||
Channel string `json:"channel"`
|
||||
GeoLocFlag string `json:"geoLocFlag"`
|
||||
Digest string `json:"digest"`
|
||||
Version string `json:"version"`
|
||||
FileEtag string `json:"fileEtag"`
|
||||
FileVersion string `json:"fileVersion"`
|
||||
Tombstoned int `json:"tombstoned"`
|
||||
ProxyID string `json:"proxyID"`
|
||||
Moved int `json:"moved"`
|
||||
MidthumbnailURL string `json:"midthumbnailURL"`
|
||||
Owner string `json:"owner"`
|
||||
Modifier string `json:"modifier"`
|
||||
ShareType int `json:"shareType"`
|
||||
ExtInfo struct {
|
||||
Uploader string `json:"uploader"`
|
||||
Address string `json:"address"`
|
||||
} `json:"extInfo"`
|
||||
Exif struct {
|
||||
CreateTime string `json:"createTime"`
|
||||
Longitude interface{} `json:"longitude"`
|
||||
Latitude interface{} `json:"latitude"`
|
||||
LocalSaveTime interface{} `json:"localSaveTime"`
|
||||
} `json:"exif"`
|
||||
CollectionFlag interface{} `json:"collectionFlag"`
|
||||
TreeInfo interface{} `json:"treeInfo"`
|
||||
IsShared bool `json:"isShared"`
|
||||
ETagOprType int `json:"ETagOprType"`
|
||||
}
|
||||
|
||||
type GetDiskResp struct {
|
||||
BaseResp
|
||||
Data struct {
|
||||
Result struct {
|
||||
ResultCode string `json:"resultCode"`
|
||||
ResultDesc interface{} `json:"resultDesc"`
|
||||
} `json:"result"`
|
||||
GetDiskResult struct {
|
||||
ParentCatalogID string `json:"parentCatalogID"`
|
||||
NodeCount int `json:"nodeCount"`
|
||||
CatalogList []Catalog `json:"catalogList"`
|
||||
ContentList []Content `json:"contentList"`
|
||||
IsCompleted int `json:"isCompleted"`
|
||||
} `json:"getDiskResult"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type UploadResp struct {
|
||||
BaseResp
|
||||
Data struct {
|
||||
Result struct {
|
||||
ResultCode string `json:"resultCode"`
|
||||
ResultDesc interface{} `json:"resultDesc"`
|
||||
} `json:"result"`
|
||||
UploadResult struct {
|
||||
UploadTaskID string `json:"uploadTaskID"`
|
||||
RedirectionURL string `json:"redirectionUrl"`
|
||||
NewContentIDList []struct {
|
||||
ContentID string `json:"contentID"`
|
||||
ContentName string `json:"contentName"`
|
||||
IsNeedUpload string `json:"isNeedUpload"`
|
||||
FileEtag int64 `json:"fileEtag"`
|
||||
FileVersion int64 `json:"fileVersion"`
|
||||
OverridenFlag int `json:"overridenFlag"`
|
||||
} `json:"newContentIDList"`
|
||||
CatalogIDList interface{} `json:"catalogIDList"`
|
||||
IsSlice interface{} `json:"isSlice"`
|
||||
} `json:"uploadResult"`
|
||||
} `json:"data"`
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package _39
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func randomStr(n int) string {
|
||||
builder := strings.Builder{}
|
||||
t := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
for i := 0; i < n; i++ {
|
||||
r := rand.Intn(len(t))
|
||||
builder.WriteString(t[r : r+1])
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func encodeURIComponent(str string) string {
|
||||
r := url.QueryEscape(str)
|
||||
r = strings.Replace(r, "+", "%20", -1)
|
||||
return r
|
||||
}
|
||||
|
||||
func calSign(body, ts, randStr string) string {
|
||||
body = strings.ReplaceAll(body, "\n", "")
|
||||
body = strings.ReplaceAll(body, " ", "")
|
||||
body = encodeURIComponent(body)
|
||||
strs := strings.Split(body, "")
|
||||
sort.Strings(strs)
|
||||
body = strings.Join(strs, "")
|
||||
body = base64.StdEncoding.EncodeToString([]byte(body))
|
||||
res := utils.GetMD5Encode(body) + utils.GetMD5Encode(ts+":"+randStr)
|
||||
res = strings.ToUpper(utils.GetMD5Encode(res))
|
||||
return res
|
||||
}
|
||||
|
||||
func getTime(t string) *time.Time {
|
||||
stamp, _ := time.ParseInLocation("20060102150405", t, time.Local)
|
||||
return &stamp
|
||||
}
|
||||
|
||||
func isFamily(account *model.Account) bool {
|
||||
return account.InternalType == "Family"
|
||||
}
|
||||
|
||||
func unicode(str string) string {
|
||||
textQuoted := strconv.QuoteToASCII(str)
|
||||
textUnquoted := textQuoted[1 : len(textQuoted)-1]
|
||||
return textUnquoted
|
||||
}
|
|
@ -2,6 +2,7 @@ package drivers
|
|||
|
||||
import (
|
||||
_ "github.com/Xhofe/alist/drivers/123"
|
||||
_ "github.com/Xhofe/alist/drivers/139"
|
||||
_ "github.com/Xhofe/alist/drivers/189"
|
||||
_ "github.com/Xhofe/alist/drivers/alidrive"
|
||||
_ "github.com/Xhofe/alist/drivers/alist"
|
||||
|
|
Loading…
Reference in New Issue