Compare commits

...

27 Commits

Author SHA1 Message Date
7bfa5876ed fix(189pc): fix typo 2022-11-01 19:32:40 +08:00
f95ab6ee57 docs: add 115 to readme [skip ci] 2022-11-01 19:28:24 +08:00
e75f19e9c0 feat: add Referrer-Policy while redirect (pr #2160) 2022-11-01 19:19:08 +08:00
1c212f6c30 feat!: force to use the bin dir as the data dir (close #2108)
- move default log path to `data/log/log.log`
- replace `--conf` with `--data`
2022-11-01 19:16:23 +08:00
141419056d feat(115): add cloud 115 driver (#2164)
close #2112
close #1598
close #894
2022-11-01 15:31:31 +08:00
aabfe49cb9 docs: change contributors show [skip ci] 2022-10-30 15:26:31 +08:00
a3b631f9e9 fix(smb): remount smb before each operation (close #2123 pr #2140) 2022-10-30 15:05:07 +08:00
18165eb50d fix(123): get real url (#2135)
123 今天更新多加了一层跳转`https://web-pro.cjjd18.com/download/?params=base64encode(rawurl)`,导致ip如果不符则可能下载返回403,在服务器端处理获取rawurl
2022-10-27 17:02:35 +08:00
061c462f0b feat(mediatrack): get real url (#2132)
* feat:get real url for mediatrack

redirect token 一次有效,点击第二次就抛出了`400`错误。本次提交直接获取302后的真实链接返回前端

* add cache

cache 60 Second
2022-10-27 15:26:08 +08:00
5f79d665d9 feat: add alist v3 driver (close #1833 pr #2129)
* feat: add alist v3 driver (close #1833)

* chore: use generics

Co-authored-by: Noah Hsu <i@nn.ci>
2022-10-27 10:54:49 +08:00
f0cc0a76a9 chore: fix typos (#2122)
* refactor: fix typos

* Update help.go

Co-authored-by: Noah Hsu <i@nn.ci>
2022-10-26 14:05:56 +08:00
dd4674e486 feat: add smb driver (close #1746) (#2114)
* feat: add smb driver (close #1746)

* Update driver.go
2022-10-25 23:00:23 +08:00
0019959eec fix: delete cache if files is empty 2022-10-25 16:42:06 +08:00
3e9c38697d fix: use utils.Log during static file router init (#2100)
formerly the log is not in stderr
2022-10-24 23:33:57 +08:00
e3b7c41199 docs: update demo url & sponsor content [skip ci] 2022-10-24 22:48:36 +08:00
a2c808c8ce fix: incorrect root path of initial storage for dev mode 2022-10-23 16:26:14 +08:00
da7e17aa38 feat(local): add show hidden config (#2087) 2022-10-23 14:53:07 +08:00
02df3759df docs: fix typo [skip ci] 2022-10-20 14:29:28 +08:00
4fef500795 feat(user): set default password of init user from env (#2058)
add init user default password

Signed-off-by: ysicing <i@ysicing.me>

Signed-off-by: ysicing <i@ysicing.me>
2022-10-19 20:06:06 +08:00
07ece452b3 docs: fix docker link [skip ci] 2022-10-19 17:08:01 +08:00
b8cf02ca68 fix(aria2): retry 5 times for get status (close #1857) 2022-10-18 15:27:19 +08:00
3db798a82a feat(google_photo): Add categories in root, add album support. (#2046)
* feat(google_photo): Add categories in root, add album support.

* fix(google_photo): Remove else block in `drive/google_photo/types.go:60`
2022-10-18 15:19:05 +08:00
45cc0cedbd fix(s3): mkdir and delete (close #2029) 2022-10-18 15:10:47 +08:00
2efade123e fix(189pc):slice bounds out of range close #2045 2022-10-17 22:39:51 +08:00
fc393f743f fix(thunder):no additional processing when the deviceID is correct 2022-10-17 22:37:17 +08:00
0e99e7e9b9 fix(thunder,189pc): some known problems 2022-10-17 00:54:39 +08:00
7a95850c1b fix(google_drive): incorrect ModifiedTime (close #2002) 2022-10-14 14:17:33 +08:00
52 changed files with 1112 additions and 296 deletions

View File

@ -1,98 +0,0 @@
{
"files": [
"CONTRIBUTORS.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "Xhofe",
"name": "Xhofe",
"avatar_url": "https://avatars.githubusercontent.com/u/36558727?v=4",
"profile": "http://nn.ci",
"contributions": [
"code",
"ideas",
"doc"
]
},
{
"login": "foxxorcat",
"name": "foxxorcat",
"avatar_url": "https://avatars.githubusercontent.com/u/95907542?v=4",
"profile": "https://github.com/foxxorcat",
"contributions": [
"code"
]
},
{
"login": "DaoChen6",
"name": "道辰",
"avatar_url": "https://avatars.githubusercontent.com/u/63903027?v=4",
"profile": "https://www.iflu.cf/",
"contributions": [
"doc"
]
},
{
"login": "vg-land",
"name": "vg-land",
"avatar_url": "https://avatars.githubusercontent.com/u/16739728?v=4",
"profile": "https://vg-land.github.io/",
"contributions": [
"code"
]
},
{
"login": "Clansty",
"name": "凌莞~(=^▽^=)",
"avatar_url": "https://avatars.githubusercontent.com/u/18461360?v=4",
"profile": "https://c5y.moe",
"contributions": [
"doc"
]
},
{
"login": "Windman1320",
"name": "Windman",
"avatar_url": "https://avatars.githubusercontent.com/u/9999486?v=4",
"profile": "https://github.com/Windman1320",
"contributions": [
"code"
]
},
{
"login": "ericarena",
"name": "ericarena",
"avatar_url": "https://avatars.githubusercontent.com/u/4518927?v=4",
"profile": "https://github.com/ericarena",
"contributions": [
"code"
]
},
{
"login": "WntFlm",
"name": "WntFlm",
"avatar_url": "https://avatars.githubusercontent.com/u/34620278?v=4",
"profile": "https://github.com/WntFlm",
"contributions": [
"code"
]
},
{
"login": "XZB-1248",
"name": "XZB-1248",
"avatar_url": "https://avatars.githubusercontent.com/u/28593573?v=4",
"profile": "https://github.com/XZB-1248",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,
"projectName": "alist",
"projectOwner": "alist-org",
"repoType": "github",
"repoHost": "https://github.com",
"skipCi": true
}

View File

@ -1,33 +0,0 @@
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-9-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/alist-org/alist/commits?author=Xhofe" title="Code">💻</a> <a href="#ideas-Xhofe" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/alist-org/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/alist-org/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/alist-org/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/alist-org/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/alist-org/alist/commits?author=Clansty" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Windman1320"><img src="https://avatars.githubusercontent.com/u/9999486?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Windman</b></sub></a><br /><a href="https://github.com/alist-org/alist/commits?author=Windman1320" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ericarena"><img src="https://avatars.githubusercontent.com/u/4518927?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ericarena</b></sub></a><br /><a href="https://github.com/alist-org/alist/commits?author=ericarena" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/WntFlm"><img src="https://avatars.githubusercontent.com/u/34620278?v=4?s=100" width="100px;" alt=""/><br /><sub><b>WntFlm</b></sub></a><br /><a href="https://github.com/alist-org/alist/commits?author=WntFlm" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/XZB-1248"><img src="https://avatars.githubusercontent.com/u/28593573?v=4?s=100" width="100px;" alt=""/><br /><sub><b>XZB-1248</b></sub></a><br /><a href="https://github.com/alist-org/alist/commits?author=XZB-1248" 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!

View File

@ -28,10 +28,10 @@
<a href="https://github.com/Xhofe/alist/releases">
<img src="https://img.shields.io/github/downloads/Xhofe/alist/total?color=%239F7AEA&logo=github" alt="Downloads" />
</a>
<a href="https://github.com/Xhofe/alist/releases">
<a href="https://hub.docker.com/r/xhofe/alist">
<img src="https://img.shields.io/docker/pulls/xhofe/alist?color=%2348BB78&logo=docker&label=pulls" alt="Downloads" />
</a>
<a href="https://alist.nn.ci/zh/guide/sponsor.html">
<a href="https://alist.nn.ci/guide/sponsor.html">
<img src="https://img.shields.io/badge/%24-sponsor-F87171.svg" alt="sponsor" />
</a>
</div>
@ -39,7 +39,7 @@
---
English | [中文](./README_cn.md) | [Contributors](./CONTRIBUTORS.md) | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
English | [中文](./README_cn.md) | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
## Features
@ -67,6 +67,8 @@ English | [中文](./README_cn.md) | [Contributors](./CONTRIBUTORS.md) | [Contri
- [x] [Google photo](https://photos.google.com/)
- [x] [Mega.nz](https://mega.nz)
- [x] [Baidu photo](https://photo.baidu.com/)
- [x] SMB
- [x] [115](https://115.com/)
- [x] Easy to deploy and out-of-the-box
- [x] File preview (PDF, markdown, code, plain text, ...)
- [x] Image preview in gallery mode
@ -91,17 +93,29 @@ English | [中文](./README_cn.md) | [Contributors](./CONTRIBUTORS.md) | [Contri
## Demo
<https://pan.nn.ci>
<https://al.nn.ci>
## Discussion
Please go to our [discussion forum](https://github.com/Xhofe/alist/discussions) for general questions, **issues are for bug reports and feature request only.**
## Special sponsors
## Sponsor
AList is an open-source software, if you happen to like this project and want me to keep going, please consider sponsoring me or providing a single donation! Thanks for all the love and support:
https://alist.nn.ci/guide/sponsor.html
### Special sponsors
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
- [KinhDown 百度云盘不限速下载永久免费已稳定运行3年非常可靠!](https://kinhdown.com/?Type=Tutorials)
- [KinhDown 百度云盘不限速下载永久免费已稳定运行3年非常可靠Q群 -> 786799372](https://kinhdown.com)
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
## Contributors
Thanks goes to these wonderful people:
[![Contributors](http://contributors.nn.ci/api?repo=alist-org/alist&repo=alist-org/alist-web&repo=alist-org/docs)](https://github.com/alist-org/alist/graphs/contributors)
## License
The `AList` is open-source software licensed under the AGPL-3.0 license.

View File

@ -28,7 +28,7 @@
<a href="https://github.com/Xhofe/alist/releases">
<img src="https://img.shields.io/github/downloads/Xhofe/alist/total?color=%239F7AEA&logo=github" alt="Downloads" />
</a>
<a href="https://github.com/Xhofe/alist/releases">
<a href="https://hub.docker.com/r/xhofe/alist">
<img src="https://img.shields.io/docker/pulls/xhofe/alist?color=%2348BB78&logo=docker&label=pulls" alt="Downloads" />
</a>
<a href="https://alist.nn.ci/zh/guide/sponsor.html">
@ -39,7 +39,7 @@
---
[English](./README.md) | 中文 | [Contributors](./CONTRIBUTORS.md) | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
[English](./README.md) | 中文 | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
## Features
@ -67,6 +67,8 @@
- [x] [谷歌相册](https://photos.google.com/)
- [x] [Mega.nz](https://mega.nz)
- [x] [一刻相册](https://photo.baidu.com/)
- [x] SMB
- [x] [115](https://115.com/)
- [x] 部署方便,开箱即用
- [x] 文件预览PDF、markdown、代码、纯文本……
- [x] 画廊模式下的图像预览
@ -91,17 +93,28 @@
## Demo
<https://pan.nn.ci>
<https://al.nn.ci>
## Discussion
一般问题请到[讨论论坛](https://github.com/Xhofe/alist/discussions) **issue仅针对错误报告和功能请求。**
## Special sponsors
## Sponsor
AList 是一个开源软件如果你碰巧喜欢这个项目并希望我继续下去请考虑赞助我或提供一个单一的捐款感谢所有的爱和支持https://alist.nn.ci/zh/guide/sponsor.html
### Special sponsors
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
- [KinhDown 百度云盘不限速下载永久免费已稳定运行3年非常可靠!](https://kinhdown.com/?Type=Tutorials)
- [KinhDown 百度云盘不限速下载永久免费已稳定运行3年非常可靠Q群 -> 786799372](https://kinhdown.com)
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
## Contributors
Thanks goes to these wonderful people:
[![Contributors](http://contributors.nn.ci/api?repo=alist-org/alist&repo=alist-org/alist-web&repo=alist-org/docs)](https://github.com/alist-org/alist/graphs/contributors)
## 许可
`AList` 是在 AGPL-3.0 许可下许可的开源软件。

View File

@ -1,8 +1,9 @@
package flags
var (
Config string // config file
DataDir string
Debug bool
NoPrefix bool
Dev bool
ForceBinDir bool
)

View File

@ -24,8 +24,9 @@ func Execute() {
}
func init() {
rootCmd.PersistentFlags().StringVar(&flags.Config, "conf", "data/config.json", "config file")
rootCmd.PersistentFlags().StringVar(&flags.DataDir, "data", "data", "config file")
rootCmd.PersistentFlags().BoolVar(&flags.Debug, "debug", false, "start with debug mode")
rootCmd.PersistentFlags().BoolVar(&flags.NoPrefix, "no-prefix", false, "disable env prefix")
rootCmd.PersistentFlags().BoolVar(&flags.Dev, "dev", false, "start with dev mode")
rootCmd.PersistentFlags().BoolVar(&flags.ForceBinDir, "force-bin-dir", false, "Force to use the directory where the binary file is located as data directory")
}

98
drivers/115/driver.go Normal file
View File

@ -0,0 +1,98 @@
package _115
import (
"context"
"os"
driver115 "github.com/SheltonZhu/115driver/pkg/driver"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/pkg/errors"
)
type Pan115 struct {
model.Storage
Addition
client *driver115.Pan115Client
}
func (d *Pan115) Config() driver.Config {
return config
}
func (d *Pan115) GetAddition() driver.Additional {
return d.Addition
}
func (d *Pan115) 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.login()
}
func (d *Pan115) Drop(ctx context.Context) error {
return nil
}
func (d *Pan115) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
files, err := d.getFiles(dir.GetID())
if err != nil && !errors.Is(err, driver115.ErrNotExist) {
return nil, err
}
return utils.SliceConvert(files, func(src driver115.File) (model.Obj, error) {
return src, nil
})
}
func (d *Pan115) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
downloadInfo, err := d.client.Download(file.(driver115.File).PickCode)
if err != nil {
return nil, err
}
link := &model.Link{
URL: downloadInfo.Url.Url,
Header: downloadInfo.Header,
}
return link, nil
}
func (d *Pan115) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
if _, err := d.client.Mkdir(parentDir.GetID(), dirName); err != nil {
return err
}
return nil
}
func (d *Pan115) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
return d.client.Move(dstDir.GetID(), srcObj.GetID())
}
func (d *Pan115) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
return d.client.Rename(srcObj.GetID(), newName)
}
func (d *Pan115) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
return d.client.Copy(dstDir.GetID(), srcObj.GetID())
}
func (d *Pan115) Remove(ctx context.Context, obj model.Obj) error {
return d.client.Delete(obj.GetID())
}
func (d *Pan115) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
tempFile, err := utils.CreateTempFile(stream.GetReadCloser())
if err != nil {
return err
}
defer func() {
_ = tempFile.Close()
_ = os.Remove(tempFile.Name())
}()
return d.client.UploadFastOrByMultipart(dstDir.GetID(), stream.GetName(), stream.GetSize(), tempFile)
}
var _ driver.Driver = (*Pan115)(nil)

26
drivers/115/meta.go Normal file
View File

@ -0,0 +1,26 @@
package _115
import (
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/op"
)
type Addition struct {
Cookie string `json:"cookie" required:"true"`
driver.RootID
}
var config = driver.Config{
Name: "115 Cloud",
DefaultRoot: "0",
OnlyProxy: true,
OnlyLocal: true,
}
func New() driver.Driver {
return &Pan115{}
}
func init() {
op.RegisterDriver(config, New)
}

8
drivers/115/types.go Normal file
View File

@ -0,0 +1,8 @@
package _115
import (
"github.com/SheltonZhu/115driver/pkg/driver"
"github.com/alist-org/alist/v3/internal/model"
)
var _ model.Obj = (*driver.File)(nil)

34
drivers/115/util.go Normal file
View File

@ -0,0 +1,34 @@
package _115
import (
"github.com/SheltonZhu/115driver/pkg/driver"
"github.com/alist-org/alist/v3/drivers/base"
)
func (d *Pan115) login() error {
opts := []driver.Option{
driver.WithRestyClient(base.RestyClient),
driver.UA("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 115Browser/23.9.3.2 115disk/30.1.0"),
}
d.client = driver.New(opts...)
cr := &driver.Credential{}
if err := cr.FromCookie(d.Addition.Cookie); err != nil {
return err
}
d.client.ImportCredential(cr)
return d.client.LoginCheck()
}
func (d *Pan115) getFiles(fileId string) ([]driver.File, error) {
res := make([]driver.File, 0)
files, err := d.client.List(fileId)
if err != nil {
return nil, err
}
for _, file := range *files {
res = append(res, file)
}
return res, nil
}

View File

@ -6,6 +6,7 @@ import (
"crypto/md5"
"encoding/binary"
"encoding/hex"
"encoding/base64"
"fmt"
"io"
"net/http"
@ -96,6 +97,14 @@ func (d *Pan123) Link(ctx context.Context, file model.Obj, args model.LinkArgs)
if err != nil {
return nil, err
}
nu := u.Query().Get("params")
if nu != "" {
du, _ := base64.StdEncoding.DecodeString(nu)
u, err = url.Parse(string(du))
if err != nil {
return nil, err
}
}
u_ := fmt.Sprintf("https://%s%s", u.Host, u.Path)
res, err := base.NoRedirectClient.R().SetQueryParamsFromValues(u.Query()).Head(u_)
if err != nil {

View File

@ -110,8 +110,10 @@ func ParseHttpHeader(str string) map[string]string {
header := make(map[string]string)
for _, value := range strings.Split(str, "&") {
i := strings.Index(value, "=")
if i > 0 {
header[strings.TrimSpace(value[0:i])] = strings.TrimSpace(value[i+1:])
}
}
return header
}

View File

@ -15,6 +15,7 @@ type Addition struct {
Type string `json:"type" type:"select" options:"personal,family" default:"personal"`
FamilyID string `json:"family_id"`
RapidUpload bool `json:"rapid_upload"`
NoUseOcr bool `json:"no_use_ocr"`
}
var config = driver.Config{

View File

@ -186,20 +186,19 @@ func (y *Yun189PC) getFiles(ctx context.Context, fileId string) ([]model.Obj, er
func (y *Yun189PC) login() (err error) {
// 初始化登陆所需参数
if y.loginParam == nil {
if y.loginParam == nil || !y.NoUseOcr {
if err = y.initLoginParam(); err != nil {
// 验证码也通过错误返回
return err
}
}
defer func() {
// 销毁验证码
y.VCode = ""
// 销毁登陆参数
y.loginParam = nil
// 遇到错误,重新加载登陆参数
if err != nil {
if err != nil && y.NoUseOcr {
if err1 := y.initLoginParam(); err1 != nil {
err = fmt.Errorf("err1: %s \nerr2: %s", err, err1)
}
@ -303,21 +302,8 @@ func (y *Yun189PC) initLoginParam() error {
param.jRsaKey = fmt.Sprintf("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----", encryptConf.Data.PubKey)
param.RsaUsername = encryptConf.Data.Pre + RsaEncrypt(param.jRsaKey, y.Username)
param.RsaPassword = encryptConf.Data.Pre + RsaEncrypt(param.jRsaKey, y.Password)
// 判断是否需要验证码
res, err = y.client.R().
SetFormData(map[string]string{
"appKey": APP_ID,
"accountType": ACCOUNT_TYPE,
"userName": param.RsaUsername,
}).
Post(AUTH_URL + "/api/logbox/oauth2/needcaptcha.do")
if err != nil {
return err
}
y.loginParam = &param
if res.String() != "0" {
imgRes, err := y.client.R().
SetQueryParams(map[string]string{
"token": param.CaptchaToken,
@ -328,19 +314,22 @@ func (y *Yun189PC) initLoginParam() error {
if err != nil {
return fmt.Errorf("failed to obtain verification code")
}
// 尝试使用ocr
if imgRes.Size() > 20 {
if setting.GetStr(conf.OcrApi) != "" && !y.NoUseOcr {
vRes, err := base.RestyClient.R().
SetMultipartField("image", "validateCode.png", "image/png", bytes.NewReader(imgRes.Body())).
Post(setting.GetStr(conf.OcrApi))
if err == nil && jsoniter.Get(vRes.Body(), "status").ToInt() == 200 {
if err != nil {
return err
}
if jsoniter.Get(vRes.Body(), "status").ToInt() == 200 {
y.VCode = jsoniter.Get(vRes.Body(), "result").ToString()
return nil
}
}
// ocr无法处理返回验证码图片给前端
if len(y.VCode) != 4 {
return fmt.Errorf("need validate code: data:image/png;base64,%s", base64.StdEncoding.EncodeToString(res.Body()))
}
// 返回验证码图片给前端
return fmt.Errorf(`need img validate code: <img src="data:image/png;base64,%s"/>`, base64.StdEncoding.EncodeToString(imgRes.Body()))
}
return nil
}
@ -396,6 +385,7 @@ func (y *Yun189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mode
const DEFAULT int64 = 10485760
var count = int64(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
requestID := uuid.NewString()
params := Params{
"parentFolderId": dstDir.GetID(),
"fileName": url.QueryEscape(file.GetName()),
@ -417,6 +407,7 @@ func (y *Yun189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mode
var initMultiUpload InitMultiUploadResp
_, err = y.request(fullUrl+"/initMultiUpload", http.MethodGet, func(req *resty.Request) {
req.SetContext(ctx)
req.SetHeader("X-Request-ID", requestID)
}, params, &initMultiUpload)
if err != nil {
return err
@ -451,6 +442,7 @@ func (y *Yun189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mode
_, err = y.request(fullUrl+"/getMultiUploadUrls", http.MethodGet,
func(req *resty.Request) {
req.SetContext(ctx)
req.SetHeader("X-Request-ID", requestID)
}, Params{
"partInfo": fmt.Sprintf("%d-%s", i, silceMd5Base64),
"uploadFileId": initMultiUpload.Data.UploadFileID,
@ -486,6 +478,7 @@ func (y *Yun189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mode
_, err = y.request(fullUrl+"/commitMultiUploadFile", http.MethodGet,
func(req *resty.Request) {
req.SetContext(ctx)
req.SetHeader("X-Request-ID", requestID)
}, Params{
"uploadFileId": initMultiUpload.Data.UploadFileID,
"fileMd5": fileMd5Hex,
@ -542,6 +535,7 @@ func (y *Yun189PC) FastUpload(ctx context.Context, dstDir model.Obj, file model.
sliceMd5Hex = strings.ToUpper(utils.GetMD5Encode(strings.Join(silceMd5Hexs, "\n")))
}
requestID := uuid.NewString()
// 检测是否支持快传
params := Params{
"parentFolderId": dstDir.GetID(),
@ -564,6 +558,7 @@ func (y *Yun189PC) FastUpload(ctx context.Context, dstDir model.Obj, file model.
var uploadInfo InitMultiUploadResp
_, err = y.request(fullUrl+"/initMultiUpload", http.MethodGet, func(req *resty.Request) {
req.SetContext(ctx)
req.SetHeader("X-Request-ID", requestID)
}, params, &uploadInfo)
if err != nil {
return err
@ -575,6 +570,7 @@ func (y *Yun189PC) FastUpload(ctx context.Context, dstDir model.Obj, file model.
_, err = y.request(fullUrl+"/getMultiUploadUrls", http.MethodGet,
func(req *resty.Request) {
req.SetContext(ctx)
req.SetHeader("X-Request-ID", requestID)
}, Params{
"uploadFileId": uploadInfo.Data.UploadFileID,
"partInfo": strings.Join(silceMd5Base64s, ","),
@ -611,6 +607,7 @@ func (y *Yun189PC) FastUpload(ctx context.Context, dstDir model.Obj, file model.
_, err = y.request(fullUrl+"/commitMultiUploadFile", http.MethodGet,
func(req *resty.Request) {
req.SetContext(ctx)
req.SetHeader("X-Request-ID", requestID)
}, Params{
"uploadFileId": uploadInfo.Data.UploadFileID,
"isLog": "0",

128
drivers/alist_v3/driver.go Normal file
View File

@ -0,0 +1,128 @@
package alist_v3
import (
"context"
"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/alist-org/alist/v3/server/common"
"github.com/alist-org/alist/v3/server/handles"
)
type AListV3 struct {
model.Storage
Addition
}
func (d *AListV3) Config() driver.Config {
return config
}
func (d *AListV3) GetAddition() driver.Additional {
return d.Addition
}
func (d *AListV3) 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
}
// TODO login / refresh token
//op.MustSaveDriverStorage(d)
return err
}
func (d *AListV3) Drop(ctx context.Context) error {
return nil
}
func (d *AListV3) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
url := d.Address + "/api/fs/list"
var resp common.Resp[handles.FsListResp]
_, err := base.RestyClient.R().
SetResult(&resp).
SetHeader("Authorization", d.AccessToken).
SetBody(handles.ListReq{
PageReq: common.PageReq{
Page: 1,
PerPage: 0,
},
Path: dir.GetPath(),
Password: d.Password,
Refresh: false,
}).Post(url)
if err != nil {
return nil, err
}
var files []model.Obj
for _, f := range resp.Data.Content {
file := model.ObjThumb{
Object: model.Object{
Name: f.Name,
Modified: f.Modified,
Size: f.Size,
IsFolder: f.IsDir,
},
Thumbnail: model.Thumbnail{Thumbnail: f.Thumb},
}
files = append(files, &file)
}
return files, nil
}
//func (d *AList) Get(ctx context.Context, path string) (model.Obj, error) {
// // this is optional
// return nil, errs.NotImplement
//}
func (d *AListV3) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
url := d.Address + "/api/fs/get"
var resp common.Resp[handles.FsGetResp]
_, err := base.RestyClient.R().
SetResult(&resp).
SetHeader("Authorization", d.AccessToken).
SetBody(handles.FsGetReq{
Path: file.GetPath(),
Password: d.Password,
}).Post(url)
if err != nil {
return nil, err
}
return &model.Link{
URL: resp.Data.RawURL,
}, nil
}
func (d *AListV3) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
return errs.NotImplement
}
func (d *AListV3) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
return errs.NotImplement
}
func (d *AListV3) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
return errs.NotImplement
}
func (d *AListV3) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
return errs.NotImplement
}
func (d *AListV3) Remove(ctx context.Context, obj model.Obj) error {
return errs.NotImplement
}
func (d *AListV3) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
return errs.NotImplement
}
//func (d *AList) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
// return nil, errs.NotSupport
//}
var _ driver.Driver = (*AListV3)(nil)

26
drivers/alist_v3/meta.go Normal file
View File

@ -0,0 +1,26 @@
package alist_v3
import (
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/op"
)
type Addition struct {
driver.RootPath
Address string `json:"url" required:"true"`
Password string `json:"password"`
AccessToken string `json:"access_token"`
}
var config = driver.Config{
Name: "AList V3",
LocalSort: true,
NoUpload: true,
DefaultRoot: "/",
}
func init() {
op.RegisterDriver(config, func() driver.Driver {
return &AListV3{}
})
}

View File

@ -0,0 +1 @@
package alist_v3

1
drivers/alist_v3/util.go Normal file
View File

@ -0,0 +1 @@
package alist_v3

View File

@ -1,10 +1,12 @@
package drivers
import (
_ "github.com/alist-org/alist/v3/drivers/115"
_ "github.com/alist-org/alist/v3/drivers/123"
_ "github.com/alist-org/alist/v3/drivers/139"
_ "github.com/alist-org/alist/v3/drivers/189"
_ "github.com/alist-org/alist/v3/drivers/189pc"
_ "github.com/alist-org/alist/v3/drivers/alist_v3"
_ "github.com/alist-org/alist/v3/drivers/aliyundrive"
_ "github.com/alist-org/alist/v3/drivers/aliyundrive_share"
_ "github.com/alist-org/alist/v3/drivers/baidu_netdisk"
@ -21,6 +23,7 @@ import (
_ "github.com/alist-org/alist/v3/drivers/quark"
_ "github.com/alist-org/alist/v3/drivers/s3"
_ "github.com/alist-org/alist/v3/drivers/sftp"
_ "github.com/alist-org/alist/v3/drivers/smb"
_ "github.com/alist-org/alist/v3/drivers/teambition"
_ "github.com/alist-org/alist/v3/drivers/thunder"
_ "github.com/alist-org/alist/v3/drivers/uss"

View File

@ -33,7 +33,7 @@ func fileToObj(f File) *model.ObjThumb {
ID: f.Id,
Name: f.Name,
Size: size,
Modified: time.Time{},
Modified: f.ModifiedTime,
IsFolder: f.MimeType == "application/vnd.google-apps.folder",
},
Thumbnail: model.Thumbnail{},

View File

@ -43,7 +43,7 @@ func (d *GooglePhoto) Drop(ctx context.Context) error {
}
func (d *GooglePhoto) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
files, err := d.getFiles()
files, err := d.getFiles(dir.GetID())
if err != nil {
return nil, err
}
@ -58,7 +58,7 @@ func (d *GooglePhoto) List(ctx context.Context, dir model.Obj, args model.ListAr
//}
func (d *GooglePhoto) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
f, err := d.getFile(file.GetID())
f, err := d.getMedia(file.GetID())
if err != nil {
return nil, err
}

View File

@ -10,6 +10,7 @@ type Addition struct {
RefreshToken string `json:"refresh_token" required:"true"`
ClientID string `json:"client_id" required:"true" default:"202264815644.apps.googleusercontent.com"`
ClientSecret string `json:"client_secret" required:"true" default:"X4Z3ca8xfWDb1Voo-F9a7ZxJ"`
ShowArchive bool `json:"show_archive"`
}
var config = driver.Config{

View File

@ -1,6 +1,7 @@
package google_photo
import (
"reflect"
"time"
"github.com/alist-org/alist/v3/internal/model"
@ -11,17 +12,21 @@ type TokenError struct {
ErrorDescription string `json:"error_description"`
}
type Files struct {
type Items struct {
NextPageToken string `json:"nextPageToken"`
MediaItems []MediaItem `json:"mediaItems"`
MediaItems []MediaItem `json:"mediaItems,omitempty"`
Albums []MediaItem `json:"albums,omitempty"`
SharedAlbums []MediaItem `json:"sharedAlbums,omitempty"`
}
type MediaItem struct {
Id string `json:"id"`
BaseURL string `json:"baseUrl"`
MimeType string `json:"mimeType"`
FileName string `json:"filename"`
MediaMetadata MediaMetadata `json:"mediaMetadata"`
Title string `json:"title,omitempty"`
BaseURL string `json:"baseUrl,omitempty"`
CoverPhotoBaseUrl string `json:"coverPhotoBaseUrl,omitempty"`
MimeType string `json:"mimeType,omitempty"`
FileName string `json:"filename,omitempty"`
MediaMetadata MediaMetadata `json:"mediaMetadata,omitempty"`
}
type MediaMetadata struct {
@ -39,7 +44,7 @@ type Video struct {
}
func fileToObj(f MediaItem) *model.ObjThumb {
//size, _ := strconv.ParseInt(f.Size, 10, 64)
if !reflect.DeepEqual(f.MediaMetadata, MediaMetadata{}){
return &model.ObjThumb{
Object: model.Object{
ID: f.Id,
@ -53,6 +58,17 @@ func fileToObj(f MediaItem) *model.ObjThumb {
},
}
}
return &model.ObjThumb{
Object: model.Object{
ID: f.Id,
Name: f.Title,
Size: 0,
Modified: time.Time{},
IsFolder: true,
},
Thumbnail: model.Thumbnail{},
}
}
type Error struct {
Error struct {

View File

@ -10,6 +10,13 @@ import (
// do others that not defined in Driver interface
const (
FETCH_ALL = "all"
FETCH_ALBUMS = "albums"
FETCH_ROOT = "root"
FETCH_SHARE_ALBUMS = "share_albums"
)
func (d *GooglePhoto) refreshToken() error {
url := "https://www.googleapis.com/oauth2/v4/token"
var resp base.TokenResp
@ -34,6 +41,7 @@ func (d *GooglePhoto) refreshToken() error {
func (d *GooglePhoto) request(url string, method string, callback base.ReqCallback, resp interface{}, headers map[string]string) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeader("Authorization", "Bearer "+d.AccessToken)
req.SetHeader("Accept-Encoding", "gzip")
if headers != nil {
req.SetHeaders(headers)
}
@ -63,32 +71,83 @@ func (d *GooglePhoto) request(url string, method string, callback base.ReqCallba
return res.Body(), nil
}
func (d *GooglePhoto) getFiles() ([]MediaItem, error) {
pageToken := "first"
res := make([]MediaItem, 0)
for pageToken != "" {
if pageToken == "first" {
pageToken = ""
func (d *GooglePhoto) getFiles(id string) ([]MediaItem, error) {
switch id {
case FETCH_ALL:
return d.getAllMedias()
case FETCH_ALBUMS:
return d.getAlbums()
case FETCH_SHARE_ALBUMS:
return d.getShareAlbums()
case FETCH_ROOT:
return d.getFakeRoot()
default:
return d.getMedias(id)
}
var resp Files
query := map[string]string{
"fields": "mediaItems(id,baseUrl,mimeType,mediaMetadata,filename),nextPageToken",
"pageSize": "100",
"pageToken": pageToken,
}
_, err := d.request("https://photoslibrary.googleapis.com/v1/mediaItems", http.MethodGet, func(req *resty.Request) {
req.SetQueryParams(query)
}, &resp, nil)
if err != nil {
return nil, err
}
pageToken = resp.NextPageToken
res = append(res, resp.MediaItems...)
}
return res, nil
}
func (d *GooglePhoto) getFile(id string) (MediaItem, error) {
func (d *GooglePhoto) getFakeRoot() ([]MediaItem, error) {
return []MediaItem{
{
Id: FETCH_ALL,
Title: "全部媒体",
},
{
Id: FETCH_ALBUMS,
Title: "全部影集",
},
{
Id: FETCH_SHARE_ALBUMS,
Title: "共享影集",
},
}, nil
}
func (d *GooglePhoto) getAlbums() ([]MediaItem, error) {
return d.fetchItems(
"https://photoslibrary.googleapis.com/v1/albums",
map[string]string{
"fields": "albums(id,title,coverPhotoBaseUrl),nextPageToken",
"pageSize": "50",
"pageToken": "first",
},
http.MethodGet)
}
func (d *GooglePhoto) getShareAlbums() ([]MediaItem, error) {
return d.fetchItems(
"https://photoslibrary.googleapis.com/v1/sharedAlbums",
map[string]string{
"fields": "sharedAlbums(id,title,coverPhotoBaseUrl),nextPageToken",
"pageSize": "50",
"pageToken": "first",
},
http.MethodGet)
}
func (d *GooglePhoto) getMedias(albumId string) ([]MediaItem, error) {
return d.fetchItems(
"https://photoslibrary.googleapis.com/v1/mediaItems:search",
map[string]string{
"fields": "mediaItems(id,baseUrl,mimeType,mediaMetadata,filename),nextPageToken",
"pageSize": "100",
"albumId": albumId,
"pageToken": "first",
}, http.MethodPost)
}
func (d *GooglePhoto) getAllMedias() ([]MediaItem, error) {
return d.fetchItems(
"https://photoslibrary.googleapis.com/v1/mediaItems",
map[string]string{
"fields": "mediaItems(id,baseUrl,mimeType,mediaMetadata,filename),nextPageToken",
"pageSize": "100",
"pageToken": "first",
},
http.MethodGet)
}
func (d *GooglePhoto) getMedia(id string) (MediaItem, error) {
var resp MediaItem
query := map[string]string{
@ -103,3 +162,25 @@ func (d *GooglePhoto) getFile(id string) (MediaItem, error) {
return resp, nil
}
func (d *GooglePhoto) fetchItems(url string, query map[string]string, method string) ([]MediaItem, error){
res := make([]MediaItem, 0)
for query["pageToken"] != "" {
if query["pageToken"] == "first" {
query["pageToken"] = ""
}
var resp Items
_, err := d.request(url, method, func(req *resty.Request) {
req.SetQueryParams(query)
}, &resp, nil)
if err != nil {
return nil, err
}
query["pageToken"] = resp.NextPageToken
res = append(res, resp.MediaItems...)
res = append(res, resp.Albums...)
res = append(res, resp.SharedAlbums...)
}
return res, nil
}

View File

@ -146,16 +146,16 @@ func IsNumber(str string) bool {
var findFromReg = regexp.MustCompile(`data : '(.+?)'`) // 查找from字符串
// 解析html中的from
// 解析html中的form
func htmlFormToMap(html string) (map[string]string, error) {
froms := findFromReg.FindStringSubmatch(html)
if len(froms) != 2 {
forms := findFromReg.FindStringSubmatch(html)
if len(forms) != 2 {
return nil, fmt.Errorf("not find file sgin")
}
return fromToMap(froms[1]), nil
return formToMap(forms[1]), nil
}
func fromToMap(from string) map[string]string {
func formToMap(from string) map[string]string {
var param = make(map[string]string)
for _, kv := range strings.Split(from, "&") {
kv := strings.SplitN(kv, "=", 2)[:2]

View File

@ -68,7 +68,7 @@ func (d *Local) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([
}
var files []model.Obj
for _, f := range rawFiles {
if strings.HasPrefix(f.Name(), ".") {
if !d.ShowHidden && strings.HasPrefix(f.Name(), ".") {
continue
}
thumb := ""

View File

@ -8,6 +8,7 @@ import (
type Addition struct {
driver.RootPath
Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"`
ShowHidden bool `json:"show_hidden" default:"true" required:"false" help:"show hidden directories and files"`
}
var config = driver.Config{

View File

@ -10,6 +10,7 @@ import (
"os"
"path"
"strconv"
"time"
"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/driver"
@ -91,7 +92,21 @@ func (d *MediaTrack) Link(ctx context.Context, file model.Obj, args model.LinkAr
}
token := utils.Json.Get(body, "data", "token").ToString()
url = "https://kayn.api.mediatrack.cn/v1/download/redirect?token=" + token
return &model.Link{URL: url}, nil
res, err := base.NoRedirectClient.R().Get(url)
if err != nil {
return nil, err
}
log.Debug(res.String())
link := model.Link{
URL: url,
}
log.Debugln("res code: ", res.StatusCode())
if res.StatusCode() == 302 {
link.URL = res.Header().Get("location")
expired := time.Duration(60) * time.Second
link.Expiration = &expired
}
return &link, nil
}
func (d *MediaTrack) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {

View File

@ -52,11 +52,12 @@ func getKey(path string, dir bool) string {
return path
}
// var defaultPlaceholderName = ".placeholder"
var defaultPlaceholderName = ".alist"
func getPlaceholderName(placeholder string) string {
//if placeholder == "" {
// return defaultPlaceholderName
//}
if placeholder == "" {
return defaultPlaceholderName
}
return placeholder
}
@ -88,7 +89,7 @@ func (d *S3) listV1(prefix string) ([]model.Obj, error) {
}
for _, object := range listObjectsResult.Contents {
name := path.Base(*object.Key)
if name == getPlaceholderName(d.Placeholder) {
if name == getPlaceholderName(d.Placeholder) || name == d.Placeholder {
continue
}
file := model.Object{
@ -140,7 +141,7 @@ func (d *S3) listV2(prefix string) ([]model.Obj, error) {
}
for _, object := range listObjectsResult.Contents {
name := path.Base(*object.Key)
if name == getPlaceholderName(d.Placeholder) {
if name == getPlaceholderName(d.Placeholder) || name == d.Placeholder {
continue
}
file := model.Object{
@ -222,11 +223,12 @@ func (d *S3) removeDir(ctx context.Context, src string) error {
}
}
_ = d.removeFile(path.Join(src, getPlaceholderName(d.Placeholder)))
_ = d.removeFile(path.Join(src, d.Placeholder))
return nil
}
func (d *S3) removeFile(src string) error {
key := getKey(src, true)
key := getKey(src, false)
input := &s3.DeleteObjectInput{
Bucket: &d.Bucket,
Key: &key,

205
drivers/smb/driver.go Normal file
View File

@ -0,0 +1,205 @@
package smb
import (
"context"
"errors"
"path/filepath"
"time"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/hirochachacha/go-smb2"
)
type SMB struct {
model.Storage
Addition
fs *smb2.Share
lastConnTime time.Time
}
func (d *SMB) Config() driver.Config {
return config
}
func (d *SMB) GetAddition() driver.Additional {
return d.Addition
}
func (d *SMB) 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.initFS()
}
func (d *SMB) Drop(ctx context.Context) error {
if d.fs != nil {
_ = d.fs.Umount()
}
return nil
}
func (d *SMB) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
if err := d.checkConn(); err != nil {
return nil, err
}
fullPath := d.getSMBPath(dir)
rawFiles, err := d.fs.ReadDir(fullPath)
if err != nil {
d.cleanLastConnTime()
return nil, err
}
d.updateLastConnTime()
var files []model.Obj
for _, f := range rawFiles {
file := model.ObjThumb{
Object: model.Object{
Name: f.Name(),
Modified: f.ModTime(),
Size: f.Size(),
IsFolder: f.IsDir(),
},
}
files = append(files, &file)
}
return files, nil
}
//func (d *SMB) Get(ctx context.Context, path string) (model.Obj, error) {
// // this is optional
// return nil, errs.NotImplement
//}
func (d *SMB) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
if err := d.checkConn(); err != nil {
return nil, err
}
fullPath := d.getSMBPath(file)
remoteFile, err := d.fs.Open(fullPath)
if err != nil {
d.cleanLastConnTime()
return nil, err
}
d.updateLastConnTime()
return &model.Link{
Data: remoteFile,
}, nil
}
func (d *SMB) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
if err := d.checkConn(); err != nil {
return err
}
fullPath := filepath.Join(d.getSMBPath(parentDir), dirName)
err := d.fs.MkdirAll(fullPath, 0700)
if err != nil {
d.cleanLastConnTime()
return err
}
d.updateLastConnTime()
return nil
}
func (d *SMB) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
if err := d.checkConn(); err != nil {
return err
}
srcPath := d.getSMBPath(srcObj)
dstPath := filepath.Join(d.getSMBPath(dstDir), srcObj.GetName())
err := d.fs.Rename(srcPath, dstPath)
if err != nil {
d.cleanLastConnTime()
return err
}
d.updateLastConnTime()
return nil
}
func (d *SMB) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
if err := d.checkConn(); err != nil {
return err
}
srcPath := d.getSMBPath(srcObj)
dstPath := filepath.Join(filepath.Dir(srcPath), newName)
err := d.fs.Rename(srcPath, dstPath)
if err != nil {
d.cleanLastConnTime()
return err
}
d.updateLastConnTime()
return nil
}
func (d *SMB) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
if err := d.checkConn(); err != nil {
return err
}
srcPath := d.getSMBPath(srcObj)
dstPath := filepath.Join(d.getSMBPath(dstDir), srcObj.GetName())
var err error
if srcObj.IsDir() {
err = d.CopyDir(srcPath, dstPath)
} else {
err = d.CopyFile(srcPath, dstPath)
}
if err != nil {
d.cleanLastConnTime()
return err
}
d.updateLastConnTime()
return nil
}
func (d *SMB) Remove(ctx context.Context, obj model.Obj) error {
if err := d.checkConn(); err != nil {
return err
}
var err error
fullPath := d.getSMBPath(obj)
if obj.IsDir() {
err = d.fs.RemoveAll(fullPath)
} else {
err = d.fs.Remove(fullPath)
}
if err != nil {
d.cleanLastConnTime()
return err
}
d.updateLastConnTime()
return nil
}
func (d *SMB) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
if err := d.checkConn(); err != nil {
return err
}
fullPath := filepath.Join(d.getSMBPath(dstDir), stream.GetName())
out, err := d.fs.Create(fullPath)
if err != nil {
d.cleanLastConnTime()
return err
}
d.updateLastConnTime()
defer func() {
_ = out.Close()
if errors.Is(err, context.Canceled) {
_ = d.fs.Remove(fullPath)
}
}()
err = utils.CopyWithCtx(ctx, out, stream, stream.GetSize(), up)
if err != nil {
return err
}
return nil
}
//func (d *SMB) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
// return nil, errs.NotSupport
//}
var _ driver.Driver = (*SMB)(nil)

28
drivers/smb/meta.go Normal file
View File

@ -0,0 +1,28 @@
package smb
import (
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/op"
)
type Addition struct {
driver.RootPath
Address string `json:"address" required:"true"`
Username string `json:"username" required:"true"`
Password string `json:"password"`
ShareName string `json:"share_name" required:"true"`
}
var config = driver.Config{
Name: "SMB",
LocalSort: true,
OnlyLocal: true,
DefaultRoot: ".",
NoCache: true,
}
func init() {
op.RegisterDriver(config, func() driver.Driver {
return &SMB{}
})
}

1
drivers/smb/types.go Normal file
View File

@ -0,0 +1 @@
package smb

142
drivers/smb/util.go Normal file
View File

@ -0,0 +1,142 @@
package smb
import (
"io"
"io/fs"
"net"
"os"
"path/filepath"
"time"
"github.com/alist-org/alist/v3/internal/model"
"github.com/hirochachacha/go-smb2"
)
func (d *SMB) updateLastConnTime() {
d.lastConnTime = time.Now()
}
func (d *SMB) cleanLastConnTime() {
d.lastConnTime = time.Now().AddDate(0, 0, -1)
}
func (d *SMB) initFS() error {
conn, err := net.Dial("tcp", d.Address)
if err != nil {
return err
}
dialer := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: d.Username,
Password: d.Password,
},
}
s, err := dialer.Dial(conn)
if err != nil {
return err
}
d.fs, err = s.Mount(d.ShareName)
if err != nil {
return err
}
d.updateLastConnTime()
return err
}
func (d *SMB) checkConn() error {
if time.Since(d.lastConnTime) < 5*time.Minute {
return nil
}
if d.fs != nil {
_ = d.fs.Umount()
}
return d.initFS()
}
func (d *SMB) getSMBPath(dir model.Obj) string {
fullPath := dir.GetPath()
if fullPath[0:1] != "." {
fullPath = "." + fullPath
}
return fullPath
}
// CopyFile File copies a single file from src to dst
func (d *SMB) CopyFile(src, dst string) error {
var err error
var srcfd *smb2.File
var dstfd *smb2.File
var srcinfo fs.FileInfo
if srcfd, err = d.fs.Open(src); err != nil {
return err
}
defer srcfd.Close()
if dstfd, err = d.CreateNestedFile(dst); err != nil {
return err
}
defer dstfd.Close()
if _, err = io.Copy(dstfd, srcfd); err != nil {
return err
}
if srcinfo, err = d.fs.Stat(src); err != nil {
return err
}
return d.fs.Chmod(dst, srcinfo.Mode())
}
// CopyDir Dir copies a whole directory recursively
func (d *SMB) CopyDir(src string, dst string) error {
var err error
var fds []fs.FileInfo
var srcinfo fs.FileInfo
if srcinfo, err = d.fs.Stat(src); err != nil {
return err
}
if err = d.fs.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err
}
if fds, err = d.fs.ReadDir(src); err != nil {
return err
}
for _, fd := range fds {
srcfp := filepath.Join(src, fd.Name())
dstfp := filepath.Join(dst, fd.Name())
if fd.IsDir() {
if err = d.CopyDir(srcfp, dstfp); err != nil {
return err
}
} else {
if err = d.CopyFile(srcfp, dstfp); err != nil {
return err
}
}
}
return nil
}
// Exists determine whether the file exists
func (d *SMB) Exists(name string) bool {
if _, err := d.fs.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
// CreateNestedFile create nested file
func (d *SMB) CreateNestedFile(path string) (*smb2.File, error) {
basePath := filepath.Dir(path)
if !d.Exists(basePath) {
err := d.fs.MkdirAll(basePath, 0700)
if err != nil {
return nil, err
}
}
return d.fs.Create(path)
}

View File

@ -59,13 +59,18 @@ func (x *Thunder) Init(ctx context.Context, storage model.Storage) (err error) {
"j",
"4scKJNdd7F27Hv7tbt",
},
DeviceID: "9aa5c268e7bcfc197a9ad88e2fb330e5",
DeviceID: utils.GetMD5Encode(x.Username + x.Password),
ClientID: "Xp6vsxz_7IYVw2BB",
ClientSecret: "Xp6vsy4tN9toTVdMSpomVdXpRmES",
ClientVersion: "7.51.0.8196",
PackageName: "com.xunlei.downloadprovider",
UserAgent: "ANDROID-com.xunlei.downloadprovider/7.51.0.8196 netWorkType/5G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/220200 Oauth2Client/0.9 (Linux 4_14_186-perf-gddfs8vbb238b) (JAVA 0)",
DownloadUserAgent: "Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)",
refreshCTokenCk: func(token string) {
x.CaptchaToken = token
op.MustSaveDriverStorage(x)
},
},
refreshTokenFunc: func() error {
// 通过RefreshToken刷新
@ -88,7 +93,6 @@ func (x *Thunder) Init(ctx context.Context, storage model.Storage) (err error) {
ctoekn := strings.TrimSpace(x.CaptchaToken)
if ctoekn != "" {
x.SetCaptchaToken(ctoekn)
x.CaptchaToken = ""
}
// 防止重复登录
@ -139,7 +143,12 @@ func (x *ThunderExpert) Init(ctx context.Context, storage model.Storage) (err er
Common: &Common{
client: base.NewRestyClient(),
DeviceID: x.DeviceID,
DeviceID: func() string {
if len(x.DeviceID) != 32 {
return utils.GetMD5Encode(x.DeviceID)
}
return x.DeviceID
}(),
ClientID: x.ClientID,
ClientSecret: x.ClientSecret,
ClientVersion: x.ClientVersion,
@ -147,12 +156,16 @@ func (x *ThunderExpert) Init(ctx context.Context, storage model.Storage) (err er
UserAgent: x.UserAgent,
DownloadUserAgent: x.DownloadUserAgent,
UseVideoUrl: x.UseVideoUrl,
refreshCTokenCk: func(token string) {
x.CaptchaToken = token
op.MustSaveDriverStorage(x)
},
},
}
if x.CaptchaToken != "" {
x.SetCaptchaToken(x.CaptchaToken)
x.CaptchaToken = ""
}
// 签名方法
@ -206,7 +219,6 @@ func (x *ThunderExpert) Init(ctx context.Context, storage model.Storage) (err er
// 仅修改验证码token
if x.CaptchaToken != "" {
x.SetCaptchaToken(x.CaptchaToken)
x.CaptchaToken = ""
}
x.XunLeiCommon.UserAgent = x.UserAgent
x.XunLeiCommon.DownloadUserAgent = x.DownloadUserAgent

View File

@ -53,6 +53,9 @@ type Common struct {
UserAgent string
DownloadUserAgent string
UseVideoUrl bool
// 验证码token刷新成功回调
refreshCTokenCk func(token string)
}
func (c *Common) SetCaptchaToken(captchaToken string) {
@ -125,13 +128,16 @@ func (c *Common) refreshCaptchaToken(action string, metas map[string]string) err
}
if resp.Url != "" {
return fmt.Errorf("need verify:%s", resp.Url)
return fmt.Errorf(`need verify: <a target="_blank" href="%s">Click Here</a>`, resp.Url)
}
if resp.CaptchaToken == "" {
return fmt.Errorf("empty captchaToken")
}
if c.refreshCTokenCk != nil {
c.refreshCTokenCk(resp.CaptchaToken)
}
c.SetCaptchaToken(resp.CaptchaToken)
return nil
}

View File

@ -119,7 +119,7 @@ func (ca *CookieAuth) getSPCookie(conf *SuccessResponse) (CookieResponse, error)
Jar: jar,
}
// Send the previously aquired Token as a Post parameter
// Send the previously acquired Token as a Post parameter
if _, err = client.Post(u.String(), "text/xml", strings.NewReader(conf.Succ.Token)); err != nil {
return CookieResponse{}, err
}

17
go.mod
View File

@ -3,16 +3,18 @@ module github.com/alist-org/alist/v3
go 1.19
require (
github.com/SheltonZhu/115driver v1.0.9
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a
github.com/aws/aws-sdk-go v1.44.88
github.com/caarlos0/env/v6 v6.9.3
github.com/disintegration/imaging v1.6.2
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.8.0
github.com/gin-gonic/gin v1.8.1
github.com/go-resty/resty/v2 v2.7.0
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
github.com/hirochachacha/go-smb2 v1.1.0
github.com/jlaffaye/ftp v0.0.0-20220829015825-b85cf1edccd4
github.com/json-iterator/go v1.1.12
github.com/natefinch/lumberjack v2.0.0+incompatible
@ -33,7 +35,13 @@ require (
)
require (
github.com/aead/ecdh v0.2.0 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible // indirect
github.com/andreburgaud/crypt2go v1.1.0 // indirect
github.com/bluele/gcache v0.0.2 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/gaoyb7/115drive-webdav v0.1.8 // indirect
github.com/geoffgarside/ber v1.1.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
@ -56,16 +64,19 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.13 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/orzogc/fake115uploader v0.3.3-0.20221009101310-08b764073b77 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect

45
go.sum
View File

@ -2,10 +2,20 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/SheltonZhu/115driver v1.0.9 h1:QlSgsrbmwiFB74L3z5NCsHBjAFKlwmOShGiD9qinXBc=
github.com/SheltonZhu/115driver v1.0.9/go.mod h1:Xv7lKJ3BXyc+vU5YfymXHG8e/QTopRawSHwk09K7RRw=
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a h1:RenIAa2q4H8UcS/cqmwdT1WCWIAH5aumP8m8RpbqVsE=
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a/go.mod h1:sSBbaOg90XwWKtpT56kVujF0bIeVITnPlssLclogS04=
github.com/aead/ecdh v0.2.0 h1:pYop54xVaq/CEREFEcukHRZfTdjiWvYIsZDXXrBapQQ=
github.com/aead/ecdh v0.2.0/go.mod h1:a9HHtXuSo8J1Js1MwLQx2mBhkXMT6YwUmVVEY4tTB8U=
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible h1:QoRMR0TCctLDqBCMyOu1eXdZyMw3F7uGA9qPn2J4+R8=
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andreburgaud/crypt2go v1.1.0 h1:eitZxTPY1krUsxinsng3Qvt/Ud7q/aQmmYRh8p4hyPw=
github.com/andreburgaud/crypt2go v1.1.0/go.mod h1:4qhZPzarj1dCIRmCkpdgCklwp+hBq9yEt0zPe9Ayuhc=
github.com/aws/aws-sdk-go v1.44.88 h1:9jhiZsTx9koQQsM29RTgwI0g4mfyphCdc3bkUcKrdwA=
github.com/aws/aws-sdk-go v1.44.88/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/caarlos0/env/v6 v6.9.3 h1:Tyg69hoVXDnpO5Qvpsu8EoquarbPyQb+YwExWHP8wWU=
@ -22,13 +32,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/gaoyb7/115drive-webdav v0.1.8 h1:EJt4PSmcbvBY4KUh2zSo5p6fN9LZFNkIzuKejipubVw=
github.com/gaoyb7/115drive-webdav v0.1.8/go.mod h1:BKbeY6j8SKs3+rzBFFALznGxbPmefEm3vA+dGhqgOGU=
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/gin-gonic/gin v1.8.0 h1:4WFH5yycBMA3za5Hnl425yd9ymdw1XPm4666oab+hv4=
github.com/gin-gonic/gin v1.8.0/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
@ -39,6 +53,7 @@ github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
@ -67,6 +82,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
@ -158,8 +175,9 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I=
github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
@ -171,8 +189,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
github.com/orzogc/fake115uploader v0.3.3-0.20221009101310-08b764073b77 h1:dg/EaaJLPIg4xn2kaZil7Ax3wfoxcFXaBwyOTlcz5AI=
github.com/orzogc/fake115uploader v0.3.3-0.20221009101310-08b764073b77/go.mod h1:FD9a09Vw07CSMTdT0Y7ttStOa1WZsnPBslliMw2DkeM=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -213,7 +235,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/t3rm1n4l/go-mega v0.0.0-20220725095014-c4e0c2b5debf h1:Y43S3e9P1NPs/QF4R5/SdlXj2d31540hP4Gk8VKNvDg=
github.com/t3rm1n4l/go-mega v0.0.0-20220725095014-c4e0c2b5debf/go.mod h1:c+cGNU1qi9bO7ZF4IRMYk+KaZTNiQ/gQrSbyMmGFq1Q=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@ -223,6 +246,7 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/upyun/go-sdk/v3 v3.0.3 h1:2wUkNk2fyJReMYHMvJyav050D83rYwSjN7mEPR0Pp8Q=
github.com/upyun/go-sdk/v3 v3.0.3/go.mod h1:P/SnuuwhrIgAVRd/ZpzDWqCsBAf/oHg7UggbAxyZa0E=
github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc=
github.com/winfsp/cgofuse v1.5.0 h1:MsBP7Mi/LiJf/7/F3O/7HjjR009ds6KCdqXzKpZSWxI=
github.com/winfsp/cgofuse v1.5.0/go.mod h1:h3awhoUOcn2VYVKCwDaYxSLlZwnyK+A8KaDoLUp2lbU=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
@ -238,17 +262,20 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -284,8 +311,10 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM=
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@ -297,6 +326,9 @@ 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-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -332,6 +364,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.3.4 h1:/KoBMgsUHC3bExsekDcmNYaBnfH2WNeFuXqqrqMc98Q=
gorm.io/driver/mysql v1.3.4/go.mod h1:s4Tq0KmD0yhPGHbZEwg1VPlH0vT/GBHJZorPzhcxBUE=
gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ=

View File

@ -70,6 +70,8 @@ func (m *Monitor) Update() (bool, error) {
info, err := client.TellStatus(m.tsk.ID)
if err != nil {
m.retried++
log.Errorf("failed to get status of %s, retried %d times", m.tsk.ID, m.retried)
return false, nil
}
if m.retried > 5 {
return true, errors.Errorf("failed to get status of %s, retried %d times", m.tsk.ID, m.retried)

View File

@ -12,19 +12,28 @@ import (
)
func InitConfig() {
log.Infof("reading config file: %s", flags.Config)
if !utils.Exists(flags.Config) {
if flags.ForceBinDir {
ex, err := os.Executable()
if err != nil {
utils.Log.Fatal(err)
}
exPath := filepath.Dir(ex)
flags.DataDir = filepath.Join(exPath, "data")
}
configPath := filepath.Join(flags.DataDir, "config.json")
log.Infof("reading config file: %s", configPath)
if !utils.Exists(configPath) {
log.Infof("config file not exists, creating default config file")
_, err := utils.CreateNestedFile(flags.Config)
_, err := utils.CreateNestedFile(configPath)
if err != nil {
log.Fatalf("failed to create config file: %+v", err)
}
conf.Conf = conf.DefaultConfig()
if !utils.WriteJsonToFile(flags.Config, conf.Conf) {
if !utils.WriteJsonToFile(configPath, conf.Conf) {
log.Fatalf("failed to create default config file")
}
} else {
configBytes, err := os.ReadFile(flags.Config)
configBytes, err := os.ReadFile(configPath)
if err != nil {
log.Fatalf("reading config file error: %+v", err)
}
@ -38,7 +47,7 @@ func InitConfig() {
if err != nil {
log.Fatalf("marshal config error: %+v", err)
}
err = os.WriteFile(flags.Config, confBody, 0777)
err = os.WriteFile(configPath, confBody, 0777)
if err != nil {
log.Fatalf("update config struct error: %+v", err)
}

View File

@ -17,7 +17,7 @@ func initDevData() {
Order: 0,
Driver: "Local",
Status: "",
Addition: `{"root_folder":"."}`,
Addition: `{"root_folder_path":"."}`,
})
if err != nil {
log.Fatalf("failed to create storage: %+v", err)

View File

@ -1,6 +1,8 @@
package data
import (
"os"
"github.com/alist-org/alist/v3/cmd/flags"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
@ -13,8 +15,11 @@ import (
func initUser() {
admin, err := db.GetAdmin()
adminPassword := random.String(8)
envpass := os.Getenv("ALIST_ADMIN_PASSWORD")
if flags.Dev {
adminPassword = "admin"
} else if len(envpass) > 0 {
adminPassword = envpass
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {

View File

@ -1,6 +1,9 @@
package conf
import (
"path/filepath"
"github.com/alist-org/alist/v3/cmd/flags"
"github.com/alist-org/alist/v3/pkg/utils/random"
)
@ -46,21 +49,24 @@ type Config struct {
}
func DefaultConfig() *Config {
tempDir := filepath.Join(flags.DataDir, "temp")
logPath := filepath.Join(flags.DataDir, "log/log.log")
dbPath := filepath.Join(flags.DataDir, "data.db")
return &Config{
Address: "0.0.0.0",
Port: 5244,
JwtSecret: random.String(16),
TokenExpiresIn: 48,
TempDir: "data/temp",
TempDir: tempDir,
Database: Database{
Type: "sqlite3",
Port: 0,
TablePrefix: "x_",
DBFile: "data/data.db",
DBFile: dbPath,
},
Log: LogConfig{
Enable: true,
Name: "log/log.log",
Name: logPath,
MaxSize: 10,
MaxBackups: 5,
MaxAge: 28,

View File

@ -58,8 +58,12 @@ func List(ctx context.Context, storage driver.Driver, path string, args model.Li
if err != nil {
return nil, errors.Wrapf(err, "failed to list objs")
}
if !storage.Config().NoCache && len(files) > 0 {
if !storage.Config().NoCache {
if len(files) > 0 {
listCache.Set(key, files, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
} else {
listCache.Del(key)
}
}
return files, nil
})

View File

@ -191,7 +191,7 @@ func (id *Client) PauseAll() (g string, err error)
`aria2.pauseAll()` This method is equal to calling `aria2.pause()` for every active/waiting download. This methods returns OK for success.
```
func (id *Client) PurgeDowloadResult() (g string, err error)
func (id *Client) PurgeDownloadResult() (g string, err error)
```
`aria2.purgeDownloadResult()` This method purges completed/error/removed downloads to free memory. This method returns OK.

View File

@ -28,7 +28,7 @@ type httpCaller struct {
once sync.Once
}
func newHTTPCaller(ctx context.Context, u *url.URL, timeout time.Duration, notifer Notifier) *httpCaller {
func newHTTPCaller(ctx context.Context, u *url.URL, timeout time.Duration, notifier Notifier) *httpCaller {
c := &http.Client{
Transport: &http.Transport{
MaxIdleConnsPerHost: 1,
@ -45,8 +45,8 @@ func newHTTPCaller(ctx context.Context, u *url.URL, timeout time.Duration, notif
var wg sync.WaitGroup
ctx, cancel := context.WithCancel(ctx)
h := &httpCaller{uri: u.String(), c: c, cancel: cancel, wg: &wg}
if notifer != nil {
h.setNotifier(ctx, *u, notifer)
if notifier != nil {
h.setNotifier(ctx, *u, notifier)
}
return h
}
@ -59,7 +59,7 @@ func (h *httpCaller) Close() (err error) {
return
}
func (h *httpCaller) setNotifier(ctx context.Context, u url.URL, notifer Notifier) (err error) {
func (h *httpCaller) setNotifier(ctx context.Context, u url.URL, notifier Notifier) (err error) {
u.Scheme = "ws"
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
@ -101,17 +101,17 @@ func (h *httpCaller) setNotifier(ctx context.Context, u url.URL, notifer Notifie
}
switch request.Method {
case "aria2.onDownloadStart":
notifer.OnDownloadStart(request.Params)
notifier.OnDownloadStart(request.Params)
case "aria2.onDownloadPause":
notifer.OnDownloadPause(request.Params)
notifier.OnDownloadPause(request.Params)
case "aria2.onDownloadStop":
notifer.OnDownloadStop(request.Params)
notifier.OnDownloadStop(request.Params)
case "aria2.onDownloadComplete":
notifer.OnDownloadComplete(request.Params)
notifier.OnDownloadComplete(request.Params)
case "aria2.onDownloadError":
notifer.OnDownloadError(request.Params)
notifier.OnDownloadError(request.Params)
case "aria2.onBtDownloadComplete":
notifer.OnBtDownloadComplete(request.Params)
notifier.OnBtDownloadComplete(request.Params)
default:
log.Printf("unexpected notification: %s", request.Method)
}

View File

@ -17,7 +17,7 @@ func TestJoin(t *testing.T) {
func eq(t *testing.T, expected string, s0 string, s1 string) {
s := Join(s0, s1)
if s != expected {
t.Error("For", "'"+s0+"','"+s1+"'", "expeted", "'"+expected+"'", "got", "'"+s+"'")
t.Error("For", "'"+s0+"','"+s1+"'", "expected", "'"+expected+"'", "got", "'"+s+"'")
}
}

View File

@ -88,7 +88,7 @@ func CreateNestedFile(path string) (*os.File, error) {
if !Exists(basePath) {
err := os.MkdirAll(basePath, 0700)
if err != nil {
log.Errorf("can't create foler%s", err)
log.Errorf("can't create folder, %s", err)
return nil, err
}
}

View File

@ -28,7 +28,7 @@ func ErrorResp(c *gin.Context, err error, code int, l ...bool) {
log.Errorf("%v", err)
}
}
c.JSON(200, Resp{
c.JSON(200, Resp[interface{}]{
Code: code,
Message: hidePrivacy(err.Error()),
Data: nil,
@ -40,7 +40,7 @@ func ErrorStrResp(c *gin.Context, str string, code int, l ...bool) {
if len(l) != 0 && l[0] {
log.Error(str)
}
c.JSON(200, Resp{
c.JSON(200, Resp[interface{}]{
Code: code,
Message: hidePrivacy(str),
Data: nil,
@ -50,14 +50,14 @@ func ErrorStrResp(c *gin.Context, str string, code int, l ...bool) {
func SuccessResp(c *gin.Context, data ...interface{}) {
if len(data) == 0 {
c.JSON(200, Resp{
c.JSON(200, Resp[interface{}]{
Code: 200,
Message: "success",
Data: nil,
})
return
}
c.JSON(200, Resp{
c.JSON(200, Resp[interface{}]{
Code: 200,
Message: "success",
Data: data[0],

View File

@ -1,9 +1,9 @@
package common
type Resp struct {
type Resp[T any] struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
Data T `json:"data"`
}
type PageResp struct {

View File

@ -36,6 +36,7 @@ func Down(c *gin.Context) {
common.ErrorResp(c, err, 500)
return
}
c.Header("Referrer-Policy", "no-referrer")
c.Redirect(302, link.URL)
}
}

View File

@ -10,15 +10,18 @@ import (
"github.com/alist-org/alist/v3/cmd/flags"
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/setting"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/alist-org/alist/v3/public"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func InitIndex() {
index, err := public.Public.ReadFile("dist/index.html")
if err != nil {
log.Fatalf("failed to read index.html: %v", err)
if err == fs.ErrNotExist {
utils.Log.Fatalf("index.html not exist, you may forget to put dist of frontend to public/dist")
}
utils.Log.Fatalf("failed to read index.html: %v", err)
}
conf.RawIndexHtml = string(index)
siteConfig := getSiteConfig()
@ -65,7 +68,7 @@ func Static(r *gin.Engine) {
folder = "dist/" + folder
sub, err := fs.Sub(public.Public, folder)
if err != nil {
log.Fatalf("can't find folder: %s", folder)
utils.Log.Fatalf("can't find folder: %s", folder)
}
r.StaticFS(fmt.Sprintf("/%s/", folders[i]), http.FS(sub))
}