Skip to content

Commit

Permalink
feat: add aliyundrive share driver (close #1215)
Browse files Browse the repository at this point in the history
  • Loading branch information
xhofe committed Sep 21, 2022
1 parent 9382f66 commit 3537153
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 0 deletions.
144 changes: 144 additions & 0 deletions drivers/aliyundrive_share/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package aliyundrive_share

import (
"context"
"errors"
"net/http"
"time"

"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/cron"
"github.com/alist-org/alist/v3/pkg/utils"
log "github.com/sirupsen/logrus"
)

type AliyundriveShare struct {
model.Storage
Addition
AccessToken string
ShareToken string
DriveId string
cron *cron.Cron
}

func (d *AliyundriveShare) Config() driver.Config {
return config
}

func (d *AliyundriveShare) GetAddition() driver.Additional {
return d.Addition
}

func (d *AliyundriveShare) Init(ctx context.Context, storage model.Storage) error {
d.Storage = storage
err := utils.Json.UnmarshalFromString(d.Storage.Addition, &d.Addition)
if err != nil {
return err
}
err = d.refreshToken()
if err != nil {
return err
}
err = d.getShareToken()
if err != nil {
return err
}
d.cron = cron.NewCron(time.Hour * 2)
d.cron.Do(func() {
err := d.refreshToken()
if err != nil {
log.Errorf("%+v", err)
}
})
return nil
}

func (d *AliyundriveShare) Drop(ctx context.Context) error {
if d.cron != nil {
d.cron.Stop()
}
return nil
}

func (d *AliyundriveShare) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
files, err := d.getFiles(dir.GetID())
if err != nil {
return nil, err
}
return utils.SliceConvert(files, func(src File) (model.Obj, error) {
return fileToObj(src), nil
})
}

//func (d *AliyundriveShare) Get(ctx context.Context, path string) (model.Obj, error) {
// // this is optional
// return nil, errs.NotImplement
//}

func (d *AliyundriveShare) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
data := base.Json{
"drive_id": d.DriveId,
"file_id": file.GetID(),
"expire_sec": 14400,
}
var e ErrorResp
res, err := base.RestyClient.R().
SetError(&e).SetBody(data).
SetHeader("content-type", "application/json").
SetHeader("Authorization", "Bearer\t"+d.AccessToken).
Post("https://api.aliyundrive.com/v2/file/get_download_url")
if err != nil {
return nil, err
}
if e.Code != "" {
if e.Code == "AccessTokenInvalid" {
err = d.refreshToken()
if err != nil {
return nil, err
}
return d.Link(ctx, file, args)
}
return nil, errors.New(e.Message)
}
return &model.Link{
Header: http.Header{
"Referer": []string{"https://www.aliyundrive.com/"},
},
URL: utils.Json.Get(res.Body(), "url").ToString(),
}, nil
}

func (d *AliyundriveShare) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
// TODO create folder
return errs.NotSupport
}

func (d *AliyundriveShare) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
// TODO move obj
return errs.NotSupport
}

func (d *AliyundriveShare) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
// TODO rename obj
return errs.NotSupport
}

func (d *AliyundriveShare) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
// TODO copy obj
return errs.NotSupport
}

func (d *AliyundriveShare) Remove(ctx context.Context, obj model.Obj) error {
// TODO remove obj
return errs.NotSupport
}

func (d *AliyundriveShare) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
// TODO upload file
return errs.NotSupport
}

var _ driver.Driver = (*AliyundriveShare)(nil)
29 changes: 29 additions & 0 deletions drivers/aliyundrive_share/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package aliyundrive_share

import (
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/op"
)

type Addition struct {
RefreshToken string `json:"refresh_token" required:"true"`
ShareId string `json:"share_id" required:"true"`
SharePwd string `json:"share_pwd"`
driver.RootID
OrderBy string `json:"order_by" type:"select" options:"name,size,updated_at,created_at"`
OrderDirection string `json:"order_direction" type:"select" options:"ASC,DESC"`
}

var config = driver.Config{
Name: "AliyundriveShare",
LocalSort: false,
OnlyProxy: false,
NoUpload: true,
DefaultRoot: "root",
}

func init() {
op.RegisterDriver(config, func() driver.Driver {
return &AliyundriveShare{}
})
}
57 changes: 57 additions & 0 deletions drivers/aliyundrive_share/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package aliyundrive_share

import (
"time"

"github.com/alist-org/alist/v3/internal/model"
)

type ErrorResp struct {
Code string `json:"code"`
Message string `json:"message"`
}

type ShareTokenResp struct {
ShareToken string `json:"share_token"`
ExpireTime time.Time `json:"expire_time"`
ExpiresIn int `json:"expires_in"`
}

type ListResp struct {
Items []File `json:"items"`
NextMarker string `json:"next_marker"`
PunishedFileCount int `json:"punished_file_count"`
}

type File struct {
DriveId string `json:"drive_id"`
DomainId string `json:"domain_id"`
FileId string `json:"file_id"`
ShareId string `json:"share_id"`
Name string `json:"name"`
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ParentFileId string `json:"parent_file_id"`
Size int64 `json:"size"`
Thumbnail string `json:"thumbnail"`
}

func fileToObj(f File) *model.ObjThumb {
return &model.ObjThumb{
Object: model.Object{
ID: f.FileId,
Name: f.Name,
Size: f.Size,
Modified: f.UpdatedAt,
IsFolder: f.Type == "folder",
},
Thumbnail: model.Thumbnail{Thumbnail: f.Thumbnail},
}
}

//type ShareLinkResp struct {
// DownloadUrl string `json:"download_url"`
// Url string `json:"url"`
// Thumbnail string `json:"thumbnail"`
//}
99 changes: 99 additions & 0 deletions drivers/aliyundrive_share/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package aliyundrive_share

import (
"errors"
"fmt"

"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/op"
log "github.com/sirupsen/logrus"
)

func (d *AliyundriveShare) refreshToken() error {
url := "https://auth.aliyundrive.com/v2/account/token"
var resp base.TokenResp
var e ErrorResp
_, err := base.RestyClient.R().
SetBody(base.Json{"refresh_token": d.RefreshToken, "grant_type": "refresh_token"}).
SetResult(&resp).
SetError(&e).
Post(url)
if err != nil {
return err
}
if e.Code != "" {
return fmt.Errorf("failed to refresh token: %s", e.Message)
}
d.RefreshToken, d.AccessToken = resp.RefreshToken, resp.AccessToken
op.MustSaveDriverStorage(d)
return nil
}

// do others that not defined in Driver interface
func (d *AliyundriveShare) getShareToken() error {
data := base.Json{
"share_id": d.ShareId,
}
if d.SharePwd != "" {
data["share_pwd"] = d.SharePwd
}
var e ErrorResp
var resp ShareTokenResp
_, err := base.RestyClient.R().
SetResult(&resp).SetError(&e).SetBody(data).
Post("https://api.aliyundrive.com/v2/share_link/get_share_token")
if err != nil {
return err
}
if e.Code != "" {
return errors.New(e.Message)
}
d.ShareToken = resp.ShareToken
return nil
}

func (d *AliyundriveShare) getFiles(fileId string) ([]File, error) {
files := make([]File, 0)
data := base.Json{
"image_thumbnail_process": "image/resize,w_160/format,jpeg",
"image_url_process": "image/resize,w_1920/format,jpeg",
"limit": 100,
"order_by": d.OrderBy,
"order_direction": d.OrderDirection,
"parent_file_id": fileId,
"share_id": d.ShareId,
"video_thumbnail_process": "video/snapshot,t_1000,f_jpg,ar_auto,w_300",
"marker": "first",
}
for data["marker"] != "" {
if data["marker"] == "first" {
data["marker"] = ""
}
var e ErrorResp
var resp ListResp
res, err := base.RestyClient.R().
SetHeader("x-share-token", d.ShareToken).
SetResult(&resp).SetError(&e).SetBody(data).
Post("https://api.aliyundrive.com/adrive/v3/file/list")
if err != nil {
return nil, err
}
log.Debugf("aliyundrive share get files: %s", res.String())
if e.Code != "" {
if e.Code == "AccessTokenInvalid" {
err = d.getShareToken()
if err != nil {
return nil, err
}
return d.getFiles(fileId)
}
return nil, errors.New(e.Message)
}
data["marker"] = resp.NextMarker
files = append(files, resp.Items...)
}
if len(files) > 0 && d.DriveId == "" {
d.DriveId = files[0].DriveId
}
return files, nil
}
1 change: 1 addition & 0 deletions drivers/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
_ "github.com/alist-org/alist/v3/drivers/189"
_ "github.com/alist-org/alist/v3/drivers/189pc"
_ "github.com/alist-org/alist/v3/drivers/aliyundrive"
_ "github.com/alist-org/alist/v3/drivers/aliyundrive_share"
_ "github.com/alist-org/alist/v3/drivers/baidu_netdisk"
_ "github.com/alist-org/alist/v3/drivers/baidu_photo"
_ "github.com/alist-org/alist/v3/drivers/ftp"
Expand Down

1 comment on commit 3537153

@HW-Renew
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-done!

Please sign in to comment.