alist/drivers/alidrive.go

395 lines
9.7 KiB
Go
Raw Normal View History

2021-10-27 10:59:03 +00:00
package drivers
import (
2021-10-27 14:45:36 +00:00
"fmt"
2021-10-27 10:59:03 +00:00
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/model"
2021-10-28 04:37:31 +00:00
"github.com/Xhofe/alist/utils"
2021-11-13 07:53:26 +00:00
"github.com/gin-gonic/gin"
2021-10-27 14:45:36 +00:00
"github.com/go-resty/resty/v2"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus"
2021-10-28 14:50:09 +00:00
"path/filepath"
2021-10-27 10:59:03 +00:00
"time"
)
2021-10-27 14:45:36 +00:00
var aliClient = resty.New()
func init() {
2021-10-29 06:50:26 +00:00
RegisterDriver("AliDrive", &AliDrive{})
2021-10-27 14:45:36 +00:00
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")
}
2021-10-29 16:35:29 +00:00
type AliDrive struct{}
2021-10-29 06:50:26 +00:00
2021-10-31 13:27:47 +00:00
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,
2021-11-01 14:42:24 +00:00
"file_id": file.FileId,
2021-10-31 13:27:47 +00:00
}
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 != "" {
2021-11-01 14:42:24 +00:00
return nil, fmt.Errorf("%s", e.Message)
2021-10-31 13:27:47 +00:00
}
return resp, nil
}
2021-10-29 06:50:26 +00:00
func (a AliDrive) Items() []Item {
return []Item{
2021-11-17 09:20:57 +00:00
{
Name: "proxy",
Label: "proxy",
Type: "bool",
Required: true,
Description: "allow proxy",
},
2021-11-12 11:39:01 +00:00
{
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,
},
2021-10-29 06:50:26 +00:00
{
Name: "refresh_token",
Label: "refresh token",
Type: "string",
Required: true,
},
{
Name: "root_folder",
Label: "root folder file_id",
Type: "string",
Required: false,
},
2021-11-03 02:37:33 +00:00
{
Name: "limit",
Label: "limit",
Type: "number",
Required: false,
Description: ">0 and <=200",
},
2021-10-29 06:50:26 +00:00
}
2021-10-27 10:59:03 +00:00
}
2021-11-17 08:37:12 +00:00
func (a AliDrive) Proxy(c *gin.Context, account *model.Account) {
2021-11-13 07:53:26 +00:00
c.Request.Header.Del("Origin")
c.Request.Header.Set("Referer", "https://www.aliyundrive.com/")
2021-10-28 16:02:02 +00:00
}
2021-10-27 10:59:03 +00:00
type AliRespError struct {
Code string `json:"code"`
Message string `json:"message"`
}
2021-10-28 14:50:09 +00:00
type AliFiles struct {
Items []AliFile `json:"items"`
NextMarker string `json:"next_marker"`
}
2021-10-27 10:59:03 +00:00
type AliFile struct {
2021-10-28 14:50:09 +00:00
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"`
2021-10-30 16:36:17 +00:00
Category string `json:"category"`
2021-10-28 14:50:09 +00:00
ParentFileId string `json:"parent_file_id"`
UpdatedAt *time.Time `json:"updated_at"`
Size int64 `json:"size"`
Thumbnail string `json:"thumbnail"`
Url string `json:"url"`
2021-10-27 10:59:03 +00:00
}
2021-11-02 15:53:05 +00:00
func (a AliDrive) FormatFile(file *AliFile) *model.File {
2021-10-29 16:35:29 +00:00
f := &model.File{
2021-10-28 04:37:31 +00:00
Name: file.Name,
Size: file.Size,
UpdatedAt: file.UpdatedAt,
2021-10-29 16:35:29 +00:00
Thumbnail: file.Thumbnail,
2021-10-30 16:36:17 +00:00
Driver: "AliDrive",
2021-11-01 14:42:24 +00:00
Url: file.Url,
2021-10-28 04:37:31 +00:00
}
2021-10-29 16:35:29 +00:00
if file.Type == "folder" {
f.Type = conf.FOLDER
} else {
f.Type = utils.GetFileType(file.FileExtension)
}
2021-10-30 16:36:17 +00:00
if file.Category == "video" {
f.Type = conf.VIDEO
}
if file.Category == "image" {
f.Type = conf.IMAGE
}
2021-10-29 16:35:29 +00:00
return f
2021-10-28 04:37:31 +00:00
}
2021-10-28 14:50:09 +00:00
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).
2021-11-02 15:53:05 +00:00
SetBody(Json{
2021-10-28 14:50:09 +00:00
"drive_id": account.DriveId,
"fields": "*",
2021-10-30 09:34:34 +00:00
"image_thumbnail_process": "image/resize,w_400/format,jpeg",
2021-10-28 14:50:09 +00:00
"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,
2021-10-30 09:34:34 +00:00
"video_thumbnail_process": "video/snapshot,t_0,f_jpg,ar_auto,w_300",
2021-11-01 14:42:24 +00:00
"url_expire_sec": 14400,
2021-11-02 15:53:05 +00:00
}).Post("https://api.aliyundrive.com/v2/file/list")
2021-10-28 14:50:09 +00:00
if err != nil {
return nil, err
}
if e.Code != "" {
2021-11-02 15:53:05 +00:00
if e.Code == "AccessTokenInvalid" {
err = a.RefreshToken(account)
if err != nil {
return nil, err
} else {
2021-11-13 11:31:35 +00:00
_ = model.SaveAccount(account)
2021-11-02 15:53:05 +00:00
return a.GetFiles(fileId, account)
}
}
2021-10-28 14:50:09 +00:00
return nil, fmt.Errorf("%s", e.Message)
}
marker = resp.NextMarker
res = append(res, resp.Items...)
}
return res, nil
}
2021-10-31 13:27:47 +00:00
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")
}
2021-10-28 04:37:31 +00:00
// path: /aaa/bbb
2021-11-23 07:58:03 +00:00
func (a AliDrive) Path(path string, account *model.Account) (*model.File, []model.File, error) {
2021-10-28 14:50:09 +00:00
path = utils.ParsePath(path)
log.Debugf("ali path: %s", path)
2021-10-29 16:35:29 +00:00
cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path))
2021-10-27 10:59:03 +00:00
if err == nil {
2021-11-17 08:25:32 +00:00
files, _ := cache.([]AliFile)
if len(files) != 0 {
2021-11-23 07:58:03 +00:00
res := make([]model.File, 0)
2021-11-17 08:25:32 +00:00
for _, file := range files {
2021-11-23 07:58:03 +00:00
res = append(res, *a.FormatFile(&file))
2021-10-28 14:50:09 +00:00
}
2021-11-17 08:25:32 +00:00
return nil, res, nil
2021-10-28 14:50:09 +00:00
}
2021-11-05 08:30:50 +00:00
}
// 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)
2021-10-28 14:50:09 +00:00
if err != nil {
return nil, nil, err
}
2021-11-05 08:30:50 +00:00
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")
2021-10-28 04:37:31 +00:00
}
}
2021-11-05 08:30:50 +00:00
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)
2021-11-23 07:58:03 +00:00
res := make([]model.File, 0)
2021-11-05 08:30:50 +00:00
for _, file := range files {
2021-11-23 07:58:03 +00:00
res = append(res, *a.FormatFile(&file))
2021-11-05 08:30:50 +00:00
}
return nil, res, nil
2021-10-27 10:59:03 +00:00
}
func (a AliDrive) Link(path string, account *model.Account) (string, error) {
2021-11-01 14:42:24 +00:00
file, err := a.GetFile(utils.ParsePath(path), account)
2021-10-28 14:50:09 +00:00
if err != nil {
return "", err
}
2021-10-31 13:27:47 +00:00
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 != "" {
2021-11-02 15:53:05 +00:00
if e.Code == "AccessTokenInvalid" {
err = a.RefreshToken(account)
if err != nil {
return "", err
} else {
2021-11-13 11:31:35 +00:00
_ = model.SaveAccount(account)
2021-11-02 15:53:05 +00:00
return a.Link(path, account)
}
}
2021-10-31 13:27:47 +00:00
return "", fmt.Errorf("%s", e.Message)
2021-10-28 14:50:09 +00:00
}
2021-10-31 13:27:47 +00:00
return resp["url"].(string), nil
2021-10-27 10:59:03 +00:00
}
2021-11-02 15:53:05 +00:00
func (a AliDrive) RefreshToken(account *model.Account) error {
2021-10-27 14:45:36 +00:00
url := "https://auth.aliyundrive.com/v2/account/token"
2021-11-02 15:53:05 +00:00
var resp TokenResp
2021-10-27 14:45:36 +00:00
var e AliRespError
_, err := aliClient.R().
//ForceContentType("application/json").
2021-11-02 15:53:05 +00:00
SetBody(Json{"refresh_token": account.RefreshToken, "grant_type": "refresh_token"}).
2021-10-27 14:45:36 +00:00
SetResult(&resp).
SetError(&e).
Post(url)
if err != nil {
2021-11-05 08:30:50 +00:00
account.Status = err.Error()
2021-11-02 15:53:05 +00:00
return err
2021-10-27 14:45:36 +00:00
}
log.Debugf("%+v,%+v", resp, e)
if e.Code != "" {
2021-11-05 08:30:50 +00:00
account.Status = e.Message
2021-11-02 15:53:05 +00:00
return fmt.Errorf("failed to refresh token: %s", e.Message)
2021-11-15 07:01:14 +00:00
}else {
account.Status = "work"
2021-10-27 14:45:36 +00:00
}
2021-11-02 15:53:05 +00:00
account.RefreshToken, account.AccessToken = resp.RefreshToken, resp.AccessToken
return nil
2021-10-27 14:45:36 +00:00
}
2021-10-27 10:59:03 +00:00
func (a AliDrive) Save(account *model.Account, old *model.Account) error {
if old != nil {
2021-10-27 14:45:36 +00:00
conf.Cron.Remove(cron.EntryID(old.CronId))
2021-10-27 10:59:03 +00:00
}
2021-10-29 06:50:26 +00:00
if account.RootFolder == "" {
account.RootFolder = "root"
}
2021-10-29 16:35:29 +00:00
if account.Limit == 0 {
account.Limit = 200
}
2021-11-02 15:53:05 +00:00
err := a.RefreshToken(account)
2021-10-27 14:45:36 +00:00
if err != nil {
return err
}
2021-10-28 14:50:09 +00:00
var resp Json
_, _ = aliClient.R().SetResult(&resp).
SetBody("{}").
2021-11-02 15:53:05 +00:00
SetHeader("authorization", "Bearer\t"+account.AccessToken).
2021-10-28 14:50:09 +00:00
Post("https://api.aliyundrive.com/v2/user/get")
log.Debugf("user info: %+v", resp)
account.DriveId = resp["default_drive_id"].(string)
2021-10-27 14:45:36 +00:00
cronId, err := conf.Cron.AddFunc("@every 2h", func() {
name := account.Name
2021-11-15 06:54:22 +00:00
log.Debugf("ali account name: %s", name)
2021-10-27 14:45:36 +00:00
newAccount, ok := model.GetAccount(name)
2021-11-15 06:54:22 +00:00
log.Debugf("ali account: %+v", newAccount)
2021-10-27 14:45:36 +00:00
if !ok {
return
}
2021-11-02 15:53:05 +00:00
err = a.RefreshToken(&newAccount)
2021-11-13 11:31:35 +00:00
_ = model.SaveAccount(&newAccount)
2021-10-27 14:45:36 +00:00
})
if err != nil {
return err
}
account.CronId = int(cronId)
2021-11-13 11:31:35 +00:00
err = model.SaveAccount(account)
2021-10-27 14:45:36 +00:00
if err != nil {
return err
}
return nil
2021-10-27 10:59:03 +00:00
}
var _ Driver = (*AliDrive)(nil)