From f577d822420989a0b86fe53edb442d347d8326e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=AE=E5=87=89?= <927625802@qq.com> Date: Sat, 27 Nov 2021 19:40:36 +0800 Subject: [PATCH] :hammer: refactor driver: ali --- bootstrap/account.go | 2 +- bootstrap/drivers.go | 7 + drivers/123pan.go | 321 --------------------------- drivers/123pan/123pan.go | 150 +++++++++++++ drivers/123pan/driver.go | 181 ++++++++++++++++ drivers/{ => 189cloud}/189.go | 205 +----------------- drivers/189cloud/driver.go | 203 ++++++++++++++++++ drivers/alidrive.go | 394 ---------------------------------- drivers/alidrive/alidrive.go | 165 ++++++++++++++ drivers/alidrive/driver.go | 253 ++++++++++++++++++++++ drivers/driver.go | 12 +- drivers/googledrive.go | 8 + drivers/native.go | 8 + drivers/onedrive.go | 8 + 14 files changed, 999 insertions(+), 918 deletions(-) create mode 100644 bootstrap/drivers.go delete mode 100644 drivers/123pan.go create mode 100644 drivers/123pan/123pan.go create mode 100644 drivers/123pan/driver.go rename drivers/{ => 189cloud}/189.go (62%) create mode 100644 drivers/189cloud/driver.go delete mode 100644 drivers/alidrive.go create mode 100644 drivers/alidrive/alidrive.go create mode 100644 drivers/alidrive/driver.go diff --git a/bootstrap/account.go b/bootstrap/account.go index d799b733..4ee52acc 100644 --- a/bootstrap/account.go +++ b/bootstrap/account.go @@ -17,7 +17,7 @@ func InitAccounts() { model.RegisterAccount(account) driver, ok := drivers.GetDriver(account.Type) if !ok { - log.Errorf("no [%s] driver", driver) + log.Errorf("no [%s] driver", account.Type) } else { err := driver.Save(&accounts[i], nil) if err != nil { diff --git a/bootstrap/drivers.go b/bootstrap/drivers.go new file mode 100644 index 00000000..aa00cd5c --- /dev/null +++ b/bootstrap/drivers.go @@ -0,0 +1,7 @@ +package bootstrap + +import ( + _ "github.com/Xhofe/alist/drivers/123pan" + _ "github.com/Xhofe/alist/drivers/189cloud" + _ "github.com/Xhofe/alist/drivers/alidrive" +) \ No newline at end of file diff --git a/drivers/123pan.go b/drivers/123pan.go deleted file mode 100644 index 427b8469..00000000 --- a/drivers/123pan.go +++ /dev/null @@ -1,321 +0,0 @@ -package drivers - -import ( - "fmt" - "github.com/Xhofe/alist/conf" - "github.com/Xhofe/alist/model" - "github.com/Xhofe/alist/utils" - "github.com/gin-gonic/gin" - "github.com/go-resty/resty/v2" - log "github.com/sirupsen/logrus" - "path/filepath" - "strconv" - "time" -) - -type Pan123 struct { -} - -var pan123Client = resty.New() - -var pan123 = "123Pan" - -func (p Pan123) Items() []Item { - return []Item{ - { - Name: "proxy", - Label: "proxy", - Type: "bool", - Required: true, - Description: "allow proxy", - }, - { - Name: "username", - Label: "username", - Type: "string", - Required: true, - Description: "account username/phone number", - }, - { - Name: "password", - Label: "password", - Type: "string", - Required: true, - Description: "account password", - }, - { - Name: "root_folder", - Label: "root folder file_id", - Type: "string", - Required: false, - }, - { - Name: "order_by", - Label: "order_by", - Type: "select", - Values: "name,fileId,updateAt,createAt", - Required: true, - }, - { - Name: "order_direction", - Label: "order_direction", - Type: "select", - Values: "asc,desc", - Required: true, - }, - } -} - -type Pan123TokenResp struct { - Code int `json:"code"` - Data struct { - Token string `json:"token"` - } `json:"data"` - Message string `json:"message"` -} - -func (p Pan123) Login(account *model.Account) error { - var resp Pan123TokenResp - _, err := pan123Client.R(). - SetResult(&resp). - SetBody(Json{ - "passport": account.Username, - "password": account.Password, - }).Post("https://www.123pan.com/api/user/sign_in") - if err != nil { - return err - } - if resp.Code != 200 { - err = fmt.Errorf(resp.Message) - account.Status = resp.Message - } else { - account.Status = "work" - account.AccessToken = resp.Data.Token - } - _ = model.SaveAccount(account) - return err -} - -func (p Pan123) Save(account *model.Account, old *model.Account) error { - if account.RootFolder == "" { - account.RootFolder = "0" - } - err := p.Login(account) - return err -} - -type Pan123File struct { - FileName string `json:"FileName"` - Size int64 `json:"Size"` - UpdateAt *time.Time `json:"UpdateAt"` - FileId int64 `json:"FileId"` - Type int `json:"Type"` - Etag string `json:"Etag"` - S3KeyFlag string `json:"S3KeyFlag"` -} - -func (p Pan123) FormatFile(file *Pan123File) *model.File { - f := &model.File{ - Id: strconv.FormatInt(file.FileId, 10), - Name: file.FileName, - Size: file.Size, - Driver: "123Pan", - UpdatedAt: file.UpdateAt, - } - if file.Type == 1 { - f.Type = conf.FOLDER - } else { - f.Type = utils.GetFileType(filepath.Ext(file.FileName)) - } - return f -} - -type Pan123Files struct { - Code int `json:"code"` - Message string `json:"message"` - Data struct { - InfoList []Pan123File `json:"InfoList"` - Next string `json:"Next"` - } `json:"data"` -} - -func (p Pan123) GetFiles(parentId string, account *model.Account) ([]Pan123File, error) { - next := "0" - res := make([]Pan123File, 0) - for next != "-1" { - var resp Pan123Files - _, err := pan123Client.R().SetResult(&resp). - SetHeader("authorization", "Bearer "+account.AccessToken). - SetQueryParams(map[string]string{ - "driveId": "0", - "limit": "100", - "next": next, - "orderBy": account.OrderBy, - "orderDirection": account.OrderDirection, - "parentFileId": parentId, - "trashed": "false", - }).Get("https://www.123pan.com/api/file/list") - if err != nil { - return nil, err - } - log.Debugf("%+v", resp) - if resp.Code != 0 { - if resp.Code == 401 { - err := p.Login(account) - if err != nil { - return nil, err - } - return p.GetFiles(parentId, account) - } - return nil, fmt.Errorf(resp.Message) - } - next = resp.Data.Next - res = append(res, resp.Data.InfoList...) - } - return res, nil -} - -func (p Pan123) 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: pan123, - UpdatedAt: account.UpdatedAt, - }, nil - } - dir, name := filepath.Split(path) - files, err := p.Files(dir, account) - if err != nil { - return nil, err - } - for _, file := range files { - if file.Name == name { - return &file, nil - } - } - return nil, PathNotFound -} - -func (p Pan123) Files(path string, account *model.Account) ([]model.File, error) { - path = utils.ParsePath(path) - var rawFiles []Pan123File - cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path)) - if err == nil { - rawFiles, _ = cache.([]Pan123File) - } else { - file, err := p.File(path, account) - if err != nil { - return nil, err - } - rawFiles, err = p.GetFiles(file.Id, account) - if err != nil { - return nil, err - } - if len(rawFiles) > 0 { - _ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), rawFiles, nil) - } - } - files := make([]model.File, 0) - for _, file := range rawFiles { - files = append(files, *p.FormatFile(&file)) - } - return files, nil -} - -func (p Pan123) Path(path string, account *model.Account) (*model.File, []model.File, error) { - path = utils.ParsePath(path) - log.Debugf("pan123 path: %s", path) - file, err := p.File(path, account) - if err != nil { - return nil, nil, err - } - if file.Type != conf.FOLDER { - file.Url, _ = p.Link(path, account) - return file, nil, nil - } - files, err := p.Files(path, account) - if err != nil { - return nil, nil, err - } - return nil, files, nil -} - -func (p Pan123) GetFile(path string, account *model.Account) (*Pan123File, error) { - dir, name := filepath.Split(path) - dir = utils.ParsePath(dir) - _, err := p.Files(dir, account) - if err != nil { - return nil, err - } - parentFiles_, _ := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, dir)) - parentFiles, _ := parentFiles_.([]Pan123File) - for _, file := range parentFiles { - if file.FileName == name { - if file.Type != 1 { - return &file, err - } else { - return nil, NotFile - } - } - } - return nil, PathNotFound -} - -type Pan123DownResp struct { - Code int `json:"code"` - Message string `json:"message"` - Data struct { - DownloadUrl string `json:"DownloadUrl"` - } `json:"data"` -} - -func (p Pan123) Link(path string, account *model.Account) (string, error) { - file, err := p.GetFile(utils.ParsePath(path), account) - if err != nil { - return "", err - } - var resp Pan123DownResp - _, err = pan123Client.R().SetResult(&resp).SetHeader("authorization", "Bearer "+account.AccessToken). - SetBody(Json{ - "driveId": 0, - "etag": file.Etag, - "fileId": file.FileId, - "fileName": file.FileName, - "s3keyFlag": file.S3KeyFlag, - "size": file.Size, - "type": file.Type, - }).Post("https://www.123pan.com/api/file/download_info") - if err != nil { - return "", err - } - if resp.Code != 0 { - if resp.Code == 401 { - err := p.Login(account) - if err != nil { - return "", err - } - return p.Link(path, account) - } - return "", fmt.Errorf(resp.Message) - } - return resp.Data.DownloadUrl, nil -} - -func (p Pan123) Proxy(c *gin.Context, account *model.Account) { - c.Request.Header.Del("origin") -} - -func (p Pan123) Preview(path string, account *model.Account) (interface{}, error) { - return nil, nil -} - -var _ Driver = (*Pan123)(nil) - -func init() { - RegisterDriver("123Pan", &Pan123{}) - pan123Client.SetRetryCount(3) -} diff --git a/drivers/123pan/123pan.go b/drivers/123pan/123pan.go new file mode 100644 index 00000000..5054bbe5 --- /dev/null +++ b/drivers/123pan/123pan.go @@ -0,0 +1,150 @@ +package _23pan + +import ( + "fmt" + "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers" + "github.com/Xhofe/alist/model" + "github.com/Xhofe/alist/utils" + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" + "path/filepath" + "strconv" + "time" +) + +var pan123Client = resty.New() + +type Pan123TokenResp struct { + Code int `json:"code"` + Data struct { + Token string `json:"token"` + } `json:"data"` + Message string `json:"message"` +} + +type Pan123File struct { + FileName string `json:"FileName"` + Size int64 `json:"Size"` + UpdateAt *time.Time `json:"UpdateAt"` + FileId int64 `json:"FileId"` + Type int `json:"Type"` + Etag string `json:"Etag"` + S3KeyFlag string `json:"S3KeyFlag"` +} + +type Pan123Files struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + InfoList []Pan123File `json:"InfoList"` + Next string `json:"Next"` + } `json:"data"` +} + +type Pan123DownResp struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + DownloadUrl string `json:"DownloadUrl"` + } `json:"data"` +} + +func (driver Pan123) Login(account *model.Account) error { + var resp Pan123TokenResp + _, err := pan123Client.R(). + SetResult(&resp). + SetBody(drivers.Json{ + "passport": account.Username, + "password": account.Password, + }).Post("https://www.123pan.com/api/user/sign_in") + if err != nil { + return err + } + if resp.Code != 200 { + err = fmt.Errorf(resp.Message) + account.Status = resp.Message + } else { + account.Status = "work" + account.AccessToken = resp.Data.Token + } + _ = model.SaveAccount(account) + return err +} + +func (driver Pan123) FormatFile(file *Pan123File) *model.File { + f := &model.File{ + Id: strconv.FormatInt(file.FileId, 10), + Name: file.FileName, + Size: file.Size, + Driver: driverName, + UpdatedAt: file.UpdateAt, + } + if file.Type == 1 { + f.Type = conf.FOLDER + } else { + f.Type = utils.GetFileType(filepath.Ext(file.FileName)) + } + return f +} + +func (driver Pan123) GetFiles(parentId string, account *model.Account) ([]Pan123File, error) { + next := "0" + res := make([]Pan123File, 0) + for next != "-1" { + var resp Pan123Files + _, err := pan123Client.R().SetResult(&resp). + SetHeader("authorization", "Bearer "+account.AccessToken). + SetQueryParams(map[string]string{ + "driveId": "0", + "limit": "100", + "next": next, + "orderBy": account.OrderBy, + "orderDirection": account.OrderDirection, + "parentFileId": parentId, + "trashed": "false", + }).Get("https://www.123pan.com/api/file/list") + if err != nil { + return nil, err + } + log.Debugf("%+v", resp) + if resp.Code != 0 { + if resp.Code == 401 { + err := driver.Login(account) + if err != nil { + return nil, err + } + return driver.GetFiles(parentId, account) + } + return nil, fmt.Errorf(resp.Message) + } + next = resp.Data.Next + res = append(res, resp.Data.InfoList...) + } + return res, nil +} + +func (driver Pan123) GetFile(path string, account *model.Account) (*Pan123File, error) { + dir, name := filepath.Split(path) + _, err := driver.Files(dir, account) + if err != nil { + return nil, err + } + parentFiles_, _ := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, dir)) + parentFiles, _ := parentFiles_.([]Pan123File) + for _, file := range parentFiles { + if file.FileName == name { + if file.Type != 1 { + return &file, err + } else { + return nil, drivers.NotFile + } + } + } + return nil, drivers.PathNotFound +} + +func init() { + drivers.RegisterDriver(driverName, &Pan123{}) + pan123Client.SetRetryCount(3) +} diff --git a/drivers/123pan/driver.go b/drivers/123pan/driver.go new file mode 100644 index 00000000..efa94c16 --- /dev/null +++ b/drivers/123pan/driver.go @@ -0,0 +1,181 @@ +package _23pan + +import ( + "fmt" + "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers" + "github.com/Xhofe/alist/model" + "github.com/Xhofe/alist/utils" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "path/filepath" +) + +type Pan123 struct {} + +var driverName = "123Pan" + +func (driver Pan123) Items() []drivers.Item { + return []drivers.Item{ + { + Name: "proxy", + Label: "proxy", + Type: "bool", + Required: true, + Description: "allow proxy", + }, + { + Name: "username", + Label: "username", + Type: "string", + Required: true, + Description: "account username/phone number", + }, + { + Name: "password", + Label: "password", + Type: "string", + Required: true, + Description: "account password", + }, + { + Name: "root_folder", + Label: "root folder file_id", + Type: "string", + Required: false, + }, + { + Name: "order_by", + Label: "order_by", + Type: "select", + Values: "name,fileId,updateAt,createAt", + Required: true, + }, + { + Name: "order_direction", + Label: "order_direction", + Type: "select", + Values: "asc,desc", + Required: true, + }, + } +} + +func (driver Pan123) Save(account *model.Account, old *model.Account) error { + if account.RootFolder == "" { + account.RootFolder = "0" + } + err := driver.Login(account) + return err +} + +func (driver Pan123) 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: driverName, + 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, drivers.PathNotFound +} + +func (driver Pan123) Files(path string, account *model.Account) ([]model.File, error) { + path = utils.ParsePath(path) + var rawFiles []Pan123File + cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path)) + if err == nil { + rawFiles, _ = cache.([]Pan123File) + } else { + file, err := driver.File(path, account) + if err != nil { + return nil, err + } + rawFiles, err = driver.GetFiles(file.Id, account) + if err != nil { + return nil, err + } + if len(rawFiles) > 0 { + _ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), rawFiles, nil) + } + } + files := make([]model.File, 0) + for _, file := range rawFiles { + files = append(files, *driver.FormatFile(&file)) + } + return files, nil +} + +func (driver Pan123) Link(path string, account *model.Account) (string, error) { + file, err := driver.GetFile(utils.ParsePath(path), account) + if err != nil { + return "", err + } + var resp Pan123DownResp + _, err = pan123Client.R().SetResult(&resp).SetHeader("authorization", "Bearer "+account.AccessToken). + SetBody(drivers.Json{ + "driveId": 0, + "etag": file.Etag, + "fileId": file.FileId, + "fileName": file.FileName, + "s3keyFlag": file.S3KeyFlag, + "size": file.Size, + "type": file.Type, + }).Post("https://www.123pan.com/api/file/download_info") + if err != nil { + return "", err + } + if resp.Code != 0 { + if resp.Code == 401 { + err := driver.Login(account) + if err != nil { + return "", err + } + return driver.Link(path, account) + } + return "", fmt.Errorf(resp.Message) + } + return resp.Data.DownloadUrl, nil +} + +func (driver Pan123) Path(path string, account *model.Account) (*model.File, []model.File, error) { + path = utils.ParsePath(path) + log.Debugf("pan123 path: %s", path) + file, err := driver.File(path, account) + if err != nil { + return nil, nil, err + } + if file.Type != conf.FOLDER { + file.Url, _ = driver.Link(path, account) + return file, nil, nil + } + files, err := driver.Files(path, account) + if err != nil { + return nil, nil, err + } + return nil, files, nil +} + +func (driver Pan123) Proxy(c *gin.Context, account *model.Account) { + c.Request.Header.Del("origin") +} + +func (driver Pan123) Preview(path string, account *model.Account) (interface{}, error) { + return nil, nil +} + +var _ drivers.Driver = (*Pan123)(nil) \ No newline at end of file diff --git a/drivers/189.go b/drivers/189cloud/189.go similarity index 62% rename from drivers/189.go rename to drivers/189cloud/189.go index 60cef2ff..f1fa9ba8 100644 --- a/drivers/189.go +++ b/drivers/189cloud/189.go @@ -1,4 +1,4 @@ -package drivers +package _89cloud import ( "crypto/rand" @@ -9,9 +9,9 @@ import ( "encoding/pem" "fmt" "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers" "github.com/Xhofe/alist/model" "github.com/Xhofe/alist/utils" - "github.com/gin-gonic/gin" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" mathRand "math/rand" @@ -22,75 +22,10 @@ import ( "time" ) -type Cloud189 struct { -} var client189Map map[string]*resty.Client -func (c Cloud189) Items() []Item { - return []Item{ - { - Name: "proxy", - Label: "proxy", - Type: "bool", - Required: true, - Description: "allow proxy", - }, - { - Name: "username", - Label: "username", - Type: "string", - Required: true, - Description: "account username/phone number", - }, - { - Name: "password", - Label: "password", - Type: "string", - Required: true, - Description: "account password", - }, - { - Name: "root_folder", - Label: "root folder file_id", - Type: "string", - Required: true, - }, - { - Name: "order_by", - Label: "order_by", - Type: "select", - Values: "name,size,lastOpTime,createdDate", - Required: true, - }, - { - Name: "order_direction", - Label: "desc", - Type: "select", - Values: "true,false", - Required: true, - }, - } -} - -func (c Cloud189) Save(account *model.Account, old *model.Account) error { - if old != nil && old.Name != account.Name { - delete(client189Map, old.Name) - } - if err := c.Login(account); err != nil { - account.Status = err.Error() - _ = model.SaveAccount(account) - return err - } - account.Status = "work" - err := model.SaveAccount(account) - if err != nil { - return err - } - return nil -} - -func (c Cloud189) FormatFile(file *Cloud189File) *model.File { +func (driver Cloud189) FormatFile(file *Cloud189File) *model.File { f := &model.File{ Id: strconv.FormatInt(file.Id, 10), Name: file.Name, @@ -114,75 +49,6 @@ func (c Cloud189) FormatFile(file *Cloud189File) *model.File { return f } -func (c Cloud189) 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: pan123, - UpdatedAt: account.UpdatedAt, - }, nil - } - dir, name := filepath.Split(path) - files, err := c.Files(dir, account) - if err != nil { - return nil, err - } - for _, file := range files { - if file.Name == name { - return &file, nil - } - } - return nil, PathNotFound -} - -func (c Cloud189) Files(path string, account *model.Account) ([]model.File, error) { - path = utils.ParsePath(path) - var rawFiles []Cloud189File - cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path)) - if err == nil { - rawFiles, _ = cache.([]Cloud189File) - } else { - file, err := c.File(path, account) - if err != nil { - return nil, err - } - rawFiles, err = c.GetFiles(file.Id, account) - if err != nil { - return nil, err - } - if len(rawFiles) > 0 { - _ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), rawFiles, nil) - } - } - files := make([]model.File, 0) - for _, file := range rawFiles { - files = append(files, *c.FormatFile(&file)) - } - return files, nil -} - -func (c Cloud189) Path(path string, account *model.Account) (*model.File, []model.File, error) { - path = utils.ParsePath(path) - log.Debugf("189 path: %s", path) - file, err := c.File(path, account) - if err != nil { - return nil, nil, err - } - if file.Type != conf.FOLDER { - file.Url, _ = c.Link(path, account) - return file, nil, nil - } - files, err := c.Files(path, account) - if err != nil { - return nil, nil, err - } - return nil, files, nil -} - //func (c Cloud189) GetFile(path string, account *model.Account) (*Cloud189File, error) { // dir, name := filepath.Split(path) // dir = utils.ParsePath(dir) @@ -210,63 +76,8 @@ type Cloud189Down struct { FileDownloadUrl string `json:"fileDownloadUrl"` } -func (c Cloud189) Link(path string, account *model.Account) (string, error) { - file, err := c.File(utils.ParsePath(path), account) - if err != nil { - return "", err - } - if file.Type == conf.FOLDER { - return "", NotFile - } - client, ok := client189Map[account.Name] - if !ok { - return "", fmt.Errorf("can't find [%s] client", account.Name) - } - var e Cloud189Error - var resp Cloud189Down - _, err = client.R().SetResult(&resp).SetError(&e). - SetHeader("Accept", "application/json;charset=UTF-8"). - SetQueryParams(map[string]string{ - "noCache": random(), - "fileId": file.Id, - }).Get("https://cloud.189.cn/api/open/file/getFileDownloadUrl.action") - if err != nil { - return "", err - } - if e.ErrorCode != "" { - if e.ErrorCode == "InvalidSessionKey" { - err = c.Login(account) - if err != nil { - return "", err - } - return c.Link(path, account) - } - } - if resp.ResCode != 0 { - return "", fmt.Errorf(resp.ResMessage) - } - res, err := noRedirectClient.R().Get(resp.FileDownloadUrl) - if err != nil { - return "", err - } - if res.StatusCode() == 302 { - return res.Header().Get("location"), nil - } - return resp.FileDownloadUrl, nil -} - -func (c Cloud189) Proxy(ctx *gin.Context, account *model.Account) { - ctx.Request.Header.Del("Origin") -} - -func (c Cloud189) Preview(path string, account *model.Account) (interface{}, error) { - return nil, nil -} - -var _ Driver = (*Cloud189)(nil) - func init() { - RegisterDriver("189Cloud", &Cloud189{}) + drivers.RegisterDriver("189Cloud", &Cloud189{}) client189Map = make(map[string]*resty.Client, 0) } @@ -277,7 +88,7 @@ type LoginResp struct { } // Login refer to PanIndex -func (c Cloud189) Login(account *model.Account) error { +func (driver Cloud189) Login(account *model.Account) error { client, ok := client189Map[account.Name] if !ok { //cookieJar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) @@ -394,7 +205,7 @@ type Cloud189Files struct { } `json:"fileListAO"` } -func (c Cloud189) GetFiles(fileId string, account *model.Account) ([]Cloud189File, error) { +func (driver Cloud189) GetFiles(fileId string, account *model.Account) ([]Cloud189File, error) { client, ok := client189Map[account.Name] if !ok { return nil, fmt.Errorf("can't find [%s] client", account.Name) @@ -421,11 +232,11 @@ func (c Cloud189) GetFiles(fileId string, account *model.Account) ([]Cloud189Fil } if e.ErrorCode != "" { if e.ErrorCode == "InvalidSessionKey" { - err = c.Login(account) + err = driver.Login(account) if err != nil { return nil, err } - return c.GetFiles(fileId, account) + return driver.GetFiles(fileId, account) } } if resp.ResCode != 0 { diff --git a/drivers/189cloud/driver.go b/drivers/189cloud/driver.go new file mode 100644 index 00000000..07681c27 --- /dev/null +++ b/drivers/189cloud/driver.go @@ -0,0 +1,203 @@ +package _89cloud + +import ( + "fmt" + "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers" + "github.com/Xhofe/alist/model" + "github.com/Xhofe/alist/utils" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "path/filepath" +) + +type Cloud189 struct {} + +var driverName = "189Cloud" + +func (driver Cloud189) Items() []drivers.Item { + return []drivers.Item{ + { + Name: "proxy", + Label: "proxy", + Type: "bool", + Required: true, + Description: "allow proxy", + }, + { + Name: "username", + Label: "username", + Type: "string", + Required: true, + Description: "account username/phone number", + }, + { + Name: "password", + Label: "password", + Type: "string", + Required: true, + Description: "account password", + }, + { + Name: "root_folder", + Label: "root folder file_id", + Type: "string", + Required: true, + }, + { + Name: "order_by", + Label: "order_by", + Type: "select", + Values: "name,size,lastOpTime,createdDate", + Required: true, + }, + { + Name: "order_direction", + Label: "desc", + Type: "select", + Values: "true,false", + Required: true, + }, + } +} + +func (driver Cloud189) Save(account *model.Account, old *model.Account) error { + if old != nil && old.Name != account.Name { + delete(client189Map, old.Name) + } + if err := driver.Login(account); err != nil { + account.Status = err.Error() + _ = model.SaveAccount(account) + return err + } + account.Status = "work" + err := model.SaveAccount(account) + if err != nil { + return err + } + return nil +} + +func (driver Cloud189) 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: driverName, + 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, drivers.PathNotFound +} + +func (driver Cloud189) Files(path string, account *model.Account) ([]model.File, error) { + path = utils.ParsePath(path) + var rawFiles []Cloud189File + cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path)) + if err == nil { + rawFiles, _ = cache.([]Cloud189File) + } else { + file, err := driver.File(path, account) + if err != nil { + return nil, err + } + rawFiles, err = driver.GetFiles(file.Id, account) + if err != nil { + return nil, err + } + if len(rawFiles) > 0 { + _ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), rawFiles, nil) + } + } + files := make([]model.File, 0) + for _, file := range rawFiles { + files = append(files, *driver.FormatFile(&file)) + } + return files, nil +} + +func (driver Cloud189) Link(path string, account *model.Account) (string, error) { + file, err := driver.File(utils.ParsePath(path), account) + if err != nil { + return "", err + } + if file.Type == conf.FOLDER { + return "", drivers.NotFile + } + client, ok := client189Map[account.Name] + if !ok { + return "", fmt.Errorf("can't find [%s] client", account.Name) + } + var e Cloud189Error + var resp Cloud189Down + _, err = client.R().SetResult(&resp).SetError(&e). + SetHeader("Accept", "application/json;charset=UTF-8"). + SetQueryParams(map[string]string{ + "noCache": random(), + "fileId": file.Id, + }).Get("https://cloud.189.cn/api/open/file/getFileDownloadUrl.action") + if err != nil { + return "", err + } + if e.ErrorCode != "" { + if e.ErrorCode == "InvalidSessionKey" { + err = driver.Login(account) + if err != nil { + return "", err + } + return driver.Link(path, account) + } + } + if resp.ResCode != 0 { + return "", fmt.Errorf(resp.ResMessage) + } + res, err := drivers.NoRedirectClient.R().Get(resp.FileDownloadUrl) + if err != nil { + return "", err + } + if res.StatusCode() == 302 { + return res.Header().Get("location"), nil + } + return resp.FileDownloadUrl, nil +} + +func (driver Cloud189) Path(path string, account *model.Account) (*model.File, []model.File, error) { + path = utils.ParsePath(path) + log.Debugf("189 path: %s", path) + file, err := driver.File(path, account) + if err != nil { + return nil, nil, err + } + if file.Type != conf.FOLDER { + file.Url, _ = driver.Link(path, account) + return file, nil, nil + } + files, err := driver.Files(path, account) + if err != nil { + return nil, nil, err + } + return nil, files, nil +} + +func (driver Cloud189) Proxy(ctx *gin.Context, account *model.Account) { + ctx.Request.Header.Del("Origin") +} + +func (driver Cloud189) Preview(path string, account *model.Account) (interface{}, error) { + return nil, nil +} + +var _ drivers.Driver = (*Cloud189)(nil) \ No newline at end of file diff --git a/drivers/alidrive.go b/drivers/alidrive.go deleted file mode 100644 index ddcbff8d..00000000 --- a/drivers/alidrive.go +++ /dev/null @@ -1,394 +0,0 @@ -package drivers - -import ( - "fmt" - "github.com/Xhofe/alist/conf" - "github.com/Xhofe/alist/model" - "github.com/Xhofe/alist/utils" - "github.com/gin-gonic/gin" - "github.com/go-resty/resty/v2" - "github.com/robfig/cron/v3" - log "github.com/sirupsen/logrus" - "path/filepath" - "time" -) - -var aliClient = resty.New() - -func init() { - RegisterDriver("AliDrive", &AliDrive{}) - aliClient. - SetRetryCount(3). - SetHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"). - SetHeader("content-type", "application/json"). - SetHeader("origin", "https://aliyundrive.com") -} - -type AliDrive struct{} - -func (a AliDrive) Preview(path string, account *model.Account) (interface{}, error) { - file, err := a.GetFile(path, account) - if err != nil { - return nil, err - } - // office - var resp Json - var e AliRespError - var url string - req := Json{ - "drive_id": account.DriveId, - "file_id": file.FileId, - } - switch file.Category { - case "doc": - { - url = "https://api.aliyundrive.com/v2/file/get_office_preview_url" - req["access_token"] = account.AccessToken - } - case "video": - { - url = "https://api.aliyundrive.com/v2/file/get_video_preview_play_info" - req["category"] = "live_transcoding" - } - default: - return nil, fmt.Errorf("don't support") - } - _, err = aliClient.R().SetResult(&resp).SetError(&e). - SetHeader("authorization", "Bearer\t"+account.AccessToken). - SetBody(req).Post(url) - if err != nil { - return nil, err - } - if e.Code != "" { - return nil, fmt.Errorf("%s", e.Message) - } - return resp, nil -} - -func (a AliDrive) Items() []Item { - return []Item{ - { - Name: "proxy", - Label: "proxy", - Type: "bool", - Required: true, - Description: "allow proxy", - }, - { - Name: "order_by", - Label: "order_by", - Type: "select", - Values: "name,size,updated_at,created_at", - Required: false, - }, - { - Name: "order_direction", - Label: "order_direction", - Type: "select", - Values: "ASC,DESC", - Required: false, - }, - { - Name: "refresh_token", - Label: "refresh token", - Type: "string", - Required: true, - }, - { - Name: "root_folder", - Label: "root folder file_id", - Type: "string", - Required: false, - }, - { - Name: "limit", - Label: "limit", - Type: "number", - Required: false, - Description: ">0 and <=200", - }, - } -} - -func (a AliDrive) Proxy(c *gin.Context, account *model.Account) { - c.Request.Header.Del("Origin") - c.Request.Header.Set("Referer", "https://www.aliyundrive.com/") -} - -type AliRespError struct { - Code string `json:"code"` - Message string `json:"message"` -} - -type AliFiles struct { - Items []AliFile `json:"items"` - NextMarker string `json:"next_marker"` -} - -type AliFile struct { - DriveId string `json:"drive_id"` - CreatedAt *time.Time `json:"created_at"` - FileExtension string `json:"file_extension"` - FileId string `json:"file_id"` - Type string `json:"type"` - Name string `json:"name"` - Category string `json:"category"` - ParentFileId string `json:"parent_file_id"` - UpdatedAt *time.Time `json:"updated_at"` - Size int64 `json:"size"` - Thumbnail string `json:"thumbnail"` - Url string `json:"url"` -} - -func (a AliDrive) FormatFile(file *AliFile) *model.File { - f := &model.File{ - Name: file.Name, - Size: file.Size, - UpdatedAt: file.UpdatedAt, - Thumbnail: file.Thumbnail, - Driver: "AliDrive", - Url: file.Url, - } - if file.Type == "folder" { - f.Type = conf.FOLDER - } else { - f.Type = utils.GetFileType(file.FileExtension) - } - if file.Category == "video" { - f.Type = conf.VIDEO - } - if file.Category == "image" { - f.Type = conf.IMAGE - } - return f -} - -func (a AliDrive) GetFiles(fileId string, account *model.Account) ([]AliFile, error) { - marker := "first" - res := make([]AliFile, 0) - for marker != "" { - if marker == "first" { - marker = "" - } - var resp AliFiles - var e AliRespError - _, err := aliClient.R(). - SetResult(&resp). - SetError(&e). - SetHeader("authorization", "Bearer\t"+account.AccessToken). - SetBody(Json{ - "drive_id": account.DriveId, - "fields": "*", - "image_thumbnail_process": "image/resize,w_400/format,jpeg", - "image_url_process": "image/resize,w_1920/format,jpeg", - "limit": account.Limit, - "marker": marker, - "order_by": account.OrderBy, - "order_direction": account.OrderDirection, - "parent_file_id": fileId, - "video_thumbnail_process": "video/snapshot,t_0,f_jpg,ar_auto,w_300", - "url_expire_sec": 14400, - }).Post("https://api.aliyundrive.com/v2/file/list") - if err != nil { - return nil, err - } - if e.Code != "" { - if e.Code == "AccessTokenInvalid" { - err = a.RefreshToken(account) - if err != nil { - return nil, err - } else { - _ = model.SaveAccount(account) - return a.GetFiles(fileId, account) - } - } - return nil, fmt.Errorf("%s", e.Message) - } - marker = resp.NextMarker - res = append(res, resp.Items...) - } - return res, nil -} - -func (a AliDrive) GetFile(path string, account *model.Account) (*AliFile, error) { - dir, name := filepath.Split(path) - dir = utils.ParsePath(dir) - _, _, err := a.Path(dir, account) - if err != nil { - return nil, err - } - parentFiles_, _ := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, dir)) - parentFiles, _ := parentFiles_.([]AliFile) - for _, file := range parentFiles { - if file.Name == name { - if file.Type == "file" { - return &file, err - } else { - return nil, fmt.Errorf("not file") - } - } - } - return nil, fmt.Errorf("path not found") -} - -// path: /aaa/bbb -func (a AliDrive) Path(path string, account *model.Account) (*model.File, []model.File, error) { - path = utils.ParsePath(path) - log.Debugf("ali path: %s", path) - cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path)) - if err == nil { - files, _ := cache.([]AliFile) - if len(files) != 0 { - res := make([]model.File, 0) - for _, file := range files { - res = append(res, *a.FormatFile(&file)) - } - return nil, res, nil - } - } - // no cache or len(files) == 0 - fileId := account.RootFolder - if path != "/" { - dir, name := filepath.Split(path) - dir = utils.ParsePath(dir) - _, _, err = a.Path(dir, account) - if err != nil { - return nil, nil, err - } - parentFiles_, _ := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, dir)) - parentFiles, _ := parentFiles_.([]AliFile) - found := false - for _, file := range parentFiles { - if file.Name == name { - found = true - if file.Type == "file" { - url, err := a.Link(path, account) - if err != nil { - return nil, nil, err - } - file.Url = url - return a.FormatFile(&file), nil, nil - } else { - fileId = file.FileId - break - } - } - } - if !found { - return nil, nil, fmt.Errorf("path not found") - } - } - files, err := a.GetFiles(fileId, account) - if err != nil { - return nil, nil, err - } - _ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), files, nil) - res := make([]model.File, 0) - for _, file := range files { - res = append(res, *a.FormatFile(&file)) - } - return nil, res, nil -} - -func (a AliDrive) Link(path string, account *model.Account) (string, error) { - file, err := a.GetFile(utils.ParsePath(path), account) - if err != nil { - return "", err - } - var resp Json - var e AliRespError - _, err = aliClient.R().SetResult(&resp). - SetError(&e). - SetHeader("authorization", "Bearer\t"+account.AccessToken). - SetBody(Json{ - "drive_id": account.DriveId, - "file_id": file.FileId, - "expire_sec": 14400, - }).Post("https://api.aliyundrive.com/v2/file/get_download_url") - if err != nil { - return "", err - } - if e.Code != "" { - if e.Code == "AccessTokenInvalid" { - err = a.RefreshToken(account) - if err != nil { - return "", err - } else { - _ = model.SaveAccount(account) - return a.Link(path, account) - } - } - return "", fmt.Errorf("%s", e.Message) - } - return resp["url"].(string), nil -} - -func (a AliDrive) RefreshToken(account *model.Account) error { - url := "https://auth.aliyundrive.com/v2/account/token" - var resp TokenResp - var e AliRespError - _, err := aliClient.R(). - //ForceContentType("application/json"). - SetBody(Json{"refresh_token": account.RefreshToken, "grant_type": "refresh_token"}). - SetResult(&resp). - SetError(&e). - Post(url) - if err != nil { - account.Status = err.Error() - return err - } - log.Debugf("%+v,%+v", resp, e) - if e.Code != "" { - account.Status = e.Message - return fmt.Errorf("failed to refresh token: %s", e.Message) - }else { - account.Status = "work" - } - account.RefreshToken, account.AccessToken = resp.RefreshToken, resp.AccessToken - return nil -} - -func (a AliDrive) Save(account *model.Account, old *model.Account) error { - if old != nil { - conf.Cron.Remove(cron.EntryID(old.CronId)) - } - if account.RootFolder == "" { - account.RootFolder = "root" - } - if account.Limit == 0 { - account.Limit = 200 - } - err := a.RefreshToken(account) - if err != nil { - return err - } - var resp Json - _, _ = aliClient.R().SetResult(&resp). - SetBody("{}"). - SetHeader("authorization", "Bearer\t"+account.AccessToken). - Post("https://api.aliyundrive.com/v2/user/get") - log.Debugf("user info: %+v", resp) - account.DriveId = resp["default_drive_id"].(string) - cronId, err := conf.Cron.AddFunc("@every 2h", func() { - name := account.Name - log.Debugf("ali account name: %s", name) - newAccount, ok := model.GetAccount(name) - log.Debugf("ali account: %+v", newAccount) - if !ok { - return - } - err = a.RefreshToken(&newAccount) - _ = model.SaveAccount(&newAccount) - }) - if err != nil { - return err - } - account.CronId = int(cronId) - err = model.SaveAccount(account) - if err != nil { - return err - } - return nil -} - -var _ Driver = (*AliDrive)(nil) diff --git a/drivers/alidrive/alidrive.go b/drivers/alidrive/alidrive.go new file mode 100644 index 00000000..30055741 --- /dev/null +++ b/drivers/alidrive/alidrive.go @@ -0,0 +1,165 @@ +package alidrive + +import ( + "fmt" + "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers" + "github.com/Xhofe/alist/model" + "github.com/Xhofe/alist/utils" + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" + "path/filepath" + "time" +) + +var aliClient = resty.New() + +type AliRespError struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type AliFiles struct { + Items []AliFile `json:"items"` + NextMarker string `json:"next_marker"` +} + +type AliFile struct { + DriveId string `json:"drive_id"` + CreatedAt *time.Time `json:"created_at"` + FileExtension string `json:"file_extension"` + FileId string `json:"file_id"` + Type string `json:"type"` + Name string `json:"name"` + Category string `json:"category"` + ParentFileId string `json:"parent_file_id"` + UpdatedAt *time.Time `json:"updated_at"` + Size int64 `json:"size"` + Thumbnail string `json:"thumbnail"` + Url string `json:"url"` +} + +func (driver AliDrive) FormatFile(file *AliFile) *model.File { + f := &model.File{ + Id: file.FileId, + Name: file.Name, + Size: file.Size, + UpdatedAt: file.UpdatedAt, + Thumbnail: file.Thumbnail, + Driver: driverName, + Url: file.Url, + } + if file.Type == "folder" { + f.Type = conf.FOLDER + } else { + f.Type = utils.GetFileType(file.FileExtension) + } + if file.Category == "video" { + f.Type = conf.VIDEO + } + if file.Category == "image" { + f.Type = conf.IMAGE + } + return f +} + +func (driver AliDrive) GetFiles(fileId string, account *model.Account) ([]AliFile, error) { + marker := "first" + res := make([]AliFile, 0) + for marker != "" { + if marker == "first" { + marker = "" + } + var resp AliFiles + var e AliRespError + _, err := aliClient.R(). + SetResult(&resp). + SetError(&e). + SetHeader("authorization", "Bearer\t"+account.AccessToken). + SetBody(drivers.Json{ + "drive_id": account.DriveId, + "fields": "*", + "image_thumbnail_process": "image/resize,w_400/format,jpeg", + "image_url_process": "image/resize,w_1920/format,jpeg", + "limit": account.Limit, + "marker": marker, + "order_by": account.OrderBy, + "order_direction": account.OrderDirection, + "parent_file_id": fileId, + "video_thumbnail_process": "video/snapshot,t_0,f_jpg,ar_auto,w_300", + "url_expire_sec": 14400, + }).Post("https://api.aliyundrive.com/v2/file/list") + if err != nil { + return nil, err + } + if e.Code != "" { + if e.Code == "AccessTokenInvalid" { + err = driver.RefreshToken(account) + if err != nil { + return nil, err + } else { + _ = model.SaveAccount(account) + return driver.GetFiles(fileId, account) + } + } + return nil, fmt.Errorf("%s", e.Message) + } + marker = resp.NextMarker + res = append(res, resp.Items...) + } + return res, nil +} + +func (driver AliDrive) GetFile(path string, account *model.Account) (*AliFile, error) { + dir, name := filepath.Split(path) + _, err := driver.Files(dir, account) + if err != nil { + return nil, err + } + parentFiles_, _ := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, dir)) + parentFiles, _ := parentFiles_.([]AliFile) + for _, file := range parentFiles { + if file.Name == name { + if file.Type == "file" { + return &file, err + } else { + return nil, fmt.Errorf("not file") + } + } + } + return nil, drivers.PathNotFound +} + +func (driver AliDrive) RefreshToken(account *model.Account) error { + url := "https://auth.aliyundrive.com/v2/account/token" + var resp drivers.TokenResp + var e AliRespError + _, err := aliClient.R(). + //ForceContentType("application/json"). + SetBody(drivers.Json{"refresh_token": account.RefreshToken, "grant_type": "refresh_token"}). + SetResult(&resp). + SetError(&e). + Post(url) + if err != nil { + account.Status = err.Error() + return err + } + log.Debugf("%+v,%+v", resp, e) + if e.Code != "" { + account.Status = e.Message + return fmt.Errorf("failed to refresh token: %s", e.Message) + } else { + account.Status = "work" + } + account.RefreshToken, account.AccessToken = resp.RefreshToken, resp.AccessToken + return nil +} + +func init() { + drivers.RegisterDriver(driverName, &AliDrive{}) + aliClient. + SetRetryCount(3). + SetHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"). + SetHeader("content-type", "application/json"). + SetHeader("origin", "https://aliyundrive.com") +} diff --git a/drivers/alidrive/driver.go b/drivers/alidrive/driver.go new file mode 100644 index 00000000..5fd55260 --- /dev/null +++ b/drivers/alidrive/driver.go @@ -0,0 +1,253 @@ +package alidrive + +import ( + "fmt" + "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers" + "github.com/Xhofe/alist/model" + "github.com/Xhofe/alist/utils" + "github.com/gin-gonic/gin" + "github.com/robfig/cron/v3" + log "github.com/sirupsen/logrus" + "path/filepath" +) + +type AliDrive struct{} + +var driverName = "AliDrive" + +func (driver AliDrive) Items() []drivers.Item { + return []drivers.Item{ + { + Name: "proxy", + Label: "proxy", + Type: "bool", + Required: true, + Description: "allow proxy", + }, + { + Name: "order_by", + Label: "order_by", + Type: "select", + Values: "name,size,updated_at,created_at", + Required: false, + }, + { + Name: "order_direction", + Label: "order_direction", + Type: "select", + Values: "ASC,DESC", + Required: false, + }, + { + Name: "refresh_token", + Label: "refresh token", + Type: "string", + Required: true, + }, + { + Name: "root_folder", + Label: "root folder file_id", + Type: "string", + Required: false, + }, + { + Name: "limit", + Label: "limit", + Type: "number", + Required: false, + Description: ">0 and <=200", + }, + } +} + +func (driver AliDrive) Save(account *model.Account, old *model.Account) error { + if old != nil { + conf.Cron.Remove(cron.EntryID(old.CronId)) + } + if account.RootFolder == "" { + account.RootFolder = "root" + } + if account.Limit == 0 { + account.Limit = 200 + } + err := driver.RefreshToken(account) + if err != nil { + return err + } + var resp drivers.Json + _, _ = aliClient.R().SetResult(&resp). + SetBody("{}"). + SetHeader("authorization", "Bearer\t"+account.AccessToken). + Post("https://api.aliyundrive.com/v2/user/get") + log.Debugf("user info: %+v", resp) + account.DriveId = resp["default_drive_id"].(string) + cronId, err := conf.Cron.AddFunc("@every 2h", func() { + name := account.Name + log.Debugf("ali account name: %s", name) + newAccount, ok := model.GetAccount(name) + log.Debugf("ali account: %+v", newAccount) + if !ok { + return + } + err = driver.RefreshToken(&newAccount) + _ = model.SaveAccount(&newAccount) + }) + if err != nil { + return err + } + account.CronId = int(cronId) + err = model.SaveAccount(account) + if err != nil { + return err + } + return nil +} + +func (driver AliDrive) 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: driverName, + 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, drivers.PathNotFound +} + +func (driver AliDrive) Files(path string, account *model.Account) ([]model.File, error) { + path = utils.ParsePath(path) + var rawFiles []AliFile + cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path)) + if err == nil { + rawFiles, _ = cache.([]AliFile) + } else { + file, err := driver.File(path, account) + if err != nil { + return nil, err + } + rawFiles, err = driver.GetFiles(file.Id, account) + if err != nil { + return nil, err + } + if len(rawFiles) > 0 { + _ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), rawFiles, nil) + } + } + files := make([]model.File, 0) + for _, file := range rawFiles { + files = append(files, *driver.FormatFile(&file)) + } + return files, nil +} + +func (driver AliDrive) Link(path string, account *model.Account) (string, error) { + file, err := driver.File(path, account) + if err != nil { + return "", err + } + var resp drivers.Json + var e AliRespError + _, err = aliClient.R().SetResult(&resp). + SetError(&e). + SetHeader("authorization", "Bearer\t"+account.AccessToken). + SetBody(drivers.Json{ + "drive_id": account.DriveId, + "file_id": file.Id, + "expire_sec": 14400, + }).Post("https://api.aliyundrive.com/v2/file/get_download_url") + if err != nil { + return "", err + } + if e.Code != "" { + if e.Code == "AccessTokenInvalid" { + err = driver.RefreshToken(account) + if err != nil { + return "", err + } else { + _ = model.SaveAccount(account) + return driver.Link(path, account) + } + } + return "", fmt.Errorf("%s", e.Message) + } + return resp["url"].(string), nil +} + +func (driver AliDrive) Path(path string, account *model.Account) (*model.File, []model.File, error) { + path = utils.ParsePath(path) + log.Debugf("ali path: %s", path) + file, err := driver.File(path, account) + if err != nil { + return nil, nil, err + } + if file.Type != conf.FOLDER { + file.Url, _ = driver.Link(path, account) + return file, nil, nil + } + files, err := driver.Files(path, account) + if err != nil { + return nil, nil, err + } + return nil, files, nil +} + +func (driver AliDrive) Proxy(c *gin.Context, account *model.Account) { + c.Request.Header.Del("Origin") + c.Request.Header.Set("Referer", "https://www.aliyundrive.com/") +} + +func (driver AliDrive) Preview(path string, account *model.Account) (interface{}, error) { + file, err := driver.GetFile(path, account) + if err != nil { + return nil, err + } + // office + var resp drivers.Json + var e AliRespError + var url string + req := drivers.Json{ + "drive_id": account.DriveId, + "file_id": file.FileId, + } + switch file.Category { + case "doc": + { + url = "https://api.aliyundrive.com/v2/file/get_office_preview_url" + req["access_token"] = account.AccessToken + } + case "video": + { + url = "https://api.aliyundrive.com/v2/file/get_video_preview_play_info" + req["category"] = "live_transcoding" + } + default: + return nil, fmt.Errorf("don't support") + } + _, err = aliClient.R().SetResult(&resp).SetError(&e). + SetHeader("authorization", "Bearer\t"+account.AccessToken). + SetBody(req).Post(url) + if err != nil { + return nil, err + } + if e.Code != "" { + return nil, fmt.Errorf("%s", e.Message) + } + return resp, nil +} + +var _ drivers.Driver = (*AliDrive)(nil) \ No newline at end of file diff --git a/drivers/driver.go b/drivers/driver.go index 1e52f87f..ac52d4d4 100644 --- a/drivers/driver.go +++ b/drivers/driver.go @@ -4,16 +4,17 @@ import ( "github.com/Xhofe/alist/model" "github.com/gin-gonic/gin" "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" "net/http" ) type Driver interface { Items() []Item Save(account *model.Account, old *model.Account) error - //File(path string, account *model.Account) (*model.File, error) - //Files(path string, account *model.Account) ([]model.File, error) - Path(path string, account *model.Account) (*model.File, []model.File, error) + File(path string, account *model.Account) (*model.File, error) + Files(path string, account *model.Account) ([]model.File, error) Link(path string, account *model.Account) (string, error) + Path(path string, account *model.Account) (*model.File, []model.File, error) Proxy(c *gin.Context, account *model.Account) Preview(path string, account *model.Account) (interface{}, error) // TODO @@ -41,6 +42,7 @@ type TokenResp struct { var driversMap = map[string]Driver{} func RegisterDriver(name string, driver Driver) { + log.Infof("register driver: [%s]", name) driversMap[name] = driver } @@ -59,10 +61,10 @@ func GetDrivers() map[string][]Item { type Json map[string]interface{} -var noRedirectClient *resty.Client +var NoRedirectClient *resty.Client func init() { - noRedirectClient = resty.New().SetRedirectPolicy( + NoRedirectClient = resty.New().SetRedirectPolicy( resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }), diff --git a/drivers/googledrive.go b/drivers/googledrive.go index acdf5050..cfa5201d 100644 --- a/drivers/googledrive.go +++ b/drivers/googledrive.go @@ -16,6 +16,14 @@ import ( type GoogleDrive struct { } +func (g GoogleDrive) File(path string, account *model.Account) (*model.File, error) { + panic("implement me") +} + +func (g GoogleDrive) Files(path string, account *model.Account) ([]model.File, error) { + panic("implement me") +} + var googleClient = resty.New() func (g GoogleDrive) Items() []Item { diff --git a/drivers/native.go b/drivers/native.go index 73e88778..dc2c10cd 100644 --- a/drivers/native.go +++ b/drivers/native.go @@ -16,6 +16,14 @@ import ( type Native struct { } +func (n Native) File(path string, account *model.Account) (*model.File, error) { + panic("implement me") +} + +func (n Native) Files(path string, account *model.Account) ([]model.File, error) { + panic("implement me") +} + func (n Native) Preview(path string, account *model.Account) (interface{}, error) { return nil, fmt.Errorf("no need") } diff --git a/drivers/onedrive.go b/drivers/onedrive.go index b0b33213..a7c83d63 100644 --- a/drivers/onedrive.go +++ b/drivers/onedrive.go @@ -15,6 +15,14 @@ import ( type Onedrive struct{} +func (o Onedrive) File(path string, account *model.Account) (*model.File, error) { + panic("implement me") +} + +func (o Onedrive) Files(path string, account *model.Account) ([]model.File, error) { + panic("implement me") +} + var oneClient = resty.New() type OnedriveHost struct {