Repository: AlistGo/alist (language: go)

Issue:
使用rclone同步和彩云与OneDrive出现OOM的情况
### Please make sure of the following things

- [X] I have read the [documentation](https://alist-doc.nn.ci).
- [X] I'm sure there are no duplicate issues or discussions.
- [X] I'm sure it's due to `alist` and not something else(such as `Dependencies` or `Operational`).

### Alist Version / Alist 版本

v2.5.1

### Describe the bug / 问题描述

## 环境与配置说明
ubuntu20.04，amd64
2核2g
rclone版本v1.58.0
alist版本2.5.1

***

## 前言
本人为了将OneDrive的一些文件同步到和彩云上，使用了rclone+alist的方法。（因为rclone的sync命令真的很香）

首先使用rclone配置OneDrive和alist的webdav，然后输入命令：
```bash
rclone sync "od:/XXXXX" "alist:/cloud139/XXXXXX" -P --cache-chunk-total-size=100M --cache-chunk-size=30M --transfers=3
```

需要同步的文件夹大小为19.8g，其中绝大多数为图片（7000多张），以下是od在win10下的同步文件夹属性截图

![image](https://user-images.githubusercontent.com/56548141/167465675-7c1f8769-ba3c-4a54-91ca-6071c89831d1.png)

（由于该文件夹带有一定私密性，请原谅我不予展示）

## 问题描述

前言所述的操作刚开始是正常同步的，大概同步了1个半小时，我发现ssh不上去服务器了，vnc后发现OOM了

![image](https://user-images.githubusercontent.com/56548141/167466758-e38e97e1-6988-4d12-86de-15b2f0fad87b.png)

在OOM之前，rclone的同步命令也是一直提示同步失败，错误代码409
![image](https://user-images.githubusercontent.com/56548141/167468154-7c06f1d1-4860-4a0c-9811-237aee428920.png)

当时我初步诊断为rclone的同步命令参数设置的太高了，于是我重启了alist的服务，并设置`--cache-chunk-total-size=10M`和`--cache-chunk-size=3M`重新跑同步命令

此时的alist内存占用在htop面板下是这样的
![image](https://user-images.githubusercontent.com/56548141/167469776-fe5656bc-7803-4863-bd94-a75c70b2e810.png)

大概过了10几分钟我再去看，发现alist的内存占用极高。
![image](https://user-images.githubusercontent.com/56548141/167472131-fc8d59ec-e67e-415b-abcb-f65803def9f1.png)
我尝试进入网页端手动清理缓存，发现内存并没有降下来，无奈只有重启alist服务，很显然，rclone的同步命令也不得不中止掉。

## 后续补充

再之后，我尝试在我另一台的服务器（ubuntu20.04，1核1g）上跑，这次同步的是一些较大的文件（大部分是日漫视频），rclone的同步命令内存参数也设置的很小，同样出现了类似的情况。
![image](https://user-images.githubusercontent.com/56548141/167472688-02194476-f8e1-4ef6-9139-6c47fa3d6d1b.png)

## 其他补充

我之前也试过rclone只配置alist，然后仅通过alist来进行同步，但是大多数情况下会出现405错误，或者直接找不到文件了。
![image](https://user-images.githubusercontent.com/56548141/167473486-c0ccb101-5460-4870-9089-d766a3039e69.png)
如果rclone配置OneDrive和alist的话这种情况就会大大缓解（不是完全解决，仍然有少数文件会出现这类情况，这时只需要在同步命令执行完成后再执行一次同步命令即可）





### Reproduction / 复现链接

无

### Logs / 日志

_No response_


Discussion / hints:

Fix patch:
diff --git a/drivers/123/123.go b/drivers/123/123.go
index e93f144baf6..87f8cafea8f 100644
--- a/drivers/123/123.go
+++ b/drivers/123/123.go
@@ -3,14 +3,15 @@ package _23
 import (
 	"errors"
 	"fmt"
+	"path/filepath"
+	"strconv"
+
 	"github.com/Xhofe/alist/drivers/base"
 	"github.com/Xhofe/alist/model"
 	"github.com/Xhofe/alist/utils"
 	"github.com/go-resty/resty/v2"
 	jsoniter "github.com/json-iterator/go"
 	log "github.com/sirupsen/logrus"
-	"path/filepath"
-	"strconv"
 )
 
 func (driver Pan123) Login(account *model.Account) error {
@@ -46,6 +47,7 @@ func (driver Pan123) FormatFile(file *File) *model.File {
 		Size:      file.Size,
 		Driver:    driver.Config().Name,
 		UpdatedAt: file.UpdateAt,
+		Thumbnail: file.DownloadUrl,
 	}
 	f.Type = file.GetType()
 	return f
@@ -65,7 +67,7 @@ func (driver Pan123) GetFiles(parentId string, account *model.Account) ([]File,
 			"parentFileId":   parentId,
 			"trashed":        "false",
 		}
-		_, err := driver.Request("https://www.123pan.com/api/file/list",
+		_, err := driver.Request("https://www.123pan.com/api/file/list/new",
 			base.Get, nil, query, nil, &resp, false, account)
 		if err != nil {
 			return nil, err
diff --git a/drivers/123/driver.go b/drivers/123/driver.go
index eeb6bebd4e9..43cf7cf7efa 100644
--- a/drivers/123/driver.go
+++ b/drivers/123/driver.go
@@ -4,6 +4,13 @@ import (
 	"crypto/md5"
 	"encoding/hex"
 	"fmt"
+	"io"
+	"io/ioutil"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strconv"
+
 	"github.com/Xhofe/alist/conf"
 	"github.com/Xhofe/alist/drivers/base"
 	"github.com/Xhofe/alist/model"
@@ -13,12 +20,6 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/s3/s3manager"
 	log "github.com/sirupsen/logrus"
-	"io"
-	"io/ioutil"
-	"net/url"
-	"os"
-	"path/filepath"
-	"strconv"
 )
 
 type Pan123 struct{}
@@ -125,7 +126,7 @@ func (driver Pan123) Files(path string, account *model.Account) ([]model.File, e
 			_ = base.SetCache(path, rawFiles, account)
 		}
 	}
-	files := make([]model.File, 0)
+	files := make([]model.File, 0, len(rawFiles))
 	for _, file := range rawFiles {
 		files = append(files, *driver.FormatFile(&file))
 	}
@@ -300,46 +301,36 @@ func (driver Pan123) Upload(file *model.FileStream, account *model.Account) erro
 	if !parentFile.IsDir() {
 		return base.ErrNotFolder
 	}
-	parentFileId, _ := strconv.Atoi(parentFile.Id)
+
 	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
-	}
+	defer tempFile.Close()
+	defer os.Remove(tempFile.Name())
 	h := md5.New()
-	_, err = io.Copy(h, tempFile)
-	if err != nil {
+	if _, err = io.Copy(io.MultiWriter(tempFile, h), file); err != nil {
 		return err
 	}
 	etag := hex.EncodeToString(h.Sum(nil))
-	log.Debugln("md5:", etag)
+
 	_, err = tempFile.Seek(0, io.SeekStart)
 	if err != nil {
 		return err
 	}
+
 	data := base.Json{
 		"driveId":      0,
-		"duplicate":    true,
+		"duplicate":    2, // 2->覆盖 1->重命名 0->默认
 		"etag":         etag,
 		"fileName":     file.GetFileName(),
-		"parentFileId": parentFileId,
+		"parentFileId": parentFile.Id,
 		"size":         file.GetSize(),
 		"type":         0,
 	}
 	var resp UploadResp
 	_, err = driver.Request("https://www.123pan.com/api/file/upload_request",
-		base.Post, nil, nil, &data, &resp, false, account)
+		base.Post, map[string]string{"app-version": "1.1"}, nil, &data, &resp, false, account)
 	//res, err := driver.Post("https://www.123pan.com/api/file/upload_request", data, account)
 	if err != nil {
 		return err
diff --git a/drivers/123/types.go b/drivers/123/types.go
index 012d350eb72..c464628c366 100644
--- a/drivers/123/types.go
+++ b/drivers/123/types.go
@@ -1,20 +1,22 @@
 package _23
 
 import (
-	"github.com/Xhofe/alist/conf"
-	"github.com/Xhofe/alist/utils"
 	"path"
 	"time"
+
+	"github.com/Xhofe/alist/conf"
+	"github.com/Xhofe/alist/utils"
 )
 
 type File struct {
-	FileName  string     `json:"FileName"`
-	Size      int64      `json:"Size"`
-	UpdateAt  *time.Time `json:"UpdateAt"`
-	FileId    int64      `json:"FileId"`
-	Type      int        `json:"Type"`
-	Etag      string     `json:"Etag"`
-	S3KeyFlag string     `json:"S3KeyFlag"`
+	FileName    string     `json:"FileName"`
+	Size        int64      `json:"Size"`
+	UpdateAt    *time.Time `json:"UpdateAt"`
+	FileId      int64      `json:"FileId"`
+	Type        int        `json:"Type"`
+	Etag        string     `json:"Etag"`
+	S3KeyFlag   string     `json:"S3KeyFlag"`
+	DownloadUrl string     `json:"DownloadUrl"`
 }
 
 func (f File) GetSize() uint64 {
diff --git a/drivers/139/driver.go b/drivers/139/driver.go
index b0025fcc897..8864787c3a1 100644
--- a/drivers/139/driver.go
+++ b/drivers/139/driver.go
@@ -448,6 +448,7 @@ func (driver Cloud139) Upload(file *model.FileStream, account *model.Account) er
 			return err
 		}
 		log.Debugf("%+v", res)
+		res.Body.Close()
 		start += byteSize
 	}
 	return nil
diff --git a/drivers/189/189.go b/drivers/189/189.go
index f921a749d15..ac6ea189dd0 100644
--- a/drivers/189/189.go
+++ b/drivers/189/189.go
@@ -577,6 +577,7 @@ func (driver Cloud189) NewUpload(file *model.FileStream, account *model.Account)
 
 		r, err := base.HttpClient.Do(req)
 		log.Debugf("%+v %+v", r, r.Request.Header)
+		r.Body.Close()
 		if err != nil {
 			return err
 		}
diff --git a/drivers/189pc/driver.go b/drivers/189pc/driver.go
index b6ca7a1bd30..e8ea2e1c9f2 100644
--- a/drivers/189pc/driver.go
+++ b/drivers/189pc/driver.go
@@ -607,6 +607,7 @@ func (driver Cloud189) CommonUpload(file *model.FileStream, parentFile *model.Fi
 
 		uploadData := uploadUrl.UploadUrls[fmt.Sprint("partNumber_", i)]
 		req, _ := http.NewRequest(http.MethodPut, uploadData.RequestURL, byteData)
+		req.Header.Del("User-Agent")
 		for k, v := range ParseHttpHeader(uploadData.RequestHeader) {
 			req.Header.Set(k, v)
 		}
@@ -619,8 +620,10 @@ func (driver Cloud189) CommonUpload(file *model.FileStream, parentFile *model.Fi
 		}
 		if r.StatusCode != http.StatusOK {
 			data, _ := io.ReadAll(r.Body)
+			r.Body.Close()
 			return fmt.Errorf(string(data))
 		}
+		r.Body.Close()
 	}
 
 	fileMd5Hex := strings.ToUpper(hex.EncodeToString(fileMd5.Sum(nil)))
@@ -715,6 +718,7 @@ func (driver Cloud189) FastUpload(file *model.FileStream, parentFile *model.File
 		for i := 1; i <= count; i++ {
 			uploadData := uploadUrls.UploadUrls[fmt.Sprint("partNumber_", i)]
 			req, _ := http.NewRequest(http.MethodPut, uploadData.RequestURL, io.NewSectionReader(tempFile, int64(i-1)*DEFAULT, DEFAULT))
+			req.Header.Del("User-Agent")
 			for k, v := range ParseHttpHeader(uploadData.RequestHeader) {
 				req.Header.Set(k, v)
 			}
@@ -727,8 +731,10 @@ func (driver Cloud189) FastUpload(file *model.FileStream, parentFile *model.File
 			}
 			if r.StatusCode != http.StatusOK {
 				data, _ := io.ReadAll(r.Body)
+				r.Body.Close()
 				return fmt.Errorf(string(data))
 			}
+			r.Body.Close()
 		}
 	}
 
diff --git a/drivers/alidrive/driver.go b/drivers/alidrive/driver.go
index 9ad815662bf..013d9a49f31 100644
--- a/drivers/alidrive/driver.go
+++ b/drivers/alidrive/driver.go
@@ -424,10 +424,17 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
 	}
 
 	if account.Bool1 {
-		buf := make([]byte, 1024)
-		n, _ := file.Read(buf[:])
-		reqBody["pre_hash"] = utils.GetSHA1Encode(string(buf[:n]))
-		file.File = io.NopCloser(io.MultiReader(bytes.NewReader(buf[:n]), file.File))
+		buf := bytes.NewBuffer(make([]byte, 0, 1024))
+		io.CopyN(buf, file, 1024)
+		reqBody["pre_hash"] = utils.GetSHA1Encode(buf.String())
+		// 把头部拼接回去
+		file.File = struct {
+			io.Reader
+			io.Closer
+		}{
+			Reader: io.MultiReader(buf, file.File),
+			Closer: file.File,
+		}
 	} else {
 		reqBody["content_hash_name"] = "none"
 		reqBody["proof_version"] = "v1"
@@ -454,7 +461,7 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
 		return fmt.Errorf("%s", e.Message)
 	}
 
-	if e.Code == "PreHashMatched" && account.Bool1 {
+	if account.Bool1 && e.Code == "PreHashMatched" {
 		tempFile, err := ioutil.TempFile(conf.Conf.TempDir, "file-*")
 		if err != nil {
 			return err
@@ -499,6 +506,7 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
 			return nil
 		}
 
+		// 秒传失败
 		if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
 			return err
 		}
@@ -515,6 +523,7 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
 			return err
 		}
 		log.Debugf("%+v", res)
+		res.Body.Close()
 		//res, err := base.BaseClient.R().
 		//	SetHeader("Content-Type","").
 		//	SetBody(byteData).Put(resp.PartInfoList[i].UploadUrl)
diff --git a/drivers/baiduphoto/baidu.go b/drivers/baiduphoto/baidu.go
index 287ec433ef6..c192939b3f4 100644
--- a/drivers/baiduphoto/baidu.go
+++ b/drivers/baiduphoto/baidu.go
@@ -87,7 +87,7 @@ func (driver Baidu) GetAllFile(account *model.Account) (files []File, err error)
 
 	for {
 		var resp FileListResp
-		_, err = driver.Request(http.MethodGet, FILE_API_URL+"/list", func(r *resty.Request) {
+		_, err = driver.Request(http.MethodGet, FILE_API_URL_V1+"/list", func(r *resty.Request) {
 			r.SetQueryParams(map[string]string{
 				"need_thumbnail":     "1",
 				"need_filter_hidden": "0",
diff --git a/drivers/baiduphoto/driver.go b/drivers/baiduphoto/driver.go
index 99010ac1d95..833ef89f567 100644
--- a/drivers/baiduphoto/driver.go
+++ b/drivers/baiduphoto/driver.go
@@ -43,6 +43,14 @@ func (driver Baidu) Items() []base.Item {
 			Label: "album_id",
 			Type:  base.TypeString,
 		},
+		{
+			Name:     "internal_type",
+			Label:    "download api",
+			Type:     base.TypeSelect,
+			Required: true,
+			Values:   "file,album",
+			Default:  "album",
+		},
 		{
 			Name:     "client_id",
 			Label:    "client id",
@@ -156,6 +164,13 @@ func (driver Baidu) Files(path string, account *model.Account) ([]model.File, er
 }
 
 func (driver Baidu) Link(args base.Args, account *model.Account) (*base.Link, error) {
+	if account.InternalType == "file" {
+		return driver.LinkFile(args, account)
+	}
+	return driver.LinkAlbum(args, account)
+}
+
+func (driver Baidu) LinkAlbum(args base.Args, account *model.Account) (*base.Link, error) {
 	file, err := driver.File(args.Path, account)
 	if err != nil {
 		return nil, err
@@ -190,6 +205,42 @@ func (driver Baidu) Link(args base.Args, account *model.Account) (*base.Link, er
 	}, nil
 }
 
+func (driver Baidu) LinkFile(args base.Args, account *model.Account) (*base.Link, error) {
+	file, err := driver.File(args.Path, account)
+	if err != nil {
+		return nil, err
+	}
+
+	if !IsAlbumFile(file) {
+		return nil, base.ErrNotSupport
+	}
+
+	album, err := driver.File(utils.Dir(utils.ParsePath(args.Path)), account)
+	if err != nil {
+		return nil, err
+	}
+	// 拷贝到根目录
+	cfile, err := driver.CopyAlbumFile(album.Id, account, file.Id)
+	if err != nil {
+		return nil, err
+	}
+
+	res, err := driver.Request(http.MethodGet, FILE_API_URL_V2+"/download", func(r *resty.Request) {
+		r.SetQueryParams(map[string]string{
+			"fsid": fmt.Sprint(cfile.Fsid),
+		})
+	}, account)
+	if err != nil {
+		return nil, err
+	}
+	return &base.Link{
+		Headers: []base.Header{
+			{Name: "User-Agent", Value: base.UserAgent},
+		},
+		Url: utils.Json.Get(res.Body(), "dlink").ToString(),
+	}, nil
+}
+
 func (driver Baidu) Path(path string, account *model.Account) (*model.File, []model.File, error) {
 	path = utils.ParsePath(path)
 	file, err := driver.File(path, account)
@@ -402,7 +453,7 @@ func (driver Baidu) Upload(file *model.FileStream, account *model.Account) error
 
 	// 预上传
 	var precreateResp PrecreateResp
-	_, err = driver.Request(http.MethodPost, FILE_API_URL+"/precreate", func(r *resty.Request) {
+	_, err = driver.Request(http.MethodPost, FILE_API_URL_V1+"/precreate", func(r *resty.Request) {
 		r.SetFormData(params)
 		r.SetResult(&precreateResp)
 	}, account)
@@ -431,7 +482,7 @@ func (driver Baidu) Upload(file *model.FileStream, account *model.Account) error
 		fallthrough
 	case 2: // 创建文件
 		params["uploadid"] = precreateResp.UploadID
-		_, err = driver.Request(http.MethodPost, FILE_API_URL+"/create", func(r *resty.Request) {
+		_, err = driver.Request(http.MethodPost, FILE_API_URL_V1+"/create", func(r *resty.Request) {
 			r.SetFormData(params)
 			r.SetResult(&precreateResp)
 		}, account)
diff --git a/drivers/baiduphoto/types.go b/drivers/baiduphoto/types.go
index 734b5a538b6..926329d6ad4 100644
--- a/drivers/baiduphoto/types.go
+++ b/drivers/baiduphoto/types.go
@@ -97,7 +97,7 @@ type (
 type (
 	UploadFile struct {
 		FsID           int64  `json:"fs_id"`
-		Size           int    `json:"size"`
+		Size           int64  `json:"size"`
 		Md5            string `json:"md5"`
 		ServerFilename string `json:"server_filename"`
 		Path           string `json:"path"`
diff --git a/drivers/baiduphoto/util.go b/drivers/baiduphoto/util.go
index 5ab40a52c85..2c0542c7938 100644
--- a/drivers/baiduphoto/util.go
+++ b/drivers/baiduphoto/util.go
@@ -13,9 +13,10 @@ import (
 )
 
 const (
-	API_URL       = "https://photo.baidu.com/youai"
-	ALBUM_API_URL = API_URL + "/album/v1"
-	FILE_API_URL  = API_URL + "/file/v1"
+	API_URL         = "https://photo.baidu.com/youai"
+	ALBUM_API_URL   = API_URL + "/album/v1"
+	FILE_API_URL_V1 = API_URL + "/file/v1"
+	FILE_API_URL_V2 = API_URL + "/file/v2"
 )
 
 var (
diff --git a/drivers/ftp/driver.go b/drivers/ftp/driver.go
index d5915a95813..53f1a4e7966 100644
--- a/drivers/ftp/driver.go
+++ b/drivers/ftp/driver.go
@@ -227,13 +227,21 @@ func (driver FTP) Copy(src string, dst string, account *model.Account) error {
 
 func (driver FTP) Delete(path string, account *model.Account) error {
 	path = utils.ParsePath(path)
+	file, err := driver.File(path, account)
+	if err != nil {
+		return err
+	}
 	realPath := utils.Join(account.RootFolder, path)
 	conn, err := driver.Login(account)
 	if err != nil {
 		return err
 	}
 	//defer func() { _ = conn.Quit() }()
-	err = conn.Delete(realPath)
+	if file.IsDir() {
+		err = conn.RemoveDirRecur(realPath)
+	} else {
+		err = conn.Delete(realPath)
+	}
 	return err
 }
 
diff --git a/drivers/onedrive/onedrive.go b/drivers/onedrive/onedrive.go
index 7e4efc71194..77bc38ea1fd 100644
--- a/drivers/onedrive/onedrive.go
+++ b/drivers/onedrive/onedrive.go
@@ -307,8 +307,10 @@ func (driver Onedrive) UploadBig(file *model.FileStream, account *model.Account)
 		res, err := base.HttpClient.Do(req)
 		if res.StatusCode != 201 && res.StatusCode != 202 {
 			data, _ := ioutil.ReadAll(res.Body)
+			res.Body.Close()
 			return errors.New(string(data))
 		}
+		res.Body.Close()
 	}
 	return nil
 }
diff --git a/drivers/sftp/driver.go b/drivers/sftp/driver.go
index 1b61b536610..a0b70b1b4fc 100644
--- a/drivers/sftp/driver.go
+++ b/drivers/sftp/driver.go
@@ -116,7 +116,7 @@ func (driver SFTP) Files(path string, account *model.Account) ([]model.File, err
 	if err != nil {
 		return nil, err
 	}
-	var files []model.File
+	files := make([]model.File, 0)
 	rawFiles, err := client.Files(remotePath)
 	if err != nil {
 		return nil, err
diff --git a/drivers/xunlei/driver.go b/drivers/xunlei/driver.go
index bd2dddbc3c2..fa9db1cc36d 100644
--- a/drivers/xunlei/driver.go
+++ b/drivers/xunlei/driver.go
@@ -1,10 +1,6 @@
 package xunlei
 
 import (
-	"fmt"
-	"io"
-	"io/ioutil"
-	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
@@ -14,7 +10,10 @@ import (
 	"github.com/Xhofe/alist/drivers/base"
 	"github.com/Xhofe/alist/model"
 	"github.com/Xhofe/alist/utils"
-	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/service/s3/s3manager"
 	"github.com/go-resty/resty/v2"
 	"github.com/google/uuid"
 )
@@ -105,7 +104,7 @@ func (driver XunLeiCloud) Items() []base.Item {
 			Label:    "device id",
 			Default:  utils.GetMD5Encode(uuid.NewString()),
 			Type:     base.TypeString,
-			Required: false,
+			Required: true,
 		},
 	}
 }
@@ -117,8 +116,8 @@ func (driver XunLeiCloud) Save(account *model.Account, old *model.Account) error
 
 	client := GetClient(account)
 	// 指定验证通过的captchaToken
-	if client.captchaToken != "" {
-		client.captchaToken = account.CaptchaToken
+	if account.CaptchaToken != "" {
+		client.UpdateCaptchaToken(strings.TrimSpace(account.CaptchaToken))
 		account.CaptchaToken = ""
 	}
 
@@ -169,15 +168,17 @@ func (driver XunLeiCloud) Files(path string, account *model.Account) ([]model.Fi
 		return nil, err
 	}
 
-	time.Sleep(time.Millisecond * 400)
+	time.Sleep(time.Millisecond * 300)
 	files := make([]model.File, 0)
+	var pageToken string
 	for {
 		var fileList FileList
 		_, err = GetClient(account).Request("GET", FILE_API_URL, func(r *resty.Request) {
 			r.SetQueryParams(map[string]string{
 				"parent_id":  parentFile.Id,
-				"page_token": fileList.NextPageToken,
+				"page_token": pageToken,
 				"with_audit": "true",
+				"limit":      "100",
 				"filters":    `{"phase": {"eq": "PHASE_TYPE_COMPLETE"}, "trashed":{"eq":false}}`,
 			})
 			r.SetResult(&fileList)
@@ -193,6 +194,7 @@ func (driver XunLeiCloud) Files(path string, account *model.Account) ([]model.Fi
 		if fileList.NextPageToken == "" {
 			break
 		}
+		pageToken = fileList.NextPageToken
 	}
 	if len(files) > 0 {
 		_ = base.SetCache(path, files, account)
@@ -355,19 +357,24 @@ func (driver XunLeiCloud) Upload(file *model.FileStream, account *model.Account)
 		return err
 	}
 
-	tempFile, err := ioutil.TempFile(conf.Conf.TempDir, "file-*")
-	if err != nil {
-		return err
-	}
+	/*
+		tempFile, err := ioutil.TempFile(conf.Conf.TempDir, "file-*")
+		if err != nil {
+			return err
+		}
 
-	defer os.Remove(tempFile.Name())
+		defer tempFile.Close()
+		defer os.Remove(tempFile.Name())
 
-	gcid, err := getGcid(io.TeeReader(file, tempFile), int64(file.Size))
-	if err != nil {
-		return err
-	}
+		gcid, err := getGcid(io.TeeReader(file, tempFile), int64(file.Size))
+		if err != nil {
+			return err
+		}
 
-	tempFile.Close()
+		if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
+			return err
+		}
+	*/
 
 	var resp UploadTaskResponse
 	_, err = GetClient(account).Request("POST", FILE_API_URL, func(r *resty.Request) {
@@ -375,8 +382,8 @@ func (driver XunLeiCloud) Upload(file *model.FileStream, account *model.Account)
 			"kind":        FILE,
 			"parent_id":   parentFile.Id,
 			"name":        file.Name,
-			"size":        fmt.Sprint(file.Size),
-			"hash":        gcid,
+			"size":        file.Size,
+			"hash":        "1CF254FBC456E1B012CD45C546636AA62CF8350E",
 			"upload_type": UPLOAD_TYPE_RESUMABLE,
 		})
 		r.SetResult(&resp)
@@ -388,18 +395,21 @@ func (driver XunLeiCloud) Upload(file *model.FileStream, account *model.Account)
 	param := resp.Resumable.Params
 	if resp.UploadType == UPLOAD_TYPE_RESUMABLE {
 		param.Endpoint = strings.TrimLeft(param.Endpoint, param.Bucket+".")
-		client, err := oss.New(param.Endpoint, param.AccessKeyID, param.AccessKeySecret, oss.SecurityToken(param.SecurityToken), oss.EnableMD5(true))
-		if err != nil {
-			return err
-		}
-		bucket, err := client.Bucket(param.Bucket)
-		if err != nil {
-			return err
-		}
-		err = bucket.UploadFile(param.Key, tempFile.Name(), 1<<22, oss.Routines(3), oss.Checkpoint(true, ""), oss.Expires(param.Expiration))
+		s, err := session.NewSession(&aws.Config{
+			Credentials: credentials.NewStaticCredentials(param.AccessKeyID, param.AccessKeySecret, param.SecurityToken),
+			Region:      aws.String("xunlei"),
+			Endpoint:    aws.String(param.Endpoint),
+		})
 		if err != nil {
 			return err
 		}
+		_, err = s3manager.NewUploader(s).Upload(&s3manager.UploadInput{
+			Bucket:  aws.String(param.Bucket),
+			Key:     aws.String(param.Key),
+			Expires: aws.Time(param.Expiration),
+			Body:    file,
+		})
+		return err
 	}
 	return nil
 }
diff --git a/drivers/xunlei/xunlei.go b/drivers/xunlei/xunlei.go
index 13acd20230d..2c966c9937a 100644
--- a/drivers/xunlei/xunlei.go
+++ b/drivers/xunlei/xunlei.go
@@ -73,6 +73,8 @@ func (c *Client) requestCaptchaToken(action string, meta map[string]string) erro
 		SetBody(&param).
 		SetError(&e).
 		SetResult(&resp).
+		SetHeader("X-Device-Id", c.deviceID).
+		SetQueryParam("client_id", c.clientID).
 		Post(XLUSER_API_URL + "/shield/captcha/init")
 	if err != nil {
 		return err
@@ -115,8 +117,20 @@ func (c *Client) Login(account *model.Account) (err error) {
 		model.SaveAccount(account)
 	}()
 
+	meta := make(map[string]string)
+	if strings.Contains(account.Username, "@") {
+		meta["email"] = account.Username
+	} else if len(account.Username) >= 11 {
+		if !strings.Contains(account.Username, "+") {
+			account.Username = "+86 " + account.Username
+		}
+		meta["phone_number"] = account.Username
+	} else {
+		meta["username"] = account.Username
+	}
+
 	url := XLUSER_API_URL + "/auth/signin"
-	err = c.requestCaptchaToken(getAction(http.MethodPost, url), map[string]string{"username": account.Username})
+	err = c.requestCaptchaToken(getAction(http.MethodPost, url), meta)
 	if err != nil {
 		return err
 	}
@@ -133,6 +147,8 @@ func (c *Client) Login(account *model.Account) (err error) {
 			Username:     account.Username,
 			Password:     account.Password,
 		}).
+		SetHeader("X-Device-Id", c.deviceID).
+		SetQueryParam("client_id", c.clientID).
 		Post(url)
 	if err != nil {
 		return err
@@ -184,6 +200,8 @@ func (c *Client) RefreshToken() error {
 			"client_id":     c.clientID,
 			"client_secret": c.clientSecret,
 		}).
+		SetHeader("X-Device-Id", c.deviceID).
+		SetQueryParam("client_id", c.clientID).
 		Post(XLUSER_API_URL + "/auth/token")
 	if err != nil {
 		return err
@@ -211,7 +229,8 @@ func (c *Client) Request(method string, url string, callback func(*resty.Request
 			"X-Captcha-Token": c.captchaToken,
 			"User-Agent":      c.userAgent,
 			"client_id":       c.clientID,
-		}).SetQueryParam("client_id", c.clientID)
+		}).
+		SetQueryParam("client_id", c.clientID)
 	if callback != nil {
 		callback(req)
 	}
@@ -250,3 +269,14 @@ func (c *Client) Request(method string, url string, callback func(*resty.Request
 	}
 	return c.Request(method, url, callback, account)
 }
+
+func (c *Client) UpdateCaptchaToken(captchaToken string) bool {
+	c.Lock()
+	defer c.Unlock()
+
+	if captchaToken != "" {
+		c.captchaToken = captchaToken
+		return true
+	}
+	return false
+}
diff --git a/drivers/yandex/driver.go b/drivers/yandex/driver.go
index 3957fec9491..5edc5500374 100644
--- a/drivers/yandex/driver.go
+++ b/drivers/yandex/driver.go
@@ -213,7 +213,8 @@ func (driver Yandex) Upload(file *model.FileStream, account *model.Account) erro
 	}
 	req.Header.Set("Content-Length", strconv.FormatUint(file.Size, 10))
 	req.Header.Set("Content-Type", "application/octet-stream")
-	_, err = base.HttpClient.Do(req)
+	res, err := base.HttpClient.Do(req)
+	res.Body.Close()
 	//res, err := base.RestyClient.R().
 	//	SetHeader("Content-Length", strconv.FormatUint(file.Size, 10)).
 	//	SetBody(file).Put(resp.Href)
diff --git a/go.mod b/go.mod
index 433b2ed02f4..9da54ec129b 100644
--- a/go.mod
+++ b/go.mod
@@ -27,15 +27,12 @@ require (
 require github.com/kr/fs v0.1.0 // indirect
 
 require (
-	github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
 	github.com/fatih/color v1.13.0
 	github.com/mattn/go-colorable v0.1.9 // indirect
-	golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
 )
 
 require (
 	github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 // indirect
-	github.com/aliyun/aliyun-oss-go-sdk v2.2.1+incompatible
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
 	github.com/cenkalti/backoff/v4 v4.1.0 // indirect
diff --git a/go.sum b/go.sum
index 7e73c1242f9..7d46f2d7f81 100644
--- a/go.sum
+++ b/go.sum
@@ -20,8 +20,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/aliyun-oss-go-sdk v2.2.1+incompatible h1:uuJIwCFhbZy+zdvLy5zrcIToPEQP0s5CFOZ0Zj03O/w=
-github.com/aliyun/aliyun-oss-go-sdk v2.2.1+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/allegro/bigcache/v2 v2.2.5 h1:mRc8r6GQjuJsmSKQNPsR5jQVXc8IJ1xsW5YXUYMLfqI=
 github.com/allegro/bigcache/v2 v2.2.5/go.mod h1:FppZsIO+IZk7gCuj5FiIDHGygD9xvWQcqg1uIPMb6tY=
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -34,8 +32,6 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ
 github.com/aws/aws-sdk-go v1.27.0 h1:0xphMHGMLBrPMfxR2AmVjZKcMEESEgWF8Kru94BNByk=
 github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -466,8 +462,6 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
 github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
@@ -659,9 +653,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/server/common/proxy.go b/server/common/proxy.go
index 6a84d78f4f4..e6a2174e5e8 100644
--- a/server/common/proxy.go
+++ b/server/common/proxy.go
@@ -26,7 +26,7 @@ func Proxy(w http.ResponseWriter, r *http.Request, link *base.Link, file *model.
 			_ = link.Data.Close()
 		}()
 		w.Header().Set("Content-Type", "application/octet-stream")
-		w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename=%s`, url.QueryEscape(file.Name)))
+		w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename=%s`, file.Name))
 		w.Header().Set("Content-Length", strconv.FormatInt(file.Size, 10))
 		if link.Header != nil {
 			for h, val := range link.Header {
diff --git a/server/static.go b/server/static.go
index c91ea10abe0..c60b98d47c5 100644
--- a/server/static.go
+++ b/server/static.go
@@ -1,14 +1,16 @@
 package server
 
 import (
-	"github.com/Xhofe/alist/conf"
-	"github.com/Xhofe/alist/public"
-	"github.com/gin-gonic/gin"
-	log "github.com/sirupsen/logrus"
 	"io/fs"
 	"io/ioutil"
 	"net/http"
+	"net/http/pprof"
 	"strings"
+
+	"github.com/Xhofe/alist/conf"
+	"github.com/Xhofe/alist/public"
+	"github.com/gin-gonic/gin"
+	log "github.com/sirupsen/logrus"
 )
 
 func InitIndex() {
@@ -48,6 +50,8 @@ func Static(r *gin.Engine) {
 		c.Status(200)
 		if strings.HasPrefix(c.Request.URL.Path, "/@manage") {
 			_, _ = c.Writer.WriteString(conf.ManageHtml)
+		} else if strings.HasPrefix(c.Request.URL.Path, "/debug/pprof") {
+			pprof.Index(c.Writer, c.Request)
 		} else {
 			_, _ = c.Writer.WriteString(conf.IndexHtml)
 		}


Test patch: