mirror of https://github.com/Xhofe/alist
321 lines
7.0 KiB
Go
321 lines
7.0 KiB
Go
![]() |
package quark
|
||
|
|
||
|
import (
|
||
|
"crypto/md5"
|
||
|
"crypto/sha1"
|
||
|
"encoding/hex"
|
||
|
"github.com/Xhofe/alist/conf"
|
||
|
"github.com/Xhofe/alist/drivers/base"
|
||
|
"github.com/Xhofe/alist/model"
|
||
|
"github.com/Xhofe/alist/utils"
|
||
|
log "github.com/sirupsen/logrus"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
)
|
||
|
|
||
|
type Quark struct{}
|
||
|
|
||
|
func (driver Quark) Config() base.DriverConfig {
|
||
|
return base.DriverConfig{
|
||
|
Name: "Quark",
|
||
|
OnlyProxy: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Items() []base.Item {
|
||
|
return []base.Item{
|
||
|
{
|
||
|
Name: "access_token",
|
||
|
Label: "Cookie",
|
||
|
Type: base.TypeString,
|
||
|
Required: true,
|
||
|
Description: "Unknown expiration time",
|
||
|
},
|
||
|
{
|
||
|
Name: "root_folder",
|
||
|
Label: "root folder file_id",
|
||
|
Type: base.TypeString,
|
||
|
Required: true,
|
||
|
Default: "0",
|
||
|
},
|
||
|
{
|
||
|
Name: "order_by",
|
||
|
Label: "order_by",
|
||
|
Type: base.TypeSelect,
|
||
|
Values: "file_type,file_name,updated_at",
|
||
|
Required: true,
|
||
|
Default: "file_name",
|
||
|
},
|
||
|
{
|
||
|
Name: "order_direction",
|
||
|
Label: "order_direction",
|
||
|
Type: base.TypeSelect,
|
||
|
Values: "asc,desc",
|
||
|
Required: true,
|
||
|
Default: "asc",
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Save(account *model.Account, old *model.Account) error {
|
||
|
if account == nil {
|
||
|
return nil
|
||
|
}
|
||
|
_, err := driver.Get("/config", nil, nil, account)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (driver Quark) 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: driver.Config().Name,
|
||
|
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, base.ErrPathNotFound
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Files(path string, account *model.Account) ([]model.File, error) {
|
||
|
path = utils.ParsePath(path)
|
||
|
var files []model.File
|
||
|
cache, err := base.GetCache(path, account)
|
||
|
if err == nil {
|
||
|
files, _ = cache.([]model.File)
|
||
|
} else {
|
||
|
file, err := driver.File(path, account)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
files, err = driver.GetFiles(file.Id, account)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if len(files) > 0 {
|
||
|
_ = base.SetCache(path, files, account)
|
||
|
}
|
||
|
}
|
||
|
return files, nil
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Link(args base.Args, account *model.Account) (*base.Link, error) {
|
||
|
path := args.Path
|
||
|
file, err := driver.File(path, account)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
data := base.Json{
|
||
|
"fids": []string{file.Id},
|
||
|
}
|
||
|
var resp DownResp
|
||
|
_, err = driver.Post("/file/download", data, &resp, account)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &base.Link{
|
||
|
Url: resp.Data[0].DownloadUrl,
|
||
|
Headers: []base.Header{
|
||
|
{Name: "Cookie", Value: account.AccessToken},
|
||
|
},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Path(path string, account *model.Account) (*model.File, []model.File, error) {
|
||
|
path = utils.ParsePath(path)
|
||
|
log.Debugf("quark path: %s", path)
|
||
|
file, err := driver.File(path, account)
|
||
|
if err != nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
if !file.IsDir() {
|
||
|
return file, nil, nil
|
||
|
}
|
||
|
files, err := driver.Files(path, account)
|
||
|
if err != nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
return nil, files, nil
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Preview(path string, account *model.Account) (interface{}, error) {
|
||
|
return nil, base.ErrNotSupport
|
||
|
}
|
||
|
|
||
|
func (driver Quark) MakeDir(path string, account *model.Account) error {
|
||
|
parentFile, err := driver.File(utils.Dir(path), account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
data := base.Json{
|
||
|
"dir_init_lock": false,
|
||
|
"dir_path": "",
|
||
|
"file_name": utils.Base(path),
|
||
|
"pdir_fid": parentFile.Id,
|
||
|
}
|
||
|
_, err = driver.Post("/file", data, nil, account)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Move(src string, dst string, account *model.Account) error {
|
||
|
srcFile, err := driver.File(src, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
dstParentFile, err := driver.File(utils.Dir(dst), account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
data := base.Json{
|
||
|
"action_type": 1,
|
||
|
"exclude_fids": []string{},
|
||
|
"filelist": []string{srcFile.Id},
|
||
|
"to_pdir_fid": dstParentFile.Id,
|
||
|
}
|
||
|
_, err = driver.Post("/file/move", data, nil, account)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Rename(src string, dst string, account *model.Account) error {
|
||
|
srcFile, err := driver.File(src, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
data := base.Json{
|
||
|
"fid": srcFile.Id,
|
||
|
"file_name": utils.Base(dst),
|
||
|
}
|
||
|
_, err = driver.Post("/file/rename", data, nil, account)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Copy(src string, dst string, account *model.Account) error {
|
||
|
return base.ErrNotSupport
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Delete(path string, account *model.Account) error {
|
||
|
srcFile, err := driver.File(path, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
data := base.Json{
|
||
|
"action_type": 1,
|
||
|
"exclude_fids": []string{},
|
||
|
"filelist": []string{srcFile.Id},
|
||
|
}
|
||
|
_, err = driver.Post("/file/delete", data, nil, account)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (driver Quark) Upload(file *model.FileStream, account *model.Account) error {
|
||
|
if file == nil {
|
||
|
return base.ErrEmptyFile
|
||
|
}
|
||
|
parentFile, err := driver.File(file.ParentPath, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
tempFile, err := ioutil.TempFile(conf.Conf.TempDir, "file-*")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer func() {
|
||
|
_ = tempFile.Close()
|
||
|
_ = os.Remove(tempFile.Name())
|
||
|
}()
|
||
|
_, err = io.Copy(tempFile, file)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
m := md5.New()
|
||
|
_, err = io.Copy(m, tempFile)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
md5Str := hex.EncodeToString(m.Sum(nil))
|
||
|
s := sha1.New()
|
||
|
_, err = io.Copy(s, tempFile)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
sha1Str := hex.EncodeToString(s.Sum(nil))
|
||
|
// pre
|
||
|
pre, err := driver.UpPre(file, parentFile.Id, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
log.Debugln("hash: ", md5Str, sha1Str)
|
||
|
// hash
|
||
|
finish, err := driver.UpHash(md5Str, sha1Str, pre.Data.TaskId, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if finish {
|
||
|
return nil
|
||
|
}
|
||
|
// part up
|
||
|
partSize := pre.Metadata.PartSize
|
||
|
var bytes []byte
|
||
|
md5s := make([]string, 0)
|
||
|
defaultBytes := make([]byte, partSize)
|
||
|
left := int64(file.GetSize())
|
||
|
partNumber := 1
|
||
|
for left > 0 {
|
||
|
if left > int64(partSize) {
|
||
|
bytes = defaultBytes
|
||
|
} else {
|
||
|
bytes = make([]byte, left)
|
||
|
}
|
||
|
_, err := io.ReadFull(tempFile, bytes)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
left -= int64(partSize)
|
||
|
log.Debugf("left: %d", left)
|
||
|
m, err := driver.UpPart(pre, file.GetMIMEType(), partNumber, bytes, account)
|
||
|
//m, err := driver.UpPart(pre, file.GetMIMEType(), partNumber, bytes, account, md5Str, sha1Str)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if m == "finish" {
|
||
|
return nil
|
||
|
}
|
||
|
md5s = append(md5s, m)
|
||
|
partNumber++
|
||
|
}
|
||
|
err = driver.UpCommit(pre, md5s, account)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return driver.UpFinish(pre, account)
|
||
|
}
|
||
|
|
||
|
var _ base.Driver = (*Quark)(nil)
|