mirror of https://github.com/Xhofe/alist
parent
355fc576b1
commit
3e285aaec4
|
@ -44,6 +44,7 @@ import (
|
|||
_ "github.com/alist-org/alist/v3/drivers/uss"
|
||||
_ "github.com/alist-org/alist/v3/drivers/virtual"
|
||||
_ "github.com/alist-org/alist/v3/drivers/webdav"
|
||||
_ "github.com/alist-org/alist/v3/drivers/weiyun"
|
||||
_ "github.com/alist-org/alist/v3/drivers/wopan"
|
||||
_ "github.com/alist-org/alist/v3/drivers/yandex_disk"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,381 @@
|
|||
package weiyun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"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/internal/op"
|
||||
"github.com/alist-org/alist/v3/pkg/cron"
|
||||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
weiyunsdkgo "github.com/foxxorcat/weiyun-sdk-go"
|
||||
)
|
||||
|
||||
type WeiYun struct {
|
||||
model.Storage
|
||||
Addition
|
||||
|
||||
client *weiyunsdkgo.WeiYunClient
|
||||
cron *cron.Cron
|
||||
rootFolder *Folder
|
||||
}
|
||||
|
||||
func (d *WeiYun) Config() driver.Config {
|
||||
return config
|
||||
}
|
||||
|
||||
func (d *WeiYun) GetAddition() driver.Additional {
|
||||
return &d.Addition
|
||||
}
|
||||
|
||||
func (d *WeiYun) Init(ctx context.Context) error {
|
||||
d.client = weiyunsdkgo.NewWeiYunClientWithRestyClient(base.RestyClient)
|
||||
err := d.client.SetCookiesStr(d.Cookies).RefreshCtoken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Cookie过期回调
|
||||
d.client.SetOnCookieExpired(func(err error) {
|
||||
d.Status = err.Error()
|
||||
op.MustSaveDriverStorage(d)
|
||||
})
|
||||
|
||||
// cookie更新回调
|
||||
d.client.SetOnCookieUpload(func(c []*http.Cookie) {
|
||||
d.Cookies = weiyunsdkgo.CookieToString(weiyunsdkgo.ClearCookie(c))
|
||||
op.MustSaveDriverStorage(d)
|
||||
})
|
||||
|
||||
// qqCookie保活
|
||||
if d.client.LoginType() == 1 {
|
||||
d.cron = cron.NewCron(time.Minute * 5)
|
||||
d.cron.Do(func() {
|
||||
d.client.KeepAlive()
|
||||
})
|
||||
}
|
||||
|
||||
// 获取默认根目录dirKey
|
||||
if d.RootFolderID == "" {
|
||||
userInfo, err := d.client.DiskUserInfoGet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.RootFolderID = userInfo.MainDirKey
|
||||
}
|
||||
|
||||
// 处理目录ID,找到PdirKey
|
||||
folders, err := d.client.LibDirPathGet(d.RootFolderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
folder := folders[len(folders)-1]
|
||||
d.rootFolder = &Folder{
|
||||
PFolder: &Folder{
|
||||
Folder: weiyunsdkgo.Folder{
|
||||
DirKey: folder.PdirKey,
|
||||
},
|
||||
},
|
||||
Folder: folder.Folder,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *WeiYun) Drop(ctx context.Context) error {
|
||||
d.client = nil
|
||||
if d.cron != nil {
|
||||
d.cron.Stop()
|
||||
d.cron = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *WeiYun) GetRoot(ctx context.Context) (model.Obj, error) {
|
||||
return d.rootFolder, nil
|
||||
}
|
||||
|
||||
func (d *WeiYun) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
|
||||
if folder, ok := dir.(*Folder); ok {
|
||||
var files []model.Obj
|
||||
for {
|
||||
data, err := d.client.DiskDirFileList(folder.GetID(), weiyunsdkgo.WarpParamOption(
|
||||
weiyunsdkgo.QueryFileOptionOffest(int64(len(files))),
|
||||
weiyunsdkgo.QueryFileOptionGetType(weiyunsdkgo.FileAndDir),
|
||||
weiyunsdkgo.QueryFileOptionSort(func() weiyunsdkgo.OrderBy {
|
||||
switch d.OrderBy {
|
||||
case "name":
|
||||
return weiyunsdkgo.FileName
|
||||
case "size":
|
||||
return weiyunsdkgo.FileSize
|
||||
case "updated_at":
|
||||
return weiyunsdkgo.FileMtime
|
||||
default:
|
||||
return weiyunsdkgo.FileName
|
||||
}
|
||||
}(), d.OrderDirection == "desc"),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if files == nil {
|
||||
files = make([]model.Obj, 0, data.TotalDirCount+data.TotalFileCount)
|
||||
}
|
||||
|
||||
for _, dir := range data.DirList {
|
||||
files = append(files, &Folder{
|
||||
PFolder: folder,
|
||||
Folder: dir,
|
||||
})
|
||||
}
|
||||
|
||||
for _, file := range data.FileList {
|
||||
files = append(files, &File{
|
||||
PFolder: folder,
|
||||
File: file,
|
||||
})
|
||||
}
|
||||
|
||||
if data.FinishFlag || len(data.DirList)+len(data.FileList) == 0 {
|
||||
return files, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *WeiYun) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||
if file, ok := file.(*File); ok {
|
||||
data, err := d.client.DiskFileDownload(weiyunsdkgo.FileParam{PdirKey: file.GetPKey(), FileID: file.GetID()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.Link{
|
||||
URL: data.DownloadUrl,
|
||||
Header: http.Header{
|
||||
"Cookie": []string{data.CookieName + "=" + data.CookieValue},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *WeiYun) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
|
||||
if folder, ok := parentDir.(*Folder); ok {
|
||||
newFolder, err := d.client.DiskDirCreate(weiyunsdkgo.FolderParam{
|
||||
PPdirKey: folder.GetPKey(),
|
||||
PdirKey: folder.DirKey,
|
||||
DirName: dirName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Folder{
|
||||
PFolder: folder,
|
||||
Folder: *newFolder,
|
||||
}, nil
|
||||
}
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *WeiYun) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
|
||||
if dstDir, ok := dstDir.(*Folder); ok {
|
||||
dstParam := weiyunsdkgo.FolderParam{
|
||||
PdirKey: dstDir.GetPKey(),
|
||||
DirKey: dstDir.GetID(),
|
||||
DirName: dstDir.GetName(),
|
||||
}
|
||||
switch srcObj := srcObj.(type) {
|
||||
case *File:
|
||||
err := d.client.DiskFileMove(weiyunsdkgo.FileParam{
|
||||
PPdirKey: srcObj.PFolder.GetPKey(),
|
||||
PdirKey: srcObj.GetPKey(),
|
||||
FileID: srcObj.GetID(),
|
||||
FileName: srcObj.GetName(),
|
||||
}, dstParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &File{
|
||||
PFolder: dstDir,
|
||||
File: srcObj.File,
|
||||
}, nil
|
||||
case *Folder:
|
||||
err := d.client.DiskDirMove(weiyunsdkgo.FolderParam{
|
||||
PPdirKey: srcObj.PFolder.GetPKey(),
|
||||
PdirKey: srcObj.GetPKey(),
|
||||
DirKey: srcObj.GetID(),
|
||||
DirName: srcObj.GetName(),
|
||||
}, dstParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Folder{
|
||||
PFolder: dstDir,
|
||||
Folder: srcObj.Folder,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *WeiYun) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
|
||||
switch srcObj := srcObj.(type) {
|
||||
case *File:
|
||||
err := d.client.DiskFileRename(weiyunsdkgo.FileParam{
|
||||
PPdirKey: srcObj.PFolder.GetPKey(),
|
||||
PdirKey: srcObj.GetPKey(),
|
||||
FileID: srcObj.GetID(),
|
||||
FileName: srcObj.GetName(),
|
||||
}, newName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newFile := srcObj.File
|
||||
newFile.FileName = newName
|
||||
newFile.FileCtime = weiyunsdkgo.TimeStamp(time.Now())
|
||||
return &File{
|
||||
PFolder: srcObj.PFolder,
|
||||
File: newFile,
|
||||
}, nil
|
||||
case *Folder:
|
||||
err := d.client.DiskDirAttrModify(weiyunsdkgo.FolderParam{
|
||||
PPdirKey: srcObj.PFolder.GetPKey(),
|
||||
PdirKey: srcObj.GetPKey(),
|
||||
DirKey: srcObj.GetID(),
|
||||
DirName: srcObj.GetName(),
|
||||
}, newName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newFolder := srcObj.Folder
|
||||
newFolder.DirName = newName
|
||||
newFolder.DirCtime = weiyunsdkgo.TimeStamp(time.Now())
|
||||
return &Folder{
|
||||
PFolder: srcObj.PFolder,
|
||||
Folder: newFolder,
|
||||
}, nil
|
||||
}
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *WeiYun) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
// TODO copy obj, optional
|
||||
return errs.NotImplement
|
||||
}
|
||||
|
||||
func (d *WeiYun) Remove(ctx context.Context, obj model.Obj) error {
|
||||
switch obj := obj.(type) {
|
||||
case *File:
|
||||
return d.client.DiskFileDelete(weiyunsdkgo.FileParam{
|
||||
PPdirKey: obj.PFolder.GetPKey(),
|
||||
PdirKey: obj.GetPKey(),
|
||||
FileID: obj.GetID(),
|
||||
FileName: obj.GetName(),
|
||||
})
|
||||
case *Folder:
|
||||
return d.client.DiskDirDelete(weiyunsdkgo.FolderParam{
|
||||
PPdirKey: obj.PFolder.GetPKey(),
|
||||
PdirKey: obj.GetPKey(),
|
||||
DirKey: obj.GetID(),
|
||||
DirName: obj.GetName(),
|
||||
})
|
||||
}
|
||||
// TODO remove obj, optional
|
||||
return errs.NotSupport
|
||||
}
|
||||
|
||||
func (d *WeiYun) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
||||
if folder, ok := dstDir.(*Folder); ok {
|
||||
file, err := utils.CreateTempFile(stream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
_ = os.Remove(file.Name())
|
||||
}()
|
||||
|
||||
// step 1.
|
||||
preData, err := d.client.PreUpload(ctx, weiyunsdkgo.UpdloadFileParam{
|
||||
PdirKey: folder.GetPKey(),
|
||||
DirKey: folder.DirKey,
|
||||
|
||||
FileName: stream.GetName(),
|
||||
FileSize: stream.GetSize(),
|
||||
File: file,
|
||||
|
||||
ChannelCount: 4,
|
||||
FileExistOption: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fast upload
|
||||
if !preData.FileExist {
|
||||
// step 2.
|
||||
upCtx, cancel := context.WithCancelCause(ctx)
|
||||
var wg sync.WaitGroup
|
||||
for _, channel := range preData.ChannelList {
|
||||
wg.Add(1)
|
||||
go func(channel weiyunsdkgo.UploadChannelData) {
|
||||
defer wg.Done()
|
||||
if utils.IsCanceled(upCtx) {
|
||||
return
|
||||
}
|
||||
for {
|
||||
channel.Len = int(math.Min(float64(stream.GetSize()-channel.Offset), float64(channel.Len)))
|
||||
upData, err := d.client.UploadFile(upCtx, channel, preData.UploadAuthData,
|
||||
io.NewSectionReader(file, channel.Offset, int64(channel.Len)))
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
// 上传完成
|
||||
if upData.UploadState != 1 {
|
||||
return
|
||||
}
|
||||
channel = upData.Channel
|
||||
}
|
||||
}(channel)
|
||||
}
|
||||
wg.Wait()
|
||||
if utils.IsCanceled(upCtx) {
|
||||
return nil, context.Cause(upCtx)
|
||||
}
|
||||
}
|
||||
|
||||
return &File{
|
||||
PFolder: folder,
|
||||
File: preData.File,
|
||||
}, nil
|
||||
}
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
// func (d *WeiYun) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
|
||||
// return nil, errs.NotSupport
|
||||
// }
|
||||
|
||||
var _ driver.Driver = (*WeiYun)(nil)
|
||||
var _ driver.GetRooter = (*WeiYun)(nil)
|
||||
var _ driver.MkdirResult = (*WeiYun)(nil)
|
||||
|
||||
// var _ driver.CopyResult = (*WeiYun)(nil)
|
||||
var _ driver.MoveResult = (*WeiYun)(nil)
|
||||
var _ driver.Remove = (*WeiYun)(nil)
|
||||
|
||||
var _ driver.PutResult = (*WeiYun)(nil)
|
||||
var _ driver.RenameResult = (*WeiYun)(nil)
|
|
@ -0,0 +1,28 @@
|
|||
package weiyun
|
||||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
)
|
||||
|
||||
type Addition struct {
|
||||
RootFolderID string `json:"root_folder_id"`
|
||||
Cookies string `json:"cookies" required:"true"`
|
||||
OrderBy string `json:"order_by" type:"select" options:"name,size,updated_at" default:"name"`
|
||||
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
|
||||
}
|
||||
|
||||
var config = driver.Config{
|
||||
Name: "WeiYun",
|
||||
LocalSort: false,
|
||||
OnlyProxy: true,
|
||||
CheckStatus: true,
|
||||
Alert: "",
|
||||
NoOverwriteUpload: false,
|
||||
}
|
||||
|
||||
func init() {
|
||||
op.RegisterDriver(func() driver.Driver {
|
||||
return &WeiYun{}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package weiyun
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
weiyunsdkgo "github.com/foxxorcat/weiyun-sdk-go"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
PFolder *Folder
|
||||
weiyunsdkgo.File
|
||||
}
|
||||
|
||||
func (f *File) GetID() string { return f.FileID }
|
||||
func (f *File) GetSize() int64 { return f.FileSize }
|
||||
func (f *File) GetName() string { return f.FileName }
|
||||
func (f *File) ModTime() time.Time { return time.Time(f.FileMtime) }
|
||||
func (f *File) IsDir() bool { return false }
|
||||
func (f *File) GetPath() string { return "" }
|
||||
|
||||
func (f *File) GetPKey() string {
|
||||
return f.PFolder.DirKey
|
||||
}
|
||||
|
||||
type Folder struct {
|
||||
PFolder *Folder
|
||||
weiyunsdkgo.Folder
|
||||
}
|
||||
|
||||
func (f *Folder) GetID() string { return f.DirKey }
|
||||
func (f *Folder) GetSize() int64 { return 0 }
|
||||
func (f *Folder) GetName() string { return f.DirName }
|
||||
func (f *Folder) ModTime() time.Time { return time.Time(f.DirMtime) }
|
||||
func (f *Folder) IsDir() bool { return true }
|
||||
func (f *Folder) GetPath() string { return "" }
|
||||
|
||||
func (f *Folder) GetPKey() string {
|
||||
return f.PFolder.DirKey
|
||||
}
|
1
go.mod
1
go.mod
|
@ -17,6 +17,7 @@ require (
|
|||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564
|
||||
github.com/foxxorcat/mopan-sdk-go v0.1.1
|
||||
github.com/foxxorcat/weiyun-sdk-go v0.1.1
|
||||
github.com/gin-contrib/cors v1.4.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -195,6 +195,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/foxxorcat/mopan-sdk-go v0.1.1 h1:JYMeCu4PFpqgHapvOz4jPMT7CxR6Yebu3aWkgGMDeIU=
|
||||
github.com/foxxorcat/mopan-sdk-go v0.1.1/go.mod h1:LpBPmwezjQNyhaNo3HGzgFtQbhvxmF5ZybSVuKi7OVA=
|
||||
github.com/foxxorcat/weiyun-sdk-go v0.1.1 h1:m4qcJk0adr+bpM4es2zCqP3jhMEwEPyTMGICsamygEQ=
|
||||
github.com/foxxorcat/weiyun-sdk-go v0.1.1/go.mod h1:AKsLFuWhWlClpGrg1zxTdMejugZEZtmhIuElAk3W83s=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
|
|
Loading…
Reference in New Issue