-
-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package yandex_disk | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"path" | ||
"strconv" | ||
|
||
"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/utils" | ||
"github.com/go-resty/resty/v2" | ||
) | ||
|
||
type YandexDisk struct { | ||
model.Storage | ||
Addition | ||
AccessToken string | ||
} | ||
|
||
func (d *YandexDisk) Config() driver.Config { | ||
return config | ||
} | ||
|
||
func (d *YandexDisk) GetAddition() driver.Additional { | ||
return d.Addition | ||
} | ||
|
||
func (d *YandexDisk) 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 | ||
} | ||
return d.refreshToken() | ||
} | ||
|
||
func (d *YandexDisk) Drop(ctx context.Context) error { | ||
return nil | ||
} | ||
|
||
func (d *YandexDisk) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { | ||
files, err := d.getFiles(dir.GetPath()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return utils.SliceConvert(files, func(src File) (model.Obj, error) { | ||
return fileToObj(src), nil | ||
}) | ||
} | ||
|
||
//func (d *YandexDisk) Get(ctx context.Context, path string) (model.Obj, error) { | ||
// // this is optional | ||
// return nil, errs.NotImplement | ||
//} | ||
|
||
func (d *YandexDisk) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { | ||
var resp DownResp | ||
_, err := d.request("/download", http.MethodGet, func(req *resty.Request) { | ||
req.SetQueryParam("path", file.GetPath()) | ||
}, &resp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
link := model.Link{ | ||
URL: resp.Href, | ||
} | ||
return &link, nil | ||
} | ||
|
||
func (d *YandexDisk) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { | ||
_, err := d.request("", http.MethodPut, func(req *resty.Request) { | ||
req.SetQueryParam("path", path.Join(parentDir.GetPath(), dirName)) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *YandexDisk) Move(ctx context.Context, srcObj, dstDir model.Obj) error { | ||
_, err := d.request("/move", http.MethodPost, func(req *resty.Request) { | ||
req.SetQueryParams(map[string]string{ | ||
"from": srcObj.GetPath(), | ||
"path": path.Join(dstDir.GetPath(), srcObj.GetName()), | ||
"overwrite": "true", | ||
}) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *YandexDisk) Rename(ctx context.Context, srcObj model.Obj, newName string) error { | ||
_, err := d.request("/move", http.MethodPost, func(req *resty.Request) { | ||
req.SetQueryParams(map[string]string{ | ||
"from": srcObj.GetPath(), | ||
"path": path.Join(path.Dir(srcObj.GetPath()), newName), | ||
"overwrite": "true", | ||
}) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *YandexDisk) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { | ||
_, err := d.request("/copy", http.MethodPost, func(req *resty.Request) { | ||
req.SetQueryParams(map[string]string{ | ||
"from": srcObj.GetPath(), | ||
"path": path.Join(dstDir.GetPath(), srcObj.GetName()), | ||
"overwrite": "true", | ||
}) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *YandexDisk) Remove(ctx context.Context, obj model.Obj) error { | ||
_, err := d.request("", http.MethodDelete, func(req *resty.Request) { | ||
req.SetQueryParam("path", obj.GetPath()) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *YandexDisk) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { | ||
var resp UploadResp | ||
_, err := d.request("/upload", http.MethodGet, func(req *resty.Request) { | ||
req.SetQueryParams(map[string]string{ | ||
"path": path.Join(dstDir.GetPath(), stream.GetName()), | ||
"overwrite": "true", | ||
}) | ||
}, &resp) | ||
if err != nil { | ||
return err | ||
} | ||
req, err := http.NewRequest(resp.Method, resp.Href, stream) | ||
if err != nil { | ||
return err | ||
} | ||
req.Header.Set("Content-Length", strconv.FormatInt(stream.GetSize(), 10)) | ||
req.Header.Set("Content-Type", "application/octet-stream") | ||
res, err := base.HttpClient.Do(req) | ||
res.Body.Close() | ||
return err | ||
} | ||
|
||
func (d *YandexDisk) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { | ||
return nil, errs.NotSupport | ||
} | ||
|
||
var _ driver.Driver = (*YandexDisk)(nil) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package yandex_disk | ||
|
||
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"` | ||
OrderBy string `json:"order_by" type:"select" options:"name,path,created,modified,size" default:"name"` | ||
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"` | ||
driver.RootPath | ||
ClientID string `json:"client_id" required:"true" default:"a78d5a69054042fa936f6c77f9a0ae8b"` | ||
ClientSecret string `json:"client_secret" required:"true" default:"9c119bbb04b346d2a52aa64401936b2b"` | ||
} | ||
|
||
var config = driver.Config{ | ||
Name: "YandexDisk", | ||
DefaultRoot: "/", | ||
} | ||
|
||
func New() driver.Driver { | ||
return &YandexDisk{} | ||
} | ||
|
||
func init() { | ||
op.RegisterDriver(config, New) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package yandex_disk | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/alist-org/alist/v3/internal/model" | ||
) | ||
|
||
type TokenErrResp struct { | ||
ErrorDescription string `json:"error_description"` | ||
Error string `json:"error"` | ||
} | ||
|
||
type ErrResp struct { | ||
Message string `json:"message"` | ||
Description string `json:"description"` | ||
Error string `json:"error"` | ||
} | ||
|
||
type File struct { | ||
//AntivirusStatus string `json:"antivirus_status"` | ||
Size int64 `json:"size"` | ||
//CommentIds struct { | ||
// PrivateResource string `json:"private_resource"` | ||
// PublicResource string `json:"public_resource"` | ||
//} `json:"comment_ids"` | ||
Name string `json:"name"` | ||
//Exif struct { | ||
// DateTime time.Time `json:"date_time"` | ||
//} `json:"exif"` | ||
//Created time.Time `json:"created"` | ||
//ResourceId string `json:"resource_id"` | ||
Modified time.Time `json:"modified"` | ||
//MimeType string `json:"mime_type"` | ||
File string `json:"file"` | ||
//MediaType string `json:"media_type"` | ||
Preview string `json:"preview"` | ||
Path string `json:"path"` | ||
//Sha256 string `json:"sha256"` | ||
Type string `json:"type"` | ||
//Md5 string `json:"md5"` | ||
//Revision int64 `json:"revision"` | ||
} | ||
|
||
func fileToObj(f File) model.Obj { | ||
return &model.Object{ | ||
Name: f.Name, | ||
Size: f.Size, | ||
Modified: f.Modified, | ||
IsFolder: f.Type == "dir", | ||
} | ||
} | ||
|
||
type FilesResp struct { | ||
Embedded struct { | ||
Sort string `json:"sort"` | ||
Items []File `json:"items"` | ||
Limit int `json:"limit"` | ||
Offset int `json:"offset"` | ||
Path string `json:"path"` | ||
Total int `json:"total"` | ||
} `json:"_embedded"` | ||
Name string `json:"name"` | ||
Exif struct { | ||
} `json:"exif"` | ||
ResourceId string `json:"resource_id"` | ||
Created time.Time `json:"created"` | ||
Modified time.Time `json:"modified"` | ||
Path string `json:"path"` | ||
CommentIds struct { | ||
} `json:"comment_ids"` | ||
Type string `json:"type"` | ||
Revision int64 `json:"revision"` | ||
} | ||
|
||
type DownResp struct { | ||
Href string `json:"href"` | ||
Method string `json:"method"` | ||
Templated bool `json:"templated"` | ||
} | ||
|
||
type UploadResp struct { | ||
OperationId string `json:"operation_id"` | ||
Href string `json:"href"` | ||
Method string `json:"method"` | ||
Templated bool `json:"templated"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package yandex_disk | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"strconv" | ||
|
||
"github.com/alist-org/alist/v3/drivers/base" | ||
"github.com/alist-org/alist/v3/internal/op" | ||
"github.com/go-resty/resty/v2" | ||
) | ||
|
||
// do others that not defined in Driver interface | ||
|
||
func (d *YandexDisk) refreshToken() error { | ||
u := "https://oauth.yandex.com/token" | ||
var resp base.TokenResp | ||
var e TokenErrResp | ||
_, err := base.RestyClient.R().SetResult(&resp).SetError(&e).SetFormData(map[string]string{ | ||
"grant_type": "refresh_token", | ||
"refresh_token": d.RefreshToken, | ||
"client_id": d.ClientID, | ||
"client_secret": d.ClientSecret, | ||
}).Post(u) | ||
if err != nil { | ||
return err | ||
} | ||
if e.Error != "" { | ||
return fmt.Errorf("%s : %s", e.Error, e.ErrorDescription) | ||
} | ||
d.AccessToken, d.RefreshToken = resp.AccessToken, resp.RefreshToken | ||
op.MustSaveDriverStorage(d) | ||
return nil | ||
} | ||
|
||
func (d *YandexDisk) request(pathname string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) { | ||
u := "https://cloud-api.yandex.net/v1/disk/resources" + pathname | ||
req := base.RestyClient.R() | ||
req.SetHeader("Authorization", "OAuth "+d.AccessToken) | ||
if callback != nil { | ||
callback(req) | ||
} | ||
if resp != nil { | ||
req.SetResult(resp) | ||
} | ||
var e ErrResp | ||
req.SetError(&e) | ||
res, err := req.Execute(method, u) | ||
if err != nil { | ||
return nil, err | ||
} | ||
//log.Debug(res.String()) | ||
if e.Error != "" { | ||
if e.Error == "UnauthorizedError" { | ||
err = d.refreshToken() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return d.request(pathname, method, callback, resp) | ||
} | ||
return nil, errors.New(e.Description) | ||
} | ||
return res.Body(), nil | ||
} | ||
|
||
func (d *YandexDisk) getFiles(path string) ([]File, error) { | ||
limit := 100 | ||
page := 1 | ||
res := make([]File, 0) | ||
for { | ||
offset := (page - 1) * limit | ||
query := map[string]string{ | ||
"path": path, | ||
"limit": strconv.Itoa(limit), | ||
"offset": strconv.Itoa(offset), | ||
} | ||
if d.OrderBy != "" { | ||
if d.OrderDirection == "desc" { | ||
query["sort"] = "-" + d.OrderBy | ||
} else { | ||
query["sort"] = d.OrderBy | ||
} | ||
} | ||
var resp FilesResp | ||
_, err := d.request("", http.MethodGet, func(req *resty.Request) { | ||
req.SetQueryParams(query) | ||
}, &resp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
res = append(res, resp.Embedded.Items...) | ||
if resp.Embedded.Total <= offset+limit { | ||
break | ||
} | ||
} | ||
return res, nil | ||
} |