Compare commits
28 Commits
renovate/g
...
renovate/g
Author | SHA1 | Date | |
---|---|---|---|
6b420fefe0 | |||
6106a2d4cc | |||
b6451451b1 | |||
f06d2c0348 | |||
b7ae56b109 | |||
5d9167d676 | |||
1b42b9627c | |||
bb58b94a10 | |||
ffce61d227 | |||
0310b70d90 | |||
73f0b135b6 | |||
8316f81e41 | |||
cdbfda8921 | |||
9667832b32 | |||
b36d38f63f | |||
c8317250c1 | |||
0242f36e1c | |||
40a68bcee6 | |||
92713ef5c4 | |||
716d33fddd | |||
c9fa3d7cd6 | |||
4874c9e43b | |||
34ada81582 | |||
ba716ae325 | |||
d4f9c4b6af | |||
b910b8917f | |||
d92744e673 | |||
868b0ec25c |
34
.github/workflows/beta_release.yml
vendored
34
.github/workflows/beta_release.yml
vendored
@ -22,6 +22,17 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create or update ref
|
||||
id: create-or-update-ref
|
||||
uses: ovsds/create-or-update-ref-action@v1
|
||||
with:
|
||||
ref: tags/beta
|
||||
sha: ${{ github.sha }}
|
||||
|
||||
- name: Delete beta tag
|
||||
run: git tag -d beta
|
||||
continue-on-error: true
|
||||
|
||||
- name: changelog # or changelogithub@0.12 if ensure the stable result
|
||||
id: changelog
|
||||
run: |
|
||||
@ -29,7 +40,6 @@ jobs:
|
||||
npx changelogithub --output CHANGELOG.md
|
||||
# npx changelogen@latest --output CHANGELOG.md
|
||||
|
||||
|
||||
- name: Upload assets
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
@ -46,8 +56,10 @@ jobs:
|
||||
include:
|
||||
- target: '!(*musl*|*windows-arm64*|*android*)' # xgo
|
||||
hash: "md5"
|
||||
- target: 'linux-*-musl*' #musl
|
||||
- target: 'linux-!(arm*)-musl*' #musl-not-arm
|
||||
hash: "md5-linux-musl"
|
||||
- target: 'linux-arm*-musl*' #musl-arm
|
||||
hash: "md5-linux-musl-arm"
|
||||
- target: 'windows-arm64' #win-arm64
|
||||
hash: "md5-windows-arm64"
|
||||
- target: 'android-*' #android
|
||||
@ -86,3 +98,21 @@ jobs:
|
||||
files: build/compress/*
|
||||
prerelease: true
|
||||
tag_name: beta
|
||||
|
||||
desktop:
|
||||
needs:
|
||||
- release
|
||||
name: Beta Release Desktop
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
issue-number: 69
|
||||
body: |
|
||||
/release-beta
|
||||
- triggered by @${{ github.actor }}
|
||||
- commit sha: ${{ github.sha }}
|
||||
- view files: https://github.com/alist-org/alist/tree/${{ github.sha }}
|
||||
reactions: 'rocket'
|
||||
token: ${{ secrets.MY_TOKEN }}
|
||||
repository: alist-org/desktop-release
|
4
.github/workflows/changelog.yml
vendored
4
.github/workflows/changelog.yml
vendored
@ -15,6 +15,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Delete beta tag
|
||||
run: git tag -d beta
|
||||
continue-on-error: true
|
||||
|
||||
- run: npx changelogithub # or changelogithub@0.12 if ensure the stable result
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.MY_TOKEN}}
|
||||
|
@ -117,7 +117,7 @@ https://alist.nn.ci/guide/sponsor.html
|
||||
|
||||
- [VidHub](https://apps.apple.com/app/apple-store/id1659622164?pt=118612019&ct=alist&mt=8) - An elegant cloud video player within the Apple ecosystem. Support for iPhone, iPad, Mac, and Apple TV.
|
||||
- [亚洲云](https://www.asiayun.com/aff/QQCOOQKZ) - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商 (sponsored Chinese API server)
|
||||
- [找资源](https://zhaoziyuan.pw/) - 阿里云盘资源搜索引擎
|
||||
- [找资源](http://zhaoziyuan2.cc/) - 阿里云盘资源搜索引擎
|
||||
|
||||
## Contributors
|
||||
|
||||
|
@ -115,7 +115,7 @@ AList 是一个开源软件,如果你碰巧喜欢这个项目,并希望我
|
||||
|
||||
- [VidHub](https://apps.apple.com/app/apple-store/id1659622164?pt=118612019&ct=alist&mt=8) - 苹果生态下优雅的网盘视频播放器,iPhone,iPad,Mac,Apple TV全平台支持。
|
||||
- [亚洲云](https://www.asiayun.com/aff/QQCOOQKZ) - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商 (国内API服务器赞助)
|
||||
- [找资源](https://zhaoziyuan.pw/) - 阿里云盘资源搜索引擎
|
||||
- [找资源](http://zhaoziyuan2.cc/) - 阿里云盘资源搜索引擎
|
||||
|
||||
## 贡献者
|
||||
|
||||
|
@ -117,7 +117,7 @@ https://alist.nn.ci/guide/sponsor.html
|
||||
|
||||
- [VidHub](https://apps.apple.com/app/apple-store/id1659622164?pt=118612019&ct=alist&mt=8) - An elegant cloud video player within the Apple ecosystem. Support for iPhone, iPad, Mac, and Apple TV.
|
||||
- [亚洲云](https://www.asiayun.com/aff/QQCOOQKZ) - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商 (sponsored Chinese API server)
|
||||
- [找资源](https://zhaoziyuan.pw/) - 阿里云盘资源搜索引擎
|
||||
- [找资源](http://zhaoziyuan2.cc/) - 阿里云盘资源搜索引擎
|
||||
|
||||
## コントリビューター
|
||||
|
||||
|
1
build.sh
1
build.sh
@ -8,6 +8,7 @@ if [ "$1" = "dev" ]; then
|
||||
version="dev"
|
||||
webVersion="dev"
|
||||
else
|
||||
git tag -d beta
|
||||
version=$(git describe --abbrev=0 --tags)
|
||||
webVersion=$(wget -qO- -t1 -T2 "https://api.github.com/repos/alist-org/alist-web/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
||||
fi
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var UserAgent = driver115.UA115Desktop
|
||||
var UserAgent = driver115.UA115Browser
|
||||
|
||||
func (d *Pan115) login() error {
|
||||
var err error
|
||||
@ -74,9 +74,23 @@ func (d *Pan115) getFiles(fileId string) ([]FileObj, error) {
|
||||
}
|
||||
|
||||
const (
|
||||
appVer = "2.0.3.6"
|
||||
appVer = "27.0.3.7"
|
||||
)
|
||||
|
||||
func (c *Pan115) getAppVer() string {
|
||||
// todo add some cache?
|
||||
vers, err := c.client.GetAppVersion()
|
||||
if err != nil {
|
||||
return appVer
|
||||
}
|
||||
for _, ver := range vers {
|
||||
if ver.AppName == "win" {
|
||||
return ver.Version
|
||||
}
|
||||
}
|
||||
return appVer
|
||||
}
|
||||
|
||||
func (c *Pan115) DownloadWithUA(pickCode, ua string) (*driver115.DownloadInfo, error) {
|
||||
key := crypto.GenerateKey()
|
||||
result := driver115.DownloadResp{}
|
||||
@ -151,7 +165,7 @@ func (d *Pan115) rapidUpload(fileSize int64, fileName, dirID, preID, fileID stri
|
||||
userID := strconv.FormatInt(d.client.UserID, 10)
|
||||
form := url.Values{}
|
||||
form.Set("appid", "0")
|
||||
form.Set("appversion", appVer)
|
||||
form.Set("appversion", d.getAppVer())
|
||||
form.Set("userid", userID)
|
||||
form.Set("filename", fileName)
|
||||
form.Set("filesize", fileSizeStr)
|
||||
@ -161,7 +175,7 @@ func (d *Pan115) rapidUpload(fileSize int64, fileName, dirID, preID, fileID stri
|
||||
|
||||
signKey, signVal := "", ""
|
||||
for retry := true; retry; {
|
||||
t := driver115.Now()
|
||||
t := driver115.NowMilli()
|
||||
|
||||
if encodedToken, err = ecdhCipher.EncodeToken(t.ToInt64()); err != nil {
|
||||
return nil, err
|
||||
@ -225,6 +239,9 @@ func UploadDigestRange(stream model.FileStreamer, rangeSpec string) (result stri
|
||||
|
||||
length := end - start + 1
|
||||
reader, err := stream.RangeRead(http_range.Range{Start: start, Length: length})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
hashStr, err := utils.HashReader(utils.SHA1, reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -137,13 +137,19 @@ func (d *BaiduPhoto) Link(ctx context.Context, file model.Obj, args model.LinkAr
|
||||
case *File:
|
||||
return d.linkFile(ctx, file, args)
|
||||
case *AlbumFile:
|
||||
f, err := d.CopyAlbumFile(ctx, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.linkFile(ctx, f, args)
|
||||
// 处理共享相册
|
||||
if d.Uk != file.Uk {
|
||||
// 有概率无法获取到链接
|
||||
//return d.linkAlbum(ctx, file, args)
|
||||
return d.linkAlbum(ctx, file, args)
|
||||
|
||||
// 接口被限制,只能使用cookie
|
||||
// f, err := d.CopyAlbumFile(ctx, file)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return d.linkFile(ctx, f, args)
|
||||
}
|
||||
return d.linkFile(ctx, &file.File, args)
|
||||
}
|
||||
return nil, errs.NotFile
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ const (
|
||||
FILE_API_URL_V2 = API_URL + "/file/v2"
|
||||
)
|
||||
|
||||
func (d *BaiduPhoto) Request(furl string, method string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
||||
req := base.RestyClient.R().
|
||||
func (d *BaiduPhoto) Request(client *resty.Client, furl string, method string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
||||
req := client.R().
|
||||
SetQueryParam("access_token", d.AccessToken)
|
||||
if callback != nil {
|
||||
callback(req)
|
||||
@ -88,11 +88,11 @@ func (d *BaiduPhoto) refreshToken() error {
|
||||
}
|
||||
|
||||
func (d *BaiduPhoto) Get(furl string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
||||
return d.Request(furl, http.MethodGet, callback, resp)
|
||||
return d.Request(base.RestyClient, furl, http.MethodGet, callback, resp)
|
||||
}
|
||||
|
||||
func (d *BaiduPhoto) Post(furl string, callback base.ReqCallback, resp interface{}) (*resty.Response, error) {
|
||||
return d.Request(furl, http.MethodPost, callback, resp)
|
||||
return d.Request(base.RestyClient, furl, http.MethodPost, callback, resp)
|
||||
}
|
||||
|
||||
// 获取所有文件
|
||||
@ -338,24 +338,33 @@ func (d *BaiduPhoto) linkAlbum(ctx context.Context, file *AlbumFile, args model.
|
||||
headers["X-Forwarded-For"] = args.IP
|
||||
}
|
||||
|
||||
res, err := base.NoRedirectClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeaders(headers).
|
||||
SetQueryParams(map[string]string{
|
||||
"access_token": d.AccessToken,
|
||||
resp, err := d.Request(base.NoRedirectClient, ALBUM_API_URL+"/download", http.MethodHead, func(r *resty.Request) {
|
||||
r.SetContext(ctx)
|
||||
r.SetHeaders(headers)
|
||||
r.SetQueryParams(map[string]string{
|
||||
"fsid": fmt.Sprint(file.Fsid),
|
||||
"album_id": file.AlbumID,
|
||||
"tid": fmt.Sprint(file.Tid),
|
||||
"uk": fmt.Sprint(file.Uk),
|
||||
}).
|
||||
Head(ALBUM_API_URL + "/download")
|
||||
})
|
||||
}, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != 302 {
|
||||
return nil, fmt.Errorf("not found 302 redirect")
|
||||
}
|
||||
|
||||
location := resp.Header().Get("Location")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
link := &model.Link{
|
||||
URL: res.Header().Get("location"),
|
||||
URL: location,
|
||||
Header: http.Header{
|
||||
"User-Agent": []string{headers["User-Agent"]},
|
||||
"Referer": []string{"https://photo.baidu.com/"},
|
||||
@ -375,22 +384,36 @@ func (d *BaiduPhoto) linkFile(ctx context.Context, file *File, args model.LinkAr
|
||||
headers["X-Forwarded-For"] = args.IP
|
||||
}
|
||||
|
||||
var downloadUrl struct {
|
||||
Dlink string `json:"dlink"`
|
||||
}
|
||||
_, err := d.Get(FILE_API_URL_V2+"/download", func(r *resty.Request) {
|
||||
// var downloadUrl struct {
|
||||
// Dlink string `json:"dlink"`
|
||||
// }
|
||||
// _, err := d.Get(FILE_API_URL_V1+"/download", func(r *resty.Request) {
|
||||
// r.SetContext(ctx)
|
||||
// r.SetHeaders(headers)
|
||||
// r.SetQueryParams(map[string]string{
|
||||
// "fsid": fmt.Sprint(file.Fsid),
|
||||
// })
|
||||
// }, &downloadUrl)
|
||||
|
||||
resp, err := d.Request(base.NoRedirectClient, FILE_API_URL_V1+"/download", http.MethodHead, func(r *resty.Request) {
|
||||
r.SetContext(ctx)
|
||||
r.SetHeaders(headers)
|
||||
r.SetQueryParams(map[string]string{
|
||||
"fsid": fmt.Sprint(file.Fsid),
|
||||
})
|
||||
}, &downloadUrl)
|
||||
}, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != 302 {
|
||||
return nil, fmt.Errorf("not found 302 redirect")
|
||||
}
|
||||
|
||||
location := resp.Header().Get("Location")
|
||||
link := &model.Link{
|
||||
URL: downloadUrl.Dlink,
|
||||
URL: location,
|
||||
Header: http.Header{
|
||||
"User-Agent": []string{headers["User-Agent"]},
|
||||
"Referer": []string{"https://photo.baidu.com/"},
|
||||
|
@ -58,34 +58,10 @@ func (d *GooglePhoto) Link(ctx context.Context, file model.Obj, args model.LinkA
|
||||
URL: f.BaseURL + "=d",
|
||||
}, nil
|
||||
} else if strings.Contains(f.MimeType, "video/") {
|
||||
var width, height int
|
||||
|
||||
fmt.Sscanf(f.MediaMetadata.Width, "%d", &width)
|
||||
fmt.Sscanf(f.MediaMetadata.Height, "%d", &height)
|
||||
|
||||
switch {
|
||||
// 1080P
|
||||
case width == 1920 && height == 1080:
|
||||
return &model.Link{
|
||||
URL: f.BaseURL + "=m37",
|
||||
}, nil
|
||||
// 720P
|
||||
case width == 1280 && height == 720:
|
||||
return &model.Link{
|
||||
URL: f.BaseURL + "=m22",
|
||||
}, nil
|
||||
// 360P
|
||||
case width == 640 && height == 360:
|
||||
return &model.Link{
|
||||
URL: f.BaseURL + "=m18",
|
||||
}, nil
|
||||
default:
|
||||
return &model.Link{
|
||||
URL: f.BaseURL + "=dv",
|
||||
}, nil
|
||||
}
|
||||
|
||||
}
|
||||
return &model.Link{}, nil
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,10 @@ type Local struct {
|
||||
model.Storage
|
||||
Addition
|
||||
mkdirPerm int32
|
||||
|
||||
// zero means no limit
|
||||
thumbConcurrency int
|
||||
thumbTokenBucket TokenBucket
|
||||
}
|
||||
|
||||
func (d *Local) Config() driver.Config {
|
||||
@ -62,6 +66,18 @@ func (d *Local) Init(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if d.ThumbConcurrency != "" {
|
||||
v, err := strconv.ParseUint(d.ThumbConcurrency, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.thumbConcurrency = int(v)
|
||||
}
|
||||
if d.thumbConcurrency == 0 {
|
||||
d.thumbTokenBucket = NewNopTokenBucket()
|
||||
} else {
|
||||
d.thumbTokenBucket = NewStaticTokenBucket(d.thumbConcurrency)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -126,7 +142,6 @@ func (d *Local) FileInfoToObj(f fs.FileInfo, reqPath string, fullPath string) mo
|
||||
},
|
||||
}
|
||||
return &file
|
||||
|
||||
}
|
||||
func (d *Local) GetMeta(ctx context.Context, path string) (model.Obj, error) {
|
||||
f, err := os.Stat(path)
|
||||
@ -178,7 +193,13 @@ func (d *Local) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (
|
||||
fullPath := file.GetPath()
|
||||
var link model.Link
|
||||
if args.Type == "thumb" && utils.Ext(file.GetName()) != "svg" {
|
||||
buf, thumbPath, err := d.getThumb(file)
|
||||
var buf *bytes.Buffer
|
||||
var thumbPath *string
|
||||
err := d.thumbTokenBucket.Do(ctx, func() error {
|
||||
var err error
|
||||
buf, thumbPath, err = d.getThumb(file)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ type Addition struct {
|
||||
driver.RootPath
|
||||
Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"`
|
||||
ThumbCacheFolder string `json:"thumb_cache_folder"`
|
||||
ThumbConcurrency string `json:"thumb_concurrency" default:"16" required:"false" help:"Number of concurrent thumbnail generation goroutines. This controls how many thumbnails can be generated in parallel."`
|
||||
ShowHidden bool `json:"show_hidden" default:"true" required:"false" help:"show hidden directories and files"`
|
||||
MkdirPerm string `json:"mkdir_perm" default:"777"`
|
||||
RecycleBinPath string `json:"recycle_bin_path" default:"delete permanently" help:"path to recycle bin, delete permanently if empty or keep 'delete permanently'"`
|
||||
|
61
drivers/local/token_bucket.go
Normal file
61
drivers/local/token_bucket.go
Normal file
@ -0,0 +1,61 @@
|
||||
package local
|
||||
|
||||
import "context"
|
||||
|
||||
type TokenBucket interface {
|
||||
Take() <-chan struct{}
|
||||
Put()
|
||||
Do(context.Context, func() error) error
|
||||
}
|
||||
|
||||
// StaticTokenBucket is a bucket with a fixed number of tokens,
|
||||
// where the retrieval and return of tokens are manually controlled.
|
||||
// In the initial state, the bucket is full.
|
||||
type StaticTokenBucket struct {
|
||||
bucket chan struct{}
|
||||
}
|
||||
|
||||
func NewStaticTokenBucket(size int) StaticTokenBucket {
|
||||
bucket := make(chan struct{}, size)
|
||||
for range size {
|
||||
bucket <- struct{}{}
|
||||
}
|
||||
return StaticTokenBucket{bucket: bucket}
|
||||
}
|
||||
|
||||
func (b StaticTokenBucket) Take() <-chan struct{} {
|
||||
return b.bucket
|
||||
}
|
||||
|
||||
func (b StaticTokenBucket) Put() {
|
||||
b.bucket <- struct{}{}
|
||||
}
|
||||
|
||||
func (b StaticTokenBucket) Do(ctx context.Context, f func() error) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-b.bucket:
|
||||
defer b.Put()
|
||||
}
|
||||
return f()
|
||||
}
|
||||
|
||||
// NopTokenBucket all function calls to this bucket will success immediately
|
||||
type NopTokenBucket struct {
|
||||
nop chan struct{}
|
||||
}
|
||||
|
||||
func NewNopTokenBucket() NopTokenBucket {
|
||||
nop := make(chan struct{})
|
||||
close(nop)
|
||||
return NopTokenBucket{nop}
|
||||
}
|
||||
|
||||
func (b NopTokenBucket) Take() <-chan struct{} {
|
||||
return b.nop
|
||||
}
|
||||
|
||||
func (b NopTokenBucket) Put() {}
|
||||
|
||||
func (b NopTokenBucket) Do(_ context.Context, f func() error) error { return f() }
|
@ -36,12 +36,12 @@ func isSymlinkDir(f fs.FileInfo, path string) bool {
|
||||
|
||||
func GetSnapshot(videoPath string, frameNum int) (imgData *bytes.Buffer, err error) {
|
||||
srcBuf := bytes.NewBuffer(nil)
|
||||
err = ffmpeg.Input(videoPath).Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frameNum)}).
|
||||
stream := ffmpeg.Input(videoPath).
|
||||
Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frameNum)}).
|
||||
Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
|
||||
WithOutput(srcBuf, os.Stdout).
|
||||
Run()
|
||||
|
||||
if err != nil {
|
||||
GlobalArgs("-loglevel", "error").Silent(true).
|
||||
WithOutput(srcBuf, os.Stdout)
|
||||
if err = stream.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return srcBuf, nil
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@ -48,6 +49,7 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
||||
d.Common.CaptchaToken = token
|
||||
op.MustSaveDriverStorage(d)
|
||||
},
|
||||
LowLatencyAddr: "",
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +67,13 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
||||
d.PackageName = WebPackageName
|
||||
d.Algorithms = WebAlgorithms
|
||||
d.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
|
||||
} else if d.Platform == "pc" {
|
||||
d.ClientID = PCClientID
|
||||
d.ClientSecret = PCClientSecret
|
||||
d.ClientVersion = PCClientVersion
|
||||
d.PackageName = PCPackageName
|
||||
d.Algorithms = PCAlgorithms
|
||||
d.UserAgent = "MainWindow Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) PikPak/2.5.6.4831 Chrome/100.0.4896.160 Electron/18.3.15 Safari/537.36"
|
||||
}
|
||||
|
||||
if d.Addition.CaptchaToken != "" && d.Addition.RefreshToken == "" {
|
||||
@ -90,43 +99,36 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
||||
|
||||
// 如果已经有RefreshToken,直接获取AccessToken
|
||||
if d.Addition.RefreshToken != "" {
|
||||
if d.RefreshTokenMethod == "oauth2" {
|
||||
// 使用 oauth2 刷新令牌
|
||||
// 初始化 oauth2Token
|
||||
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
|
||||
return oauth2Config.TokenSource(ctx, &oauth2.Token{
|
||||
RefreshToken: d.Addition.RefreshToken,
|
||||
}).Token()
|
||||
}))
|
||||
d.initializeOAuth2Token(ctx, oauth2Config, d.Addition.RefreshToken)
|
||||
if err := d.refreshTokenByOAuth2(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := d.refreshToken(d.Addition.RefreshToken); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 如果没有填写RefreshToken,尝试登录 获取 refreshToken
|
||||
if err := d.login(); err != nil {
|
||||
return err
|
||||
}
|
||||
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
|
||||
return oauth2Config.TokenSource(ctx, &oauth2.Token{
|
||||
RefreshToken: d.RefreshToken,
|
||||
}).Token()
|
||||
}))
|
||||
if d.RefreshTokenMethod == "oauth2" {
|
||||
d.initializeOAuth2Token(ctx, oauth2Config, d.RefreshToken)
|
||||
}
|
||||
|
||||
token, err := d.oauth2Token.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.RefreshToken = token.RefreshToken
|
||||
d.AccessToken = token.AccessToken
|
||||
|
||||
// 获取CaptchaToken
|
||||
err = d.RefreshCaptchaTokenAtLogin(GetAction(http.MethodGet, "https://api-drive.mypikpak.com/drive/v1/files"), d.Username)
|
||||
err = d.RefreshCaptchaTokenAtLogin(GetAction(http.MethodGet, "https://api-drive.mypikpak.com/drive/v1/files"), d.Common.GetUserID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取用户ID
|
||||
userID := token.Extra("sub").(string)
|
||||
if userID != "" {
|
||||
d.Common.SetUserID(userID)
|
||||
}
|
||||
// 更新UserAgent
|
||||
if d.Platform == "android" {
|
||||
d.Common.UserAgent = BuildCustomUserAgent(utils.GetMD5EncodeStr(d.Username+d.Password), AndroidClientID, AndroidPackageName, AndroidSdkVersion, AndroidClientVersion, AndroidPackageName, d.Common.UserID)
|
||||
@ -135,6 +137,15 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
||||
// 保存 有效的 RefreshToken
|
||||
d.Addition.RefreshToken = d.RefreshToken
|
||||
op.MustSaveDriverStorage(d)
|
||||
|
||||
if d.UseLowLatencyAddress && d.Addition.CustomLowLatencyAddress != "" {
|
||||
d.Common.LowLatencyAddr = d.Addition.CustomLowLatencyAddress
|
||||
} else if d.UseLowLatencyAddress {
|
||||
d.Common.LowLatencyAddr = findLowestLatencyAddress(DlAddr)
|
||||
d.Addition.CustomLowLatencyAddress = d.Common.LowLatencyAddr
|
||||
op.MustSaveDriverStorage(d)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -154,6 +165,7 @@ func (d *PikPak) List(ctx context.Context, dir model.Obj, args model.ListArgs) (
|
||||
|
||||
func (d *PikPak) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||
var resp File
|
||||
var url string
|
||||
queryParams := map[string]string{
|
||||
"_magic": "2021",
|
||||
"usage": "FETCH",
|
||||
@ -169,14 +181,22 @@ func (d *PikPak) Link(ctx context.Context, file model.Obj, args model.LinkArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
link := model.Link{
|
||||
URL: resp.WebContentLink,
|
||||
}
|
||||
url = resp.WebContentLink
|
||||
|
||||
if !d.DisableMediaLink && len(resp.Medias) > 0 && resp.Medias[0].Link.Url != "" {
|
||||
log.Debugln("use media link")
|
||||
link.URL = resp.Medias[0].Link.Url
|
||||
url = resp.Medias[0].Link.Url
|
||||
}
|
||||
return &link, nil
|
||||
|
||||
if d.UseLowLatencyAddress && d.Common.LowLatencyAddr != "" {
|
||||
// 替换为加速链接
|
||||
re := regexp.MustCompile(`https://[^/]+/download/`)
|
||||
url = re.ReplaceAllString(url, "https://"+d.Common.LowLatencyAddr+"/download/")
|
||||
}
|
||||
|
||||
return &model.Link{
|
||||
URL: url,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *PikPak) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
||||
|
@ -9,11 +9,14 @@ type Addition struct {
|
||||
driver.RootID
|
||||
Username string `json:"username" required:"true"`
|
||||
Password string `json:"password" required:"true"`
|
||||
Platform string `json:"platform" required:"true" type:"select" options:"android,web"`
|
||||
Platform string `json:"platform" required:"true" type:"select" options:"android,web,pc"`
|
||||
RefreshToken string `json:"refresh_token" required:"true" default:""`
|
||||
RefreshTokenMethod string `json:"refresh_token_method" required:"true" type:"select" options:"oauth2,http"`
|
||||
CaptchaToken string `json:"captcha_token" default:""`
|
||||
DeviceID string `json:"device_id" required:"false" default:""`
|
||||
DisableMediaLink bool `json:"disable_media_link" default:"true"`
|
||||
UseLowLatencyAddress bool `json:"use_low_latency_address" default:"false"`
|
||||
CustomLowLatencyAddress string `json:"custom_low_latency_address" default:""`
|
||||
}
|
||||
|
||||
var config = driver.Config{
|
||||
|
@ -2,6 +2,7 @@ package pikpak
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
@ -13,6 +14,7 @@ import (
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/oauth2"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
@ -28,21 +30,14 @@ import (
|
||||
// do others that not defined in Driver interface
|
||||
|
||||
var AndroidAlgorithms = []string{
|
||||
"Gez0T9ijiI9WCeTsKSg3SMlx",
|
||||
"zQdbalsolyb1R/",
|
||||
"ftOjr52zt51JD68C3s",
|
||||
"yeOBMH0JkbQdEFNNwQ0RI9T3wU/v",
|
||||
"BRJrQZiTQ65WtMvwO",
|
||||
"je8fqxKPdQVJiy1DM6Bc9Nb1",
|
||||
"niV",
|
||||
"9hFCW2R1",
|
||||
"sHKHpe2i96",
|
||||
"p7c5E6AcXQ/IJUuAEC9W6",
|
||||
"",
|
||||
"aRv9hjc9P+Pbn+u3krN6",
|
||||
"BzStcgE8qVdqjEH16l4",
|
||||
"SqgeZvL5j9zoHP95xWHt",
|
||||
"zVof5yaJkPe3VFpadPof",
|
||||
"aDhgaSE3MsjROCmpmsWqP1sJdFJ",
|
||||
"+oaVkqdd8MJuKT+uMr2AYKcd9tdWge3XPEPR2hcePUknd",
|
||||
"u/sd2GgT2fTytRcKzGicHodhvIltMntA3xKw2SRv7S48OdnaQIS5mn",
|
||||
"2WZiae2QuqTOxBKaaqCNHCW3olu2UImelkDzBn",
|
||||
"/vJ3upic39lgmrkX855Qx",
|
||||
"yNc9ruCVMV7pGV7XvFeuLMOcy1",
|
||||
"4FPq8mT3JQ1jzcVxMVfwFftLQm33M7i",
|
||||
"xozoy5e3Ea",
|
||||
}
|
||||
|
||||
var WebAlgorithms = []string{
|
||||
@ -63,6 +58,19 @@ var WebAlgorithms = []string{
|
||||
"NhXXU9rg4XXdzo7u5o",
|
||||
}
|
||||
|
||||
var PCAlgorithms = []string{
|
||||
"KHBJ07an7ROXDoK7Db",
|
||||
"G6n399rSWkl7WcQmw5rpQInurc1DkLmLJqE",
|
||||
"JZD1A3M4x+jBFN62hkr7VDhkkZxb9g3rWqRZqFAAb",
|
||||
"fQnw/AmSlbbI91Ik15gpddGgyU7U",
|
||||
"/Dv9JdPYSj3sHiWjouR95NTQff",
|
||||
"yGx2zuTjbWENZqecNI+edrQgqmZKP",
|
||||
"ljrbSzdHLwbqcRn",
|
||||
"lSHAsqCkGDGxQqqwrVu",
|
||||
"TsWXI81fD1",
|
||||
"vk7hBjawK/rOSrSWajtbMk95nfgf3",
|
||||
}
|
||||
|
||||
const (
|
||||
OSSUserAgent = "aliyun-sdk-android/2.9.13(Linux/Android 14/M2004j7ac;UKQ1.231108.001)"
|
||||
OssSecurityTokenHeaderName = "X-OSS-Security-Token"
|
||||
@ -72,17 +80,65 @@ const (
|
||||
const (
|
||||
AndroidClientID = "YNxT9w7GMdWvEOKa"
|
||||
AndroidClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||
AndroidClientVersion = "1.47.1"
|
||||
AndroidClientVersion = "1.48.3"
|
||||
AndroidPackageName = "com.pikcloud.pikpak"
|
||||
AndroidSdkVersion = "2.0.4.204000"
|
||||
AndroidSdkVersion = "2.0.4.204101"
|
||||
WebClientID = "YUMx5nI8ZU8Ap8pm"
|
||||
WebClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||
WebClientVersion = "2.0.0"
|
||||
WebPackageName = "mypikpak.com"
|
||||
WebSdkVersion = "8.0.3"
|
||||
PCClientID = "YvtoWO6GNHiuCl7x"
|
||||
PCClientSecret = "1NIH5R1IEe2pAxZE3hv3uA"
|
||||
PCClientVersion = "undefined" // 2.5.6.4831
|
||||
PCPackageName = "mypikpak.com"
|
||||
PCSdkVersion = "8.0.3"
|
||||
)
|
||||
|
||||
var DlAddr = []string{
|
||||
"dl-a10b-0621.mypikpak.com",
|
||||
"dl-a10b-0622.mypikpak.com",
|
||||
"dl-a10b-0623.mypikpak.com",
|
||||
"dl-a10b-0624.mypikpak.com",
|
||||
"dl-a10b-0625.mypikpak.com",
|
||||
"dl-a10b-0858.mypikpak.com",
|
||||
"dl-a10b-0859.mypikpak.com",
|
||||
"dl-a10b-0860.mypikpak.com",
|
||||
"dl-a10b-0861.mypikpak.com",
|
||||
"dl-a10b-0862.mypikpak.com",
|
||||
"dl-a10b-0863.mypikpak.com",
|
||||
"dl-a10b-0864.mypikpak.com",
|
||||
"dl-a10b-0865.mypikpak.com",
|
||||
"dl-a10b-0866.mypikpak.com",
|
||||
"dl-a10b-0867.mypikpak.com",
|
||||
"dl-a10b-0868.mypikpak.com",
|
||||
"dl-a10b-0869.mypikpak.com",
|
||||
"dl-a10b-0870.mypikpak.com",
|
||||
"dl-a10b-0871.mypikpak.com",
|
||||
"dl-a10b-0872.mypikpak.com",
|
||||
"dl-a10b-0873.mypikpak.com",
|
||||
"dl-a10b-0874.mypikpak.com",
|
||||
"dl-a10b-0875.mypikpak.com",
|
||||
"dl-a10b-0876.mypikpak.com",
|
||||
"dl-a10b-0877.mypikpak.com",
|
||||
"dl-a10b-0878.mypikpak.com",
|
||||
"dl-a10b-0879.mypikpak.com",
|
||||
"dl-a10b-0880.mypikpak.com",
|
||||
"dl-a10b-0881.mypikpak.com",
|
||||
"dl-a10b-0882.mypikpak.com",
|
||||
"dl-a10b-0883.mypikpak.com",
|
||||
"dl-a10b-0884.mypikpak.com",
|
||||
"dl-a10b-0885.mypikpak.com",
|
||||
"dl-a10b-0886.mypikpak.com",
|
||||
"dl-a10b-0887.mypikpak.com",
|
||||
}
|
||||
|
||||
func (d *PikPak) login() error {
|
||||
// 检查用户名和密码是否为空
|
||||
if d.Addition.Username == "" || d.Addition.Password == "" {
|
||||
return errors.New("username or password is empty")
|
||||
}
|
||||
|
||||
url := "https://user.mypikpak.com/v1/auth/signin"
|
||||
// 使用 用户填写的 CaptchaToken —————— (验证后的captcha_token)
|
||||
if d.GetCaptchaToken() == "" {
|
||||
@ -112,39 +168,68 @@ func (d *PikPak) login() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//func (d *PikPak) refreshToken() error {
|
||||
// url := "https://user.mypikpak.com/v1/auth/token"
|
||||
// var e ErrResp
|
||||
// res, err := base.RestyClient.SetRetryCount(1).R().SetError(&e).
|
||||
// SetHeader("user-agent", "").SetBody(base.Json{
|
||||
// "client_id": ClientID,
|
||||
// "client_secret": ClientSecret,
|
||||
// "grant_type": "refresh_token",
|
||||
// "refresh_token": d.RefreshToken,
|
||||
// }).SetQueryParam("client_id", ClientID).Post(url)
|
||||
// if err != nil {
|
||||
// d.Status = err.Error()
|
||||
// op.MustSaveDriverStorage(d)
|
||||
// return err
|
||||
// }
|
||||
// if e.ErrorCode != 0 {
|
||||
// if e.ErrorCode == 4126 {
|
||||
// // refresh_token invalid, re-login
|
||||
// return d.login()
|
||||
// }
|
||||
// d.Status = e.Error()
|
||||
// op.MustSaveDriverStorage(d)
|
||||
// return errors.New(e.Error())
|
||||
// }
|
||||
// data := res.Body()
|
||||
// d.Status = "work"
|
||||
// d.RefreshToken = jsoniter.Get(data, "refresh_token").ToString()
|
||||
// d.AccessToken = jsoniter.Get(data, "access_token").ToString()
|
||||
// d.Common.SetUserID(jsoniter.Get(data, "sub").ToString())
|
||||
// d.Addition.RefreshToken = d.RefreshToken
|
||||
// op.MustSaveDriverStorage(d)
|
||||
// return nil
|
||||
//}
|
||||
func (d *PikPak) refreshToken(refreshToken string) error {
|
||||
url := "https://user.mypikpak.com/v1/auth/token"
|
||||
var e ErrResp
|
||||
res, err := base.RestyClient.SetRetryCount(1).R().SetError(&e).
|
||||
SetHeader("user-agent", "").SetBody(base.Json{
|
||||
"client_id": d.ClientID,
|
||||
"client_secret": d.ClientSecret,
|
||||
"grant_type": "refresh_token",
|
||||
"refresh_token": refreshToken,
|
||||
}).SetQueryParam("client_id", d.ClientID).Post(url)
|
||||
if err != nil {
|
||||
d.Status = err.Error()
|
||||
op.MustSaveDriverStorage(d)
|
||||
return err
|
||||
}
|
||||
if e.ErrorCode != 0 {
|
||||
if e.ErrorCode == 4126 {
|
||||
// 1. 未填写 username 或 password
|
||||
if d.Addition.Username == "" || d.Addition.Password == "" {
|
||||
return errors.New("refresh_token invalid, please re-provide refresh_token")
|
||||
} else {
|
||||
// refresh_token invalid, re-login
|
||||
return d.login()
|
||||
}
|
||||
}
|
||||
d.Status = e.Error()
|
||||
op.MustSaveDriverStorage(d)
|
||||
return errors.New(e.Error())
|
||||
}
|
||||
data := res.Body()
|
||||
d.Status = "work"
|
||||
d.RefreshToken = jsoniter.Get(data, "refresh_token").ToString()
|
||||
d.AccessToken = jsoniter.Get(data, "access_token").ToString()
|
||||
d.Common.SetUserID(jsoniter.Get(data, "sub").ToString())
|
||||
d.Addition.RefreshToken = d.RefreshToken
|
||||
op.MustSaveDriverStorage(d)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *PikPak) initializeOAuth2Token(ctx context.Context, oauth2Config *oauth2.Config, refreshToken string) {
|
||||
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
|
||||
return oauth2Config.TokenSource(ctx, &oauth2.Token{
|
||||
RefreshToken: refreshToken,
|
||||
}).Token()
|
||||
}))
|
||||
}
|
||||
|
||||
func (d *PikPak) refreshTokenByOAuth2() error {
|
||||
token, err := d.oauth2Token.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Status = "work"
|
||||
d.RefreshToken = token.RefreshToken
|
||||
d.AccessToken = token.AccessToken
|
||||
// 获取用户ID
|
||||
userID := token.Extra("sub").(string)
|
||||
d.Common.SetUserID(userID)
|
||||
d.Addition.RefreshToken = d.RefreshToken
|
||||
op.MustSaveDriverStorage(d)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *PikPak) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||
req := base.RestyClient.R()
|
||||
@ -154,13 +239,15 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
|
||||
"X-Device-ID": d.GetDeviceID(),
|
||||
"X-Captcha-Token": d.GetCaptchaToken(),
|
||||
})
|
||||
if d.oauth2Token != nil {
|
||||
if d.RefreshTokenMethod == "oauth2" && d.oauth2Token != nil {
|
||||
// 使用oauth2 获取 access_token
|
||||
token, err := d.oauth2Token.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken)
|
||||
} else if d.AccessToken != "" {
|
||||
req.SetHeader("Authorization", "Bearer "+d.AccessToken)
|
||||
}
|
||||
|
||||
if callback != nil {
|
||||
@ -181,22 +268,19 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
|
||||
return res.Body(), nil
|
||||
case 4122, 4121, 16:
|
||||
// access_token 过期
|
||||
|
||||
//if err1 := d.refreshToken(); err1 != nil {
|
||||
// return nil, err1
|
||||
//}
|
||||
t, err := d.oauth2Token.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if d.RefreshTokenMethod == "oauth2" {
|
||||
if err1 := d.refreshTokenByOAuth2(); err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
} else {
|
||||
if err1 := d.refreshToken(d.RefreshToken); err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
}
|
||||
d.AccessToken = t.AccessToken
|
||||
d.RefreshToken = t.RefreshToken
|
||||
d.Addition.RefreshToken = t.RefreshToken
|
||||
op.MustSaveDriverStorage(d)
|
||||
|
||||
return d.request(url, method, callback, resp)
|
||||
case 9: // 验证码token过期
|
||||
if err = d.RefreshCaptchaTokenAtLogin(GetAction(method, url), d.Common.UserID); err != nil {
|
||||
if err = d.RefreshCaptchaTokenAtLogin(GetAction(method, url), d.GetUserID()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.request(url, method, callback, resp)
|
||||
@ -254,6 +338,7 @@ type Common struct {
|
||||
UserAgent string
|
||||
// 验证码token刷新成功回调
|
||||
RefreshCTokenCk func(token string)
|
||||
LowLatencyAddr string
|
||||
}
|
||||
|
||||
func generateDeviceSign(deviceID, packageName string) string {
|
||||
@ -337,6 +422,10 @@ func (c *Common) GetDeviceID() string {
|
||||
return c.DeviceID
|
||||
}
|
||||
|
||||
func (c *Common) GetUserID() string {
|
||||
return c.UserID
|
||||
}
|
||||
|
||||
// RefreshCaptchaTokenAtLogin 刷新验证码token(登录后)
|
||||
func (d *PikPak) RefreshCaptchaTokenAtLogin(action, userID string) error {
|
||||
metas := map[string]string{
|
||||
@ -640,3 +729,46 @@ func OssOption(params *S3Params) []oss.Option {
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
type AddressLatency struct {
|
||||
Address string
|
||||
Latency time.Duration
|
||||
}
|
||||
|
||||
func checkLatency(address string, wg *sync.WaitGroup, ch chan<- AddressLatency) {
|
||||
defer wg.Done()
|
||||
start := time.Now()
|
||||
resp, err := http.Get("https://" + address + "/generate_204")
|
||||
if err != nil {
|
||||
ch <- AddressLatency{Address: address, Latency: time.Hour} // Set high latency on error
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
latency := time.Since(start)
|
||||
ch <- AddressLatency{Address: address, Latency: latency}
|
||||
}
|
||||
|
||||
func findLowestLatencyAddress(addresses []string) string {
|
||||
var wg sync.WaitGroup
|
||||
ch := make(chan AddressLatency, len(addresses))
|
||||
|
||||
for _, address := range addresses {
|
||||
wg.Add(1)
|
||||
go checkLatency(address, &wg, ch)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(ch)
|
||||
|
||||
var lowestLatencyAddress string
|
||||
lowestLatency := time.Hour
|
||||
|
||||
for result := range ch {
|
||||
if result.Latency < lowestLatency {
|
||||
lowestLatency = result.Latency
|
||||
lowestLatencyAddress = result.Address
|
||||
}
|
||||
}
|
||||
|
||||
return lowestLatencyAddress
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
@ -36,6 +37,7 @@ func (d *PikPakShare) Init(ctx context.Context) error {
|
||||
d.Common.CaptchaToken = token
|
||||
op.MustSaveDriverStorage(d)
|
||||
},
|
||||
LowLatencyAddr: "",
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,6 +62,21 @@ func (d *PikPakShare) Init(ctx context.Context) error {
|
||||
d.PackageName = WebPackageName
|
||||
d.Algorithms = WebAlgorithms
|
||||
d.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
|
||||
} else if d.Platform == "pc" {
|
||||
d.ClientID = PCClientID
|
||||
d.ClientSecret = PCClientSecret
|
||||
d.ClientVersion = PCClientVersion
|
||||
d.PackageName = PCPackageName
|
||||
d.Algorithms = PCAlgorithms
|
||||
d.UserAgent = "MainWindow Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) PikPak/2.5.6.4831 Chrome/100.0.4896.160 Electron/18.3.15 Safari/537.36"
|
||||
}
|
||||
|
||||
if d.UseLowLatencyAddress && d.Addition.CustomLowLatencyAddress != "" {
|
||||
d.Common.LowLatencyAddr = d.Addition.CustomLowLatencyAddress
|
||||
} else if d.UseLowLatencyAddress {
|
||||
d.Common.LowLatencyAddr = findLowestLatencyAddress(DlAddr)
|
||||
d.Addition.CustomLowLatencyAddress = d.Common.LowLatencyAddr
|
||||
op.MustSaveDriverStorage(d)
|
||||
}
|
||||
|
||||
// 获取CaptchaToken
|
||||
@ -71,6 +88,7 @@ func (d *PikPakShare) Init(ctx context.Context) error {
|
||||
if d.SharePwd != "" {
|
||||
return d.getSharePassToken()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -112,10 +130,16 @@ func (d *PikPakShare) Link(ctx context.Context, file model.Obj, args model.LinkA
|
||||
}
|
||||
|
||||
}
|
||||
link := model.Link{
|
||||
URL: downloadUrl,
|
||||
|
||||
if d.UseLowLatencyAddress && d.Common.LowLatencyAddr != "" {
|
||||
// 替换为加速链接
|
||||
re := regexp.MustCompile(`https://[^/]+/download/`)
|
||||
downloadUrl = re.ReplaceAllString(downloadUrl, "https://"+d.Common.LowLatencyAddr+"/download/")
|
||||
}
|
||||
return &link, nil
|
||||
|
||||
return &model.Link{
|
||||
URL: downloadUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ driver.Driver = (*PikPakShare)(nil)
|
||||
|
@ -9,9 +9,11 @@ type Addition struct {
|
||||
driver.RootID
|
||||
ShareId string `json:"share_id" required:"true"`
|
||||
SharePwd string `json:"share_pwd"`
|
||||
Platform string `json:"platform" required:"true" type:"select" options:"android,web"`
|
||||
Platform string `json:"platform" required:"true" type:"select" options:"android,web,pc"`
|
||||
DeviceID string `json:"device_id" required:"false" default:""`
|
||||
UseTransCodingAddress bool `json:"use_transcoding_address" required:"true" default:"false"`
|
||||
UseLowLatencyAddress bool `json:"use_low_latency_address" default:"false"`
|
||||
CustomLowLatencyAddress string `json:"custom_low_latency_address" default:""`
|
||||
}
|
||||
|
||||
var config = driver.Config{
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/alist-org/alist/v3/drivers/base"
|
||||
@ -17,21 +18,14 @@ import (
|
||||
)
|
||||
|
||||
var AndroidAlgorithms = []string{
|
||||
"Gez0T9ijiI9WCeTsKSg3SMlx",
|
||||
"zQdbalsolyb1R/",
|
||||
"ftOjr52zt51JD68C3s",
|
||||
"yeOBMH0JkbQdEFNNwQ0RI9T3wU/v",
|
||||
"BRJrQZiTQ65WtMvwO",
|
||||
"je8fqxKPdQVJiy1DM6Bc9Nb1",
|
||||
"niV",
|
||||
"9hFCW2R1",
|
||||
"sHKHpe2i96",
|
||||
"p7c5E6AcXQ/IJUuAEC9W6",
|
||||
"",
|
||||
"aRv9hjc9P+Pbn+u3krN6",
|
||||
"BzStcgE8qVdqjEH16l4",
|
||||
"SqgeZvL5j9zoHP95xWHt",
|
||||
"zVof5yaJkPe3VFpadPof",
|
||||
"aDhgaSE3MsjROCmpmsWqP1sJdFJ",
|
||||
"+oaVkqdd8MJuKT+uMr2AYKcd9tdWge3XPEPR2hcePUknd",
|
||||
"u/sd2GgT2fTytRcKzGicHodhvIltMntA3xKw2SRv7S48OdnaQIS5mn",
|
||||
"2WZiae2QuqTOxBKaaqCNHCW3olu2UImelkDzBn",
|
||||
"/vJ3upic39lgmrkX855Qx",
|
||||
"yNc9ruCVMV7pGV7XvFeuLMOcy1",
|
||||
"4FPq8mT3JQ1jzcVxMVfwFftLQm33M7i",
|
||||
"xozoy5e3Ea",
|
||||
}
|
||||
|
||||
var WebAlgorithms = []string{
|
||||
@ -52,19 +46,75 @@ var WebAlgorithms = []string{
|
||||
"NhXXU9rg4XXdzo7u5o",
|
||||
}
|
||||
|
||||
var PCAlgorithms = []string{
|
||||
"KHBJ07an7ROXDoK7Db",
|
||||
"G6n399rSWkl7WcQmw5rpQInurc1DkLmLJqE",
|
||||
"JZD1A3M4x+jBFN62hkr7VDhkkZxb9g3rWqRZqFAAb",
|
||||
"fQnw/AmSlbbI91Ik15gpddGgyU7U",
|
||||
"/Dv9JdPYSj3sHiWjouR95NTQff",
|
||||
"yGx2zuTjbWENZqecNI+edrQgqmZKP",
|
||||
"ljrbSzdHLwbqcRn",
|
||||
"lSHAsqCkGDGxQqqwrVu",
|
||||
"TsWXI81fD1",
|
||||
"vk7hBjawK/rOSrSWajtbMk95nfgf3",
|
||||
}
|
||||
|
||||
const (
|
||||
AndroidClientID = "YNxT9w7GMdWvEOKa"
|
||||
AndroidClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||
AndroidClientVersion = "1.47.1"
|
||||
AndroidClientVersion = "1.48.3"
|
||||
AndroidPackageName = "com.pikcloud.pikpak"
|
||||
AndroidSdkVersion = "2.0.4.204000"
|
||||
AndroidSdkVersion = "2.0.4.204101"
|
||||
WebClientID = "YUMx5nI8ZU8Ap8pm"
|
||||
WebClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||
WebClientVersion = "2.0.0"
|
||||
WebPackageName = "mypikpak.com"
|
||||
WebSdkVersion = "8.0.3"
|
||||
PCClientID = "YvtoWO6GNHiuCl7x"
|
||||
PCClientSecret = "1NIH5R1IEe2pAxZE3hv3uA"
|
||||
PCClientVersion = "undefined" // 2.5.6.4831
|
||||
PCPackageName = "mypikpak.com"
|
||||
PCSdkVersion = "8.0.3"
|
||||
)
|
||||
|
||||
var DlAddr = []string{
|
||||
"dl-a10b-0621.mypikpak.com",
|
||||
"dl-a10b-0622.mypikpak.com",
|
||||
"dl-a10b-0623.mypikpak.com",
|
||||
"dl-a10b-0624.mypikpak.com",
|
||||
"dl-a10b-0625.mypikpak.com",
|
||||
"dl-a10b-0858.mypikpak.com",
|
||||
"dl-a10b-0859.mypikpak.com",
|
||||
"dl-a10b-0860.mypikpak.com",
|
||||
"dl-a10b-0861.mypikpak.com",
|
||||
"dl-a10b-0862.mypikpak.com",
|
||||
"dl-a10b-0863.mypikpak.com",
|
||||
"dl-a10b-0864.mypikpak.com",
|
||||
"dl-a10b-0865.mypikpak.com",
|
||||
"dl-a10b-0866.mypikpak.com",
|
||||
"dl-a10b-0867.mypikpak.com",
|
||||
"dl-a10b-0868.mypikpak.com",
|
||||
"dl-a10b-0869.mypikpak.com",
|
||||
"dl-a10b-0870.mypikpak.com",
|
||||
"dl-a10b-0871.mypikpak.com",
|
||||
"dl-a10b-0872.mypikpak.com",
|
||||
"dl-a10b-0873.mypikpak.com",
|
||||
"dl-a10b-0874.mypikpak.com",
|
||||
"dl-a10b-0875.mypikpak.com",
|
||||
"dl-a10b-0876.mypikpak.com",
|
||||
"dl-a10b-0877.mypikpak.com",
|
||||
"dl-a10b-0878.mypikpak.com",
|
||||
"dl-a10b-0879.mypikpak.com",
|
||||
"dl-a10b-0880.mypikpak.com",
|
||||
"dl-a10b-0881.mypikpak.com",
|
||||
"dl-a10b-0882.mypikpak.com",
|
||||
"dl-a10b-0883.mypikpak.com",
|
||||
"dl-a10b-0884.mypikpak.com",
|
||||
"dl-a10b-0885.mypikpak.com",
|
||||
"dl-a10b-0886.mypikpak.com",
|
||||
"dl-a10b-0887.mypikpak.com",
|
||||
}
|
||||
|
||||
func (d *PikPakShare) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||
req := base.RestyClient.R()
|
||||
req.SetHeaders(map[string]string{
|
||||
@ -177,6 +227,7 @@ type Common struct {
|
||||
UserAgent string
|
||||
// 验证码token刷新成功回调
|
||||
RefreshCTokenCk func(token string)
|
||||
LowLatencyAddr string
|
||||
}
|
||||
|
||||
func (c *Common) SetUserAgent(userAgent string) {
|
||||
@ -316,3 +367,46 @@ func (d *PikPakShare) refreshCaptchaToken(action string, metas map[string]string
|
||||
d.Common.SetCaptchaToken(resp.CaptchaToken)
|
||||
return nil
|
||||
}
|
||||
|
||||
type AddressLatency struct {
|
||||
Address string
|
||||
Latency time.Duration
|
||||
}
|
||||
|
||||
func checkLatency(address string, wg *sync.WaitGroup, ch chan<- AddressLatency) {
|
||||
defer wg.Done()
|
||||
start := time.Now()
|
||||
resp, err := http.Get("https://" + address + "/generate_204")
|
||||
if err != nil {
|
||||
ch <- AddressLatency{Address: address, Latency: time.Hour} // Set high latency on error
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
latency := time.Since(start)
|
||||
ch <- AddressLatency{Address: address, Latency: latency}
|
||||
}
|
||||
|
||||
func findLowestLatencyAddress(addresses []string) string {
|
||||
var wg sync.WaitGroup
|
||||
ch := make(chan AddressLatency, len(addresses))
|
||||
|
||||
for _, address := range addresses {
|
||||
wg.Add(1)
|
||||
go checkLatency(address, &wg, ch)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(ch)
|
||||
|
||||
var lowestLatencyAddress string
|
||||
lowestLatency := time.Hour
|
||||
|
||||
for result := range ch {
|
||||
if result.Latency < lowestLatency {
|
||||
lowestLatency = result.Latency
|
||||
lowestLatencyAddress = result.Address
|
||||
}
|
||||
}
|
||||
|
||||
return lowestLatencyAddress
|
||||
}
|
||||
|
48
go.mod
48
go.mod
@ -3,7 +3,7 @@ module github.com/alist-org/alist/v3
|
||||
go 1.22.4
|
||||
|
||||
require (
|
||||
github.com/SheltonZhu/115driver v1.0.27
|
||||
github.com/SheltonZhu/115driver v1.0.29
|
||||
github.com/Xhofe/go-cache v0.0.0-20240804043513-b1a71927bc21
|
||||
github.com/Xhofe/rateg v0.0.0-20230728072201-251a4e1adad4
|
||||
github.com/alist-org/gofakes3 v0.0.7
|
||||
@ -13,8 +13,8 @@ require (
|
||||
github.com/aws/aws-sdk-go v1.55.5
|
||||
github.com/blevesearch/bleve/v2 v2.4.2
|
||||
github.com/caarlos0/env/v9 v9.0.0
|
||||
github.com/charmbracelet/bubbles v0.19.0
|
||||
github.com/charmbracelet/bubbletea v0.27.0
|
||||
github.com/charmbracelet/bubbles v0.20.0
|
||||
github.com/charmbracelet/bubbletea v1.1.0
|
||||
github.com/charmbracelet/lipgloss v0.13.0
|
||||
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
@ -42,12 +42,12 @@ require (
|
||||
github.com/meilisearch/meilisearch-go v0.27.2
|
||||
github.com/minio/sio v0.4.0
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||
github.com/ncw/swift/v2 v2.0.2
|
||||
github.com/ncw/swift/v2 v2.0.3
|
||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/sftp v1.13.6
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/rclone/rclone v1.67.0
|
||||
github.com/rclone/rclone v1.68.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
@ -58,8 +58,8 @@ require (
|
||||
github.com/xhofe/tache v0.1.2
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3
|
||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
||||
golang.org/x/crypto v0.26.0
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
||||
golang.org/x/crypto v0.27.0
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
|
||||
golang.org/x/image v0.19.0
|
||||
golang.org/x/net v0.28.0
|
||||
golang.org/x/oauth2 v0.22.0
|
||||
@ -77,16 +77,14 @@ require (
|
||||
github.com/blevesearch/go-faiss v1.0.20 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.1.5 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.4 // indirect
|
||||
github.com/charmbracelet/x/input v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/ipfs/boxo v0.12.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@ -126,17 +124,17 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
|
||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.12 // indirect
|
||||
github.com/go-chi/chi/v5 v5.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/go-webauthn/x v0.1.12 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
@ -156,8 +154,8 @@ require (
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
@ -202,7 +200,7 @@ require (
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
|
||||
github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
@ -217,16 +215,16 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xhofe/gsync v0.0.0-20230917091818-2111ceb38a25 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.etcd.io/bbolt v1.3.8 // indirect
|
||||
go.etcd.io/bbolt v1.3.10 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/term v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/term v0.24.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
google.golang.org/api v0.169.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
|
||||
google.golang.org/grpc v1.65.0
|
||||
google.golang.org/api v0.188.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b // indirect
|
||||
google.golang.org/grpc v1.66.0
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
|
80
go.sum
80
go.sum
@ -7,8 +7,8 @@ github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9
|
||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc=
|
||||
github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM=
|
||||
github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||
github.com/SheltonZhu/115driver v1.0.27 h1:Ya1HYHYXFmi7JnqQ/+Vy6xZvq3leto+E+PxTm6UChj8=
|
||||
github.com/SheltonZhu/115driver v1.0.27/go.mod h1:e3fPOBANbH/FsTya8FquJwOR3ErhCQgEab3q6CVY2k4=
|
||||
github.com/SheltonZhu/115driver v1.0.29 h1:yFBqFDYJyADo3eG2RjJgSovnFd1OrpGHmsHBi6j0+r4=
|
||||
github.com/SheltonZhu/115driver v1.0.29/go.mod h1:e3fPOBANbH/FsTya8FquJwOR3ErhCQgEab3q6CVY2k4=
|
||||
github.com/Unknwon/goconfig v1.0.0 h1:9IAu/BYbSLQi8puFjUQApZTxIHqSwrj5d8vpP8vTq4A=
|
||||
github.com/Unknwon/goconfig v1.0.0/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
|
||||
github.com/Xhofe/go-cache v0.0.0-20240804043513-b1a71927bc21 h1:h6q5E9aMBhhdqouW81LozVPI1I+Pu6IxL2EKpfm5OjY=
|
||||
@ -96,22 +96,18 @@ github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc
|
||||
github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbles v0.19.0 h1:gKZkKXPP6GlDk6EcfujDK19PCQqRjaJZQ7QRERx1UF0=
|
||||
github.com/charmbracelet/bubbles v0.19.0/go.mod h1:WILteEqZ+krG5c3ntGEMeG99nCupcuIk7V0/zOP0tOA=
|
||||
github.com/charmbracelet/bubbletea v0.27.0 h1:Mznj+vvYuYagD9Pn2mY7fuelGvP0HAXtZYGgRBCbHvU=
|
||||
github.com/charmbracelet/bubbletea v0.27.0/go.mod h1:5MdP9XH6MbQkgGhnlxUqCNmBXf9I74KRQ8HIidRxV1Y=
|
||||
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
||||
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
|
||||
github.com/charmbracelet/bubbletea v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c=
|
||||
github.com/charmbracelet/bubbletea v1.1.0/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4=
|
||||
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
|
||||
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
|
||||
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
|
||||
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY=
|
||||
github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ=
|
||||
github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28=
|
||||
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
|
||||
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
|
||||
github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4=
|
||||
github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
|
||||
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
|
||||
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
|
||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
|
||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
|
||||
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e h1:GLC8iDDcbt1H8+RkNao2nRGjyNTIo81e1rAJT9/uWYA=
|
||||
@ -124,6 +120,8 @@ github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjs
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg=
|
||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE=
|
||||
@ -159,6 +157,8 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
|
||||
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=
|
||||
@ -172,6 +172,8 @@ github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@ -205,6 +207,9 @@ github.com/go-webauthn/x v0.1.12/go.mod h1:XlRcGkNH8PT45TfeJYc6gqpOtiOendHhVmnOx
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
@ -293,9 +298,13 @@ github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
|
||||
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
@ -385,8 +394,8 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n
|
||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||
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/ncw/swift/v2 v2.0.2 h1:jx282pcAKFhmoZBSdMcCRFn9VWkoBIRsCpe+yZq7vEk=
|
||||
github.com/ncw/swift/v2 v2.0.2/go.mod h1:z0A9RVdYPjNjXVo2pDOPxZ4eu3oarO1P91fTItcb+Kg=
|
||||
github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
|
||||
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831 h1:K3T3eu4h5aYIOzUtLjN08L4Qt4WGaJONMgcaD0ayBJQ=
|
||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831/go.mod h1:lSHD4lC4zlMl+zcoysdJcd5KFzsWwOD8BJbyg1Ws9Ng=
|
||||
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
|
||||
@ -423,6 +432,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rclone/rclone v1.67.0 h1:yLRNgHEG2vQ60HCuzFqd0hYwKCRuWuvPUhvhMJ2jI5E=
|
||||
github.com/rclone/rclone v1.67.0/go.mod h1:Cb3Ar47M/SvwfhAjZTbVXdtrP/JLtPFCq2tkdtBVC6w=
|
||||
github.com/rclone/rclone v1.68.1 h1:vlEOAuPv4gGxWECM0NIaCwBNUt3ZQY7mCsyBtZjY+68=
|
||||
github.com/rclone/rclone v1.68.1/go.mod h1:T8XKOt/2Fb9INROUtFH9eF9q9o9rI1W2qTrW2bw2cYU=
|
||||
github.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4=
|
||||
github.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Nyk1k=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
@ -439,6 +450,8 @@ github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df h1:S77Pf5fIG
|
||||
github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df/go.mod h1:dcuzJZ83w/SqN9k4eQqwKYMgmKWzg/KzJAURBhRL1tc=
|
||||
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
|
||||
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
@ -512,8 +525,6 @@ github.com/xhofe/tache v0.1.2 h1:pHrXlrWcbTb4G7hVUDW7Rc+YTUnLJvnLBrdktVE1Fqg=
|
||||
github.com/xhofe/tache v0.1.2/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3 h1:J58X6v+n25ewBZjb05pKOr7AWGohb+Rdll4CThGh6+A=
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3/go.mod h1:dcY9yA28fnaoZPnXZiVTFSkcd7GnIPTpTIIlfSI5z5Q=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
@ -523,6 +534,8 @@ github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22 h1:X+lH
|
||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22/go.mod h1:1zGRDJd8zlG6P8azG96+uywfh6udYWwhOmUivw+xsuM=
|
||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
||||
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
@ -552,10 +565,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||
@ -628,8 +641,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -640,8 +653,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
|
||||
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@ -655,8 +668,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
@ -679,12 +692,15 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
|
||||
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
|
||||
google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b h1:04+jVzTs2XBnOZcPsLnmrTGqltqJbZQ1Ey26hjYdQQ0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
|
@ -102,7 +102,13 @@ func initURL() {
|
||||
}
|
||||
|
||||
func CleanTempDir() {
|
||||
if err := os.RemoveAll(conf.Conf.TempDir); err != nil {
|
||||
files, err := os.ReadDir(conf.Conf.TempDir)
|
||||
if err != nil {
|
||||
log.Errorln("failed list temp file: ", err)
|
||||
}
|
||||
for _, file := range files {
|
||||
if err := os.RemoveAll(filepath.Join(conf.Conf.TempDir, file.Name())); err != nil {
|
||||
log.Errorln("failed delete temp file: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,9 +87,9 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, name string, modTime time
|
||||
sendSize := size
|
||||
var sendContent io.ReadCloser
|
||||
ranges, err := http_range.ParseRange(rangeReq, size)
|
||||
switch err {
|
||||
case nil:
|
||||
case http_range.ErrNoOverlap:
|
||||
switch {
|
||||
case err == nil:
|
||||
case errors.Is(err, http_range.ErrNoOverlap):
|
||||
if size == 0 {
|
||||
// Some clients add a Range header to all requests to
|
||||
// limit the size of the response. If the file is empty,
|
||||
@ -105,7 +105,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, name string, modTime time
|
||||
return
|
||||
}
|
||||
|
||||
if sumRangesSize(ranges) > size || size < 0 {
|
||||
if sumRangesSize(ranges) > size {
|
||||
// The total number of bytes in all the ranges is larger than the size of the file
|
||||
// or unknown file size, ignore the range request.
|
||||
ranges = nil
|
||||
@ -174,6 +174,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, name string, modTime time
|
||||
pw.Close()
|
||||
}()
|
||||
}
|
||||
defer sendContent.Close()
|
||||
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
if w.Header().Get("Content-Encoding") == "" {
|
||||
@ -192,7 +193,6 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, name string, modTime time
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
//defer sendContent.Close()
|
||||
}
|
||||
func ProcessHeader(origin, override http.Header) http.Header {
|
||||
result := http.Header{}
|
||||
|
@ -267,6 +267,12 @@ func Link(ctx context.Context, storage driver.Driver, path string, args model.Li
|
||||
}
|
||||
return link, nil
|
||||
}
|
||||
|
||||
if storage.Config().OnlyLocal {
|
||||
link, err := fn()
|
||||
return link, file, err
|
||||
}
|
||||
|
||||
link, err, _ := linkG.Do(key, fn)
|
||||
return link, file, err
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package op
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -83,11 +85,25 @@ func LoadStorage(ctx context.Context, storage model.Storage) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func getCurrentGoroutineStack() string {
|
||||
buf := make([]byte, 1<<16)
|
||||
n := runtime.Stack(buf, false)
|
||||
return string(buf[:n])
|
||||
}
|
||||
|
||||
// initStorage initialize the driver and store to storagesMap
|
||||
func initStorage(ctx context.Context, storage model.Storage, storageDriver driver.Driver) (err error) {
|
||||
storageDriver.SetStorage(storage)
|
||||
driverStorage := storageDriver.GetStorage()
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
errInfo := fmt.Sprintf("[panic] err: %v\nstack: %s\n", err, getCurrentGoroutineStack())
|
||||
log.Errorf("panic init storage: %s", errInfo)
|
||||
driverStorage.SetStatus(errInfo)
|
||||
MustSaveDriverStorage(storageDriver)
|
||||
storagesMap.Delete(driverStorage.MountPath)
|
||||
}
|
||||
}()
|
||||
// Unmarshal Addition
|
||||
err = utils.Json.UnmarshalFromString(driverStorage.Addition, storageDriver.GetAddition())
|
||||
if err == nil {
|
||||
|
Reference in New Issue
Block a user