Compare commits

..

14 Commits

Author SHA1 Message Date
c63e05983d fix: 189cloud big file download (close #683) 2022-03-07 15:04:20 +08:00
678a982535 feat: add sleep for lanzou request (close #690) 2022-03-07 14:36:25 +08:00
b2c02e6c5e feat: add driver template 2022-03-06 21:33:58 +08:00
7e05b0317f chore: Merge pull request #689 from Xhofe/dev
docs: add Contributing and move Contributors
2022-03-06 20:49:14 +08:00
19f06dfaed docs: fix typo [skip ci] 2022-03-06 20:44:37 +08:00
1680a18578 docs: move CONTRIBUTORS [skip ci] 2022-03-06 20:38:30 +08:00
e8f440ca5c docs: create CONTRIBUTING.md [skip ci] 2022-03-06 20:30:17 +08:00
7deff76f49 chore: Merge pull request #687 from Xhofe/all-contributors/add-Clansty
docs: add Clansty as a contributor for doc
2022-03-06 17:36:13 +08:00
cd0afb9536 docs: update .all-contributorsrc [skip ci] 2022-03-06 09:35:08 +00:00
668a953cd8 docs: update README_cn.md [skip ci] 2022-03-06 09:35:07 +00:00
8bfbaa74f6 docs: update README.md [skip ci] 2022-03-06 09:35:06 +00:00
3ccf5ee620 fix: ipa plist key 2022-03-05 15:33:04 +08:00
b44243c021 feat: ipa name decode 2022-03-05 15:13:19 +08:00
4ae81b5a79 feat: aliyundrive fast upload (#652) 2022-03-05 13:14:57 +08:00
16 changed files with 541 additions and 109 deletions

View File

@ -1,7 +1,6 @@
{
"files": [
"README.md",
"README_cn.md"
"CONTRIBUTORS.md"
],
"imageSize": 100,
"commit": false,
@ -43,6 +42,15 @@
"contributions": [
"code"
]
},
{
"login": "Clansty",
"name": "凌莞~(=^▽^=)",
"avatar_url": "https://avatars.githubusercontent.com/u/18461360?v=4",
"profile": "https://c5y.moe",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7,

105
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,105 @@
# Contributing
## Setup your machine
`alist` is written in [Go](https://golang.org/) and [React](https://reactjs.org/).
Prerequisites:
- [git](https://nodejs.org/zh-cn/)
- [Go 1.17+](https://golang.org/doc/install)
- [gcc](https://gcc.gnu.org/)
- [nodejs](https://nodejs.org/)
Clone `alist` and `alist-web` anywhere:
```shell
$ git clone https://github.com/Xhofe/alist.git
$ git clone https://github.com/Xhofe/alist-web.git
```
You should switch to the dev branch for development.
## Preview your change
### backend
```shell
$ go run alist.go
```
### frontend
```shell
$ yarn dev
```
## Create a commit
Commit messages should be well formatted, and to make that "standardized".
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header
of the reverted commit.
In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit
being reverted.
### Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing or correcting existing tests
* **build**: Affects project builds or dependency modifications
* **revert**: Restore the previous commit
* **ci**: Continuous integration of related file modifications
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
* **release**: Release a new version
* **workflow**: Workflow related file modification
### Scope
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
You can use `*` when the change affects more than a single scope.
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
[reference GitHub issues that this commit closes](https://help.github.com/articles/closing-issues-via-commit-messages/).
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines.
The rest of the commit message is then used for this.
## Submit a pull request
Push your branch to your `alist` fork and open a pull request against the
`dev` branch.

27
CONTRIBUTORS.md Normal file
View File

@ -0,0 +1,27 @@
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://nn.ci"><img src="https://avatars.githubusercontent.com/u/36558727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xhofe</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=Xhofe" title="Code">💻</a> <a href="#ideas-Xhofe" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/Xhofe/alist/commits?author=Xhofe" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/foxxorcat"><img src="https://avatars.githubusercontent.com/u/95907542?v=4?s=100" width="100px;" alt=""/><br /><sub><b>foxxorcat</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=foxxorcat" title="Code">💻</a></td>
<td align="center"><a href="https://www.iflu.cf/"><img src="https://avatars.githubusercontent.com/u/63903027?v=4?s=100" width="100px;" alt=""/><br /><sub><b>道辰</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=DaoChen6" title="Documentation">📖</a></td>
<td align="center"><a href="https://vg-land.github.io/"><img src="https://avatars.githubusercontent.com/u/16739728?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vg-land</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=vg-land" title="Code">💻</a></td>
<td align="center"><a href="https://c5y.moe"><img src="https://avatars.githubusercontent.com/u/18461360?v=4?s=100" width="100px;" alt=""/><br /><sub><b>凌莞~(=^▽^=)</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=Clansty" title="Documentation">📖</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

View File

@ -13,11 +13,7 @@
---
English | [中文](./README_cn.md)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
English | [中文](./README_cn.md) | [Contributors](./CONTRIBUTORS.md) | [Contributing](./CONTRIBUTING.md)
## Features
@ -73,29 +69,6 @@ Available at: <https://alist.nn.ci>.
<https://alist-doc.nn.ci/en/>
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://nn.ci"><img src="https://avatars.githubusercontent.com/u/36558727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xhofe</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=Xhofe" title="Code">💻</a> <a href="#ideas-Xhofe" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/Xhofe/alist/commits?author=Xhofe" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/foxxorcat"><img src="https://avatars.githubusercontent.com/u/95907542?v=4?s=100" width="100px;" alt=""/><br /><sub><b>foxxorcat</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=foxxorcat" title="Code">💻</a></td>
<td align="center"><a href="https://www.iflu.cf/"><img src="https://avatars.githubusercontent.com/u/63903027?v=4?s=100" width="100px;" alt=""/><br /><sub><b>道辰</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=DaoChen6" title="Documentation">📖</a></td>
<td align="center"><a href="https://vg-land.github.io/"><img src="https://avatars.githubusercontent.com/u/16739728?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vg-land</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=vg-land" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## License
The `AList` is open-source software licensed under the AGPL-3.0 license.

View File

@ -13,11 +13,7 @@
---
[English](./README.md) | 中文
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[English](./README.md) | 中文 | [Contributors](./CONTRIBUTORS.md) | [Contributing](./CONTRIBUTING.md)
## 支持
@ -73,29 +69,6 @@
<https://alist-doc.nn.ci/>
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://nn.ci"><img src="https://avatars.githubusercontent.com/u/36558727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xhofe</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=Xhofe" title="Code">💻</a> <a href="#ideas-Xhofe" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/Xhofe/alist/commits?author=Xhofe" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/foxxorcat"><img src="https://avatars.githubusercontent.com/u/95907542?v=4?s=100" width="100px;" alt=""/><br /><sub><b>foxxorcat</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=foxxorcat" title="Code">💻</a></td>
<td align="center"><a href="https://www.iflu.cf/"><img src="https://avatars.githubusercontent.com/u/63903027?v=4?s=100" width="100px;" alt=""/><br /><sub><b>道辰</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=DaoChen6" title="Documentation">📖</a></td>
<td align="center"><a href="https://vg-land.github.io/"><img src="https://avatars.githubusercontent.com/u/16739728?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vg-land</b></sub></a><br /><a href="https://github.com/Xhofe/alist/commits?author=vg-land" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## 许可
`AList` 是在 AGPL-3.0 许可下许可的开源软件。

View File

@ -88,12 +88,6 @@ func (driver Cloud189) FormatFile(file *Cloud189File) *model.File {
// return nil, ErrPathNotFound
//}
type Cloud189Down struct {
ResCode int `json:"res_code"`
ResMessage string `json:"res_message"`
FileDownloadUrl string `json:"fileDownloadUrl"`
}
type LoginResp struct {
Msg string `json:"msg"`
Result int `json:"result"`

View File

@ -6,7 +6,9 @@ import (
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
"net/http"
"path/filepath"
)
@ -152,14 +154,15 @@ func (driver Cloud189) Link(args base.Args, account *model.Account) (*base.Link,
if file.Type == conf.FOLDER {
return nil, base.ErrNotFile
}
var resp Cloud189Down
u := "https://cloud.189.cn/api/open/file/getFileDownloadUrl.action"
var resp DownResp
u := "https://cloud.189.cn/api/portal/getFileInfo.action"
body, err := driver.Request(u, base.Get, map[string]string{
"fileId": file.Id,
}, nil, nil, account)
if err != nil {
return nil, err
}
log.Debugln(string(body))
err = utils.Json.Unmarshal(body, &resp)
if err != nil {
return nil, err
@ -167,10 +170,19 @@ func (driver Cloud189) Link(args base.Args, account *model.Account) (*base.Link,
if resp.ResCode != 0 {
return nil, fmt.Errorf(resp.ResMessage)
}
res, err := base.NoRedirectClient.R().Get(resp.FileDownloadUrl)
client, err := driver.getClient(account)
if err != nil {
return nil, err
}
client = resty.NewWithClient(client.GetClient()).SetRedirectPolicy(
resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}))
res, err := client.R().Get("https:" + resp.FileDownloadUrl)
if err != nil {
return nil, err
}
log.Debugln(res.Status())
link := base.Link{
Headers: []base.Header{
{Name: "User-Agent", Value: base.UserAgent},
@ -179,6 +191,10 @@ func (driver Cloud189) Link(args base.Args, account *model.Account) (*base.Link,
}
if res.StatusCode() == 302 {
link.Url = res.Header().Get("location")
res, err = client.R().Get(link.Url)
if res.StatusCode() == 302 {
link.Url = res.Header().Get("location")
}
} else {
link.Url = resp.FileDownloadUrl
}

View File

@ -53,3 +53,15 @@ type Rsa struct {
PkId string `json:"pkId"`
PubKey string `json:"pubKey"`
}
type Cloud189Down struct {
ResCode int `json:"res_code"`
ResMessage string `json:"res_message"`
FileDownloadUrl string `json:"fileDownloadUrl"`
}
type DownResp struct {
ResCode int `json:"res_code"`
ResMessage string `json:"res_message"`
FileDownloadUrl string `json:"downloadUrl"`
}

View File

@ -2,18 +2,25 @@ package alidrive
import (
"bytes"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"math/big"
"net/http"
"os"
"path/filepath"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus"
"io"
"math"
"net/http"
"path/filepath"
)
type AliDrive struct{}
@ -376,15 +383,16 @@ type UploadResp struct {
PartInfoList []struct {
UploadUrl string `json:"upload_url"`
} `json:"part_info_list"`
RapidUpload bool `json:"rapid_upload"`
}
func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) error {
if file == nil {
return base.ErrEmptyFile
}
const DEFAULT uint64 = 10485760
const DEFAULT int64 = 10485760
var count = int64(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
var finish uint64 = 0
parentFile, err := driver.File(file.ParentPath, account)
if err != nil {
return err
@ -392,32 +400,38 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
if !parentFile.IsDir() {
return base.ErrNotFolder
}
var resp UploadResp
var e AliRespError
partInfoList := make([]base.Json, 0)
partInfoList := make([]base.Json, 0, count)
var i int64
for i = 0; i < count; i++ {
partInfoList = append(partInfoList, base.Json{
"part_number": i + 1,
})
}
_, err = aliClient.R().SetResult(&resp).SetError(&e).
SetHeader("authorization", "Bearer\t"+account.AccessToken).
SetBody(base.Json{
"check_name_mode": "auto_rename",
// content_hash
"content_hash_name": "none",
"drive_id": account.DriveId,
"name": file.GetFileName(),
"parent_file_id": parentFile.Id,
"part_info_list": partInfoList,
//proof_code
"proof_version": "v1",
"size": file.GetSize(),
"type": "file",
}).Post("https://api.aliyundrive.com/adrive/v2/file/createWithFolders") // /v2/file/create_with_proof
//log.Debugf("%+v\n%+v", resp, e)
if e.Code != "" {
buf := make([]byte, 1024)
n, _ := file.Read(buf[:])
reqBody := base.Json{
"check_name_mode": "auto_rename",
"drive_id": account.DriveId,
"name": file.GetFileName(),
"parent_file_id": parentFile.Id,
"part_info_list": partInfoList,
"size": file.GetSize(),
"type": "file",
"pre_hash": utils.GetSHA1Encode(string(buf[:n])),
}
fileReader := io.MultiReader(bytes.NewReader(buf[:n]), file.File)
var resp UploadResp
var e AliRespError
client := aliClient.R().SetResult(&resp).SetError(&e).SetHeader("authorization", "Bearer\t"+account.AccessToken).SetBody(reqBody)
_, err = client.Post("https://api.aliyundrive.com/adrive/v2/file/createWithFolders")
if err != nil {
return err
}
if e.Code != "" && e.Code != "PreHashMatched" {
if e.Code == "AccessTokenInvalid" {
err = driver.RefreshToken(account)
if err != nil {
@ -429,26 +443,59 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
}
return fmt.Errorf("%s", e.Message)
}
var byteSize uint64
for i = 0; i < count; i++ {
byteSize = file.GetSize() - finish
if DEFAULT < byteSize {
byteSize = DEFAULT
}
log.Debugf("%d,%d", byteSize, finish)
byteData := make([]byte, byteSize)
n, err := io.ReadFull(file, byteData)
//n, err := file.Read(byteData)
//byteData, err := io.ReadAll(file)
//n := len(byteData)
log.Debug(err, n)
if e.Code == "PreHashMatched" {
tempFile, err := ioutil.TempFile(conf.Conf.TempDir, "file-*")
if err != nil {
return err
}
finish += uint64(n)
defer tempFile.Close()
defer os.Remove(tempFile.Name())
req, err := http.NewRequest("PUT", resp.PartInfoList[i].UploadUrl, bytes.NewBuffer(byteData))
delete(reqBody, "pre_hash")
h := sha1.New()
if _, err = io.Copy(tempFile, io.TeeReader(fileReader, h)); err != nil {
return err
}
reqBody["content_hash"] = hex.EncodeToString(h.Sum(nil))
reqBody["content_hash_name"] = "sha1"
reqBody["proof_version"] = "v1"
/*
js 隐性转换太坑不知道有没有bug
var n = e.access_token
r = new BigNumber('0x'.concat(md5(n).slice(0, 16)))
i = new BigNumber(t.file.size)
o = i ? r.mod(i) : new gt.BigNumber(0);
(t.file.slice(o.toNumber(), Math.min(o.plus(8).toNumber(), t.file.size)))
*/
r, _ := new(big.Int).SetString(utils.GetMD5Encode(account.AccessToken)[:16], 16)
i := new(big.Int).SetUint64(file.Size)
o := r.Mod(r, i)
n, _ = io.NewSectionReader(tempFile, o.Int64(), 8).Read(buf[:8])
reqBody["proof_code"] = base64.StdEncoding.EncodeToString(buf[:n])
_, err = client.Post("https://api.aliyundrive.com/adrive/v2/file/createWithFolders")
if err != nil {
return err
}
if e.Code != "" && e.Code != "PreHashMatched" {
return fmt.Errorf("%s", e.Message)
}
if resp.RapidUpload {
return nil
}
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
return err
}
fileReader = tempFile
}
for i = 0; i < count; i++ {
req, err := http.NewRequest("PUT", resp.PartInfoList[i].UploadUrl, io.LimitReader(fileReader, DEFAULT))
if err != nil {
return err
}
@ -473,6 +520,9 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
"file_id": resp.FileId,
"upload_id": resp.UploadId,
}).Post("https://api.aliyundrive.com/v2/file/complete")
if err != nil {
return err
}
if e.Code != "" {
//if e.Code == "AccessTokenInvalid" {
// err = driver.RefreshToken(account)

View File

@ -153,6 +153,7 @@ func (driver *Lanzou) GetFilesByUrl(account *model.Account) ([]LanZouFile, error
break
}
pg++
time.Sleep(time.Second)
files = append(files, resp.Text...)
}
return files, nil

149
drivers/template/driver.go Normal file
View File

@ -0,0 +1,149 @@
package template
import (
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"path/filepath"
)
type Template struct {
}
func (driver Template) Config() base.DriverConfig {
return base.DriverConfig{
Name: "Template",
OnlyProxy: false,
OnlyLocal: false,
ApiProxy: false,
NoNeedSetLink: false,
NoCors: false,
LocalSort: false,
}
}
func (driver Template) Items() []base.Item {
// TODO fill need info
return []base.Item{
{
Name: "refresh_token",
Label: "refresh token",
Type: base.TypeString,
Required: true,
},
{
Name: "root_folder",
Label: "root folder path",
Type: base.TypeString,
Default: "/",
Required: true,
},
}
}
func (driver Template) Save(account *model.Account, old *model.Account) error {
// TODO test available or init
return nil
}
func (driver Template) 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 Template) Files(path string, account *model.Account) ([]model.File, error) {
path = utils.ParsePath(path)
cache, err := base.GetCache(path, account)
if err == nil {
files, _ := cache.([]model.File)
return files, nil
}
var files []model.File
// TODO get files
if err != nil {
return nil, err
}
if len(files) > 0 {
_ = base.SetCache(path, files, account)
}
return files, nil
}
func (driver Template) Link(args base.Args, account *model.Account) (*base.Link, error) {
// TODO get file link
return nil, base.ErrNotImplement
}
func (driver Template) Path(path string, account *model.Account) (*model.File, []model.File, error) {
path = utils.ParsePath(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 Template) Preview(path string, account *model.Account) (interface{}, error) {
//TODO preview interface if driver support
return nil, base.ErrNotImplement
}
func (driver Template) MakeDir(path string, account *model.Account) error {
//TODO make dir
return base.ErrNotImplement
}
func (driver Template) Move(src string, dst string, account *model.Account) error {
//TODO move file/dir
return base.ErrNotImplement
}
func (driver Template) Rename(src string, dst string, account *model.Account) error {
//TODO rename file/dir
return base.ErrNotImplement
}
func (driver Template) Copy(src string, dst string, account *model.Account) error {
//TODO copy file/dir
return base.ErrNotImplement
}
func (driver Template) Delete(path string, account *model.Account) error {
//TODO delete file/dir
return base.ErrNotImplement
}
func (driver Template) Upload(file *model.FileStream, account *model.Account) error {
//TODO upload file
return base.ErrNotImplement
}
var _ base.Driver = (*Template)(nil)

View File

@ -0,0 +1,90 @@
package template
import (
"errors"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/go-resty/resty/v2"
"path"
)
func LoginOrRefreshToken(account *model.Account) error {
return nil
}
func Request(u string, method int, headers, query, form map[string]string, data interface{}, resp interface{}, account *model.Account) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeaders(map[string]string{
"Authorization": "Bearer" + account.AccessToken,
"Accept": "application/json, text/plain, */*",
})
if headers != nil {
req.SetHeaders(headers)
}
if query != nil {
req.SetQueryParams(query)
}
if form != nil {
req.SetFormData(form)
}
if data != nil {
req.SetBody(data)
}
if resp != nil {
req.SetResult(resp)
}
var e Resp
var err error
var res *resty.Response
req.SetError(&e)
switch method {
case base.Get:
res, err = req.Get(u)
case base.Post:
res, err = req.Post(u)
case base.Delete:
res, err = req.Delete(u)
case base.Patch:
res, err = req.Patch(u)
case base.Put:
res, err = req.Put(u)
default:
return nil, base.ErrNotSupport
}
if err != nil {
return nil, err
}
if e.Code >= 400 {
if e.Code == 401 {
err = LoginOrRefreshToken(account)
if err != nil {
return nil, err
}
return Request(u, method, headers, query, form, data, resp, account)
}
return nil, errors.New(e.Message)
}
return res.Body(), nil
}
func (driver Template) formatFile(f *File) *model.File {
file := model.File{
Id: f.Id,
Name: f.FileName,
Size: f.Size,
Driver: driver.Config().Name,
UpdatedAt: f.UpdatedAt,
}
if f.File {
file.Type = utils.GetFileType(path.Ext(f.FileName))
} else {
file.Type = conf.FOLDER
}
return &file
}
func init() {
base.RegisterDriver(&Template{})
}

18
drivers/template/types.go Normal file
View File

@ -0,0 +1,18 @@
package template
import "time"
// write all struct here
type Resp struct {
Code int `json:"code"`
Message string `json:"message"`
}
type File struct {
Id string `json:"id"`
FileName string `json:"file_name"`
Size int64 `json:"size"`
File bool `json:"file"`
UpdatedAt *time.Time `json:"updated_at"`
}

3
drivers/template/util.go Normal file
View File

@ -0,0 +1,3 @@
package template
// write util func here, such as cal sign

View File

@ -33,8 +33,14 @@ func Plist(c *gin.Context) {
name := utils.Base(u)
u = uUrl.String()
ipaIndex := strings.Index(name, ".ipa")
decodeName := name
if ipaIndex != -1 {
name = name[:ipaIndex]
decodeName = name
tmp, err := url.PathUnescape(name)
if err == nil {
decodeName = tmp
}
}
name = strings.ReplaceAll(name, "<", "[")
name = strings.ReplaceAll(name, ">", "]")
@ -67,7 +73,7 @@ func Plist(c *gin.Context) {
</dict>
</array>
</dict>
</plist>`, u, name, name)
</plist>`, u, name, decodeName)
c.Header("Content-Type", "application/xml;charset=utf-8")
c.Status(200)
_, _ = c.Writer.WriteString(plist)

View File

@ -2,10 +2,17 @@ package utils
import (
"crypto/md5"
"crypto/sha1"
"encoding/hex"
"fmt"
)
func GetSHA1Encode(data string) string {
h := sha1.New()
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
// GetMD5Encode
func GetMD5Encode(data string) string {
h := md5.New()