Compare commits
14 Commits
renovate/g
...
v3.37.1
Author | SHA1 | Date | |
---|---|---|---|
b36d38f63f | |||
c8317250c1 | |||
0242f36e1c | |||
40a68bcee6 | |||
92713ef5c4 | |||
716d33fddd | |||
c9fa3d7cd6 | |||
4874c9e43b | |||
34ada81582 | |||
ba716ae325 | |||
d4f9c4b6af | |||
b910b8917f | |||
d92744e673 | |||
868b0ec25c |
14
.github/workflows/beta_release.yml
vendored
14
.github/workflows/beta_release.yml
vendored
@ -85,4 +85,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
files: build/compress/*
|
files: build/compress/*
|
||||||
prerelease: true
|
prerelease: true
|
||||||
tag_name: beta
|
tag_name: beta
|
||||||
|
|
||||||
|
desktop:
|
||||||
|
needs:
|
||||||
|
- release
|
||||||
|
name: Beta Release Desktop
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: dusansimic/trigger-workflow-action@v0
|
||||||
|
with:
|
||||||
|
name: release_beta.yml
|
||||||
|
owner: alist-org
|
||||||
|
repo: desktop-release
|
@ -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.
|
- [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://www.asiayun.com/aff/QQCOOQKZ) - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商 (sponsored Chinese API server)
|
||||||
- [找资源](https://zhaoziyuan.pw/) - 阿里云盘资源搜索引擎
|
- [找资源](http://zhaoziyuan2.cc/) - 阿里云盘资源搜索引擎
|
||||||
|
|
||||||
## Contributors
|
## 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全平台支持。
|
- [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://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.
|
- [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://www.asiayun.com/aff/QQCOOQKZ) - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商 (sponsored Chinese API server)
|
||||||
- [找资源](https://zhaoziyuan.pw/) - 阿里云盘资源搜索引擎
|
- [找资源](http://zhaoziyuan2.cc/) - 阿里云盘资源搜索引擎
|
||||||
|
|
||||||
## コントリビューター
|
## コントリビューター
|
||||||
|
|
||||||
|
@ -30,6 +30,10 @@ type Local struct {
|
|||||||
model.Storage
|
model.Storage
|
||||||
Addition
|
Addition
|
||||||
mkdirPerm int32
|
mkdirPerm int32
|
||||||
|
|
||||||
|
// zero means no limit
|
||||||
|
thumbConcurrency int
|
||||||
|
thumbTokenBucket TokenBucket
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Local) Config() driver.Config {
|
func (d *Local) Config() driver.Config {
|
||||||
@ -62,6 +66,18 @@ func (d *Local) Init(ctx context.Context) error {
|
|||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +142,6 @@ func (d *Local) FileInfoToObj(f fs.FileInfo, reqPath string, fullPath string) mo
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
return &file
|
return &file
|
||||||
|
|
||||||
}
|
}
|
||||||
func (d *Local) GetMeta(ctx context.Context, path string) (model.Obj, error) {
|
func (d *Local) GetMeta(ctx context.Context, path string) (model.Obj, error) {
|
||||||
f, err := os.Stat(path)
|
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()
|
fullPath := file.GetPath()
|
||||||
var link model.Link
|
var link model.Link
|
||||||
if args.Type == "thumb" && utils.Ext(file.GetName()) != "svg" {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ type Addition struct {
|
|||||||
driver.RootPath
|
driver.RootPath
|
||||||
Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"`
|
Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"`
|
||||||
ThumbCacheFolder string `json:"thumb_cache_folder"`
|
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"`
|
ShowHidden bool `json:"show_hidden" default:"true" required:"false" help:"show hidden directories and files"`
|
||||||
MkdirPerm string `json:"mkdir_perm" default:"777"`
|
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'"`
|
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) {
|
func GetSnapshot(videoPath string, frameNum int) (imgData *bytes.Buffer, err error) {
|
||||||
srcBuf := bytes.NewBuffer(nil)
|
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"}).
|
Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
|
||||||
WithOutput(srcBuf, os.Stdout).
|
GlobalArgs("-loglevel", "error").Silent(true).
|
||||||
Run()
|
WithOutput(srcBuf, os.Stdout)
|
||||||
|
if err = stream.Run(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return srcBuf, nil
|
return srcBuf, nil
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -48,6 +49,7 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
|||||||
d.Common.CaptchaToken = token
|
d.Common.CaptchaToken = token
|
||||||
op.MustSaveDriverStorage(d)
|
op.MustSaveDriverStorage(d)
|
||||||
},
|
},
|
||||||
|
LowLatencyAddr: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +67,13 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
|||||||
d.PackageName = WebPackageName
|
d.PackageName = WebPackageName
|
||||||
d.Algorithms = WebAlgorithms
|
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"
|
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 == "" {
|
if d.Addition.CaptchaToken != "" && d.Addition.RefreshToken == "" {
|
||||||
@ -90,43 +99,36 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
// 如果已经有RefreshToken,直接获取AccessToken
|
// 如果已经有RefreshToken,直接获取AccessToken
|
||||||
if d.Addition.RefreshToken != "" {
|
if d.Addition.RefreshToken != "" {
|
||||||
// 使用 oauth2 刷新令牌
|
if d.RefreshTokenMethod == "oauth2" {
|
||||||
// 初始化 oauth2Token
|
// 使用 oauth2 刷新令牌
|
||||||
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
|
// 初始化 oauth2Token
|
||||||
return oauth2Config.TokenSource(ctx, &oauth2.Token{
|
d.initializeOAuth2Token(ctx, oauth2Config, d.Addition.RefreshToken)
|
||||||
RefreshToken: d.Addition.RefreshToken,
|
if err := d.refreshTokenByOAuth2(); err != nil {
|
||||||
}).Token()
|
return err
|
||||||
}))
|
}
|
||||||
|
} else {
|
||||||
|
if err := d.refreshToken(d.Addition.RefreshToken); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 如果没有填写RefreshToken,尝试登录 获取 refreshToken
|
// 如果没有填写RefreshToken,尝试登录 获取 refreshToken
|
||||||
if err := d.login(); err != nil {
|
if err := d.login(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
|
if d.RefreshTokenMethod == "oauth2" {
|
||||||
return oauth2Config.TokenSource(ctx, &oauth2.Token{
|
d.initializeOAuth2Token(ctx, oauth2Config, d.RefreshToken)
|
||||||
RefreshToken: d.RefreshToken,
|
}
|
||||||
}).Token()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := d.oauth2Token.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
d.RefreshToken = token.RefreshToken
|
|
||||||
d.AccessToken = token.AccessToken
|
|
||||||
|
|
||||||
// 获取CaptchaToken
|
// 获取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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户ID
|
|
||||||
userID := token.Extra("sub").(string)
|
|
||||||
if userID != "" {
|
|
||||||
d.Common.SetUserID(userID)
|
|
||||||
}
|
|
||||||
// 更新UserAgent
|
// 更新UserAgent
|
||||||
if d.Platform == "android" {
|
if d.Platform == "android" {
|
||||||
d.Common.UserAgent = BuildCustomUserAgent(utils.GetMD5EncodeStr(d.Username+d.Password), AndroidClientID, AndroidPackageName, AndroidSdkVersion, AndroidClientVersion, AndroidPackageName, d.Common.UserID)
|
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
|
// 保存 有效的 RefreshToken
|
||||||
d.Addition.RefreshToken = d.RefreshToken
|
d.Addition.RefreshToken = d.RefreshToken
|
||||||
op.MustSaveDriverStorage(d)
|
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
|
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) {
|
func (d *PikPak) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||||
var resp File
|
var resp File
|
||||||
|
var url string
|
||||||
queryParams := map[string]string{
|
queryParams := map[string]string{
|
||||||
"_magic": "2021",
|
"_magic": "2021",
|
||||||
"usage": "FETCH",
|
"usage": "FETCH",
|
||||||
@ -169,14 +181,22 @@ func (d *PikPak) Link(ctx context.Context, file model.Obj, args model.LinkArgs)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
link := model.Link{
|
url = resp.WebContentLink
|
||||||
URL: resp.WebContentLink,
|
|
||||||
}
|
|
||||||
if !d.DisableMediaLink && len(resp.Medias) > 0 && resp.Medias[0].Link.Url != "" {
|
if !d.DisableMediaLink && len(resp.Medias) > 0 && resp.Medias[0].Link.Url != "" {
|
||||||
log.Debugln("use media link")
|
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 {
|
func (d *PikPak) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
||||||
|
@ -7,13 +7,16 @@ import (
|
|||||||
|
|
||||||
type Addition struct {
|
type Addition struct {
|
||||||
driver.RootID
|
driver.RootID
|
||||||
Username string `json:"username" required:"true"`
|
Username string `json:"username" required:"true"`
|
||||||
Password string `json:"password" 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:""`
|
RefreshToken string `json:"refresh_token" required:"true" default:""`
|
||||||
CaptchaToken string `json:"captcha_token" default:""`
|
RefreshTokenMethod string `json:"refresh_token_method" required:"true" type:"select" options:"oauth2,http"`
|
||||||
DeviceID string `json:"device_id" required:"false" default:""`
|
CaptchaToken string `json:"captcha_token" default:""`
|
||||||
DisableMediaLink bool `json:"disable_media_link" default:"true"`
|
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{
|
var config = driver.Config{
|
||||||
|
@ -2,6 +2,7 @@ package pikpak
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@ -13,6 +14,7 @@ import (
|
|||||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -28,21 +30,14 @@ import (
|
|||||||
// do others that not defined in Driver interface
|
// do others that not defined in Driver interface
|
||||||
|
|
||||||
var AndroidAlgorithms = []string{
|
var AndroidAlgorithms = []string{
|
||||||
"Gez0T9ijiI9WCeTsKSg3SMlx",
|
"aDhgaSE3MsjROCmpmsWqP1sJdFJ",
|
||||||
"zQdbalsolyb1R/",
|
"+oaVkqdd8MJuKT+uMr2AYKcd9tdWge3XPEPR2hcePUknd",
|
||||||
"ftOjr52zt51JD68C3s",
|
"u/sd2GgT2fTytRcKzGicHodhvIltMntA3xKw2SRv7S48OdnaQIS5mn",
|
||||||
"yeOBMH0JkbQdEFNNwQ0RI9T3wU/v",
|
"2WZiae2QuqTOxBKaaqCNHCW3olu2UImelkDzBn",
|
||||||
"BRJrQZiTQ65WtMvwO",
|
"/vJ3upic39lgmrkX855Qx",
|
||||||
"je8fqxKPdQVJiy1DM6Bc9Nb1",
|
"yNc9ruCVMV7pGV7XvFeuLMOcy1",
|
||||||
"niV",
|
"4FPq8mT3JQ1jzcVxMVfwFftLQm33M7i",
|
||||||
"9hFCW2R1",
|
"xozoy5e3Ea",
|
||||||
"sHKHpe2i96",
|
|
||||||
"p7c5E6AcXQ/IJUuAEC9W6",
|
|
||||||
"",
|
|
||||||
"aRv9hjc9P+Pbn+u3krN6",
|
|
||||||
"BzStcgE8qVdqjEH16l4",
|
|
||||||
"SqgeZvL5j9zoHP95xWHt",
|
|
||||||
"zVof5yaJkPe3VFpadPof",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var WebAlgorithms = []string{
|
var WebAlgorithms = []string{
|
||||||
@ -63,6 +58,19 @@ var WebAlgorithms = []string{
|
|||||||
"NhXXU9rg4XXdzo7u5o",
|
"NhXXU9rg4XXdzo7u5o",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var PCAlgorithms = []string{
|
||||||
|
"KHBJ07an7ROXDoK7Db",
|
||||||
|
"G6n399rSWkl7WcQmw5rpQInurc1DkLmLJqE",
|
||||||
|
"JZD1A3M4x+jBFN62hkr7VDhkkZxb9g3rWqRZqFAAb",
|
||||||
|
"fQnw/AmSlbbI91Ik15gpddGgyU7U",
|
||||||
|
"/Dv9JdPYSj3sHiWjouR95NTQff",
|
||||||
|
"yGx2zuTjbWENZqecNI+edrQgqmZKP",
|
||||||
|
"ljrbSzdHLwbqcRn",
|
||||||
|
"lSHAsqCkGDGxQqqwrVu",
|
||||||
|
"TsWXI81fD1",
|
||||||
|
"vk7hBjawK/rOSrSWajtbMk95nfgf3",
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OSSUserAgent = "aliyun-sdk-android/2.9.13(Linux/Android 14/M2004j7ac;UKQ1.231108.001)"
|
OSSUserAgent = "aliyun-sdk-android/2.9.13(Linux/Android 14/M2004j7ac;UKQ1.231108.001)"
|
||||||
OssSecurityTokenHeaderName = "X-OSS-Security-Token"
|
OssSecurityTokenHeaderName = "X-OSS-Security-Token"
|
||||||
@ -72,16 +80,59 @@ const (
|
|||||||
const (
|
const (
|
||||||
AndroidClientID = "YNxT9w7GMdWvEOKa"
|
AndroidClientID = "YNxT9w7GMdWvEOKa"
|
||||||
AndroidClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
AndroidClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||||
AndroidClientVersion = "1.47.1"
|
AndroidClientVersion = "1.48.3"
|
||||||
AndroidPackageName = "com.pikcloud.pikpak"
|
AndroidPackageName = "com.pikcloud.pikpak"
|
||||||
AndroidSdkVersion = "2.0.4.204000"
|
AndroidSdkVersion = "2.0.4.204101"
|
||||||
WebClientID = "YUMx5nI8ZU8Ap8pm"
|
WebClientID = "YUMx5nI8ZU8Ap8pm"
|
||||||
WebClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
WebClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||||
WebClientVersion = "2.0.0"
|
WebClientVersion = "2.0.0"
|
||||||
WebPackageName = "mypikpak.com"
|
WebPackageName = "mypikpak.com"
|
||||||
WebSdkVersion = "8.0.3"
|
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 {
|
func (d *PikPak) login() error {
|
||||||
url := "https://user.mypikpak.com/v1/auth/signin"
|
url := "https://user.mypikpak.com/v1/auth/signin"
|
||||||
// 使用 用户填写的 CaptchaToken —————— (验证后的captcha_token)
|
// 使用 用户填写的 CaptchaToken —————— (验证后的captcha_token)
|
||||||
@ -112,39 +163,63 @@ func (d *PikPak) login() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (d *PikPak) refreshToken() error {
|
func (d *PikPak) refreshToken(refreshToken string) error {
|
||||||
// url := "https://user.mypikpak.com/v1/auth/token"
|
url := "https://user.mypikpak.com/v1/auth/token"
|
||||||
// var e ErrResp
|
var e ErrResp
|
||||||
// res, err := base.RestyClient.SetRetryCount(1).R().SetError(&e).
|
res, err := base.RestyClient.SetRetryCount(1).R().SetError(&e).
|
||||||
// SetHeader("user-agent", "").SetBody(base.Json{
|
SetHeader("user-agent", "").SetBody(base.Json{
|
||||||
// "client_id": ClientID,
|
"client_id": d.ClientID,
|
||||||
// "client_secret": ClientSecret,
|
"client_secret": d.ClientSecret,
|
||||||
// "grant_type": "refresh_token",
|
"grant_type": "refresh_token",
|
||||||
// "refresh_token": d.RefreshToken,
|
"refresh_token": refreshToken,
|
||||||
// }).SetQueryParam("client_id", ClientID).Post(url)
|
}).SetQueryParam("client_id", d.ClientID).Post(url)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// d.Status = err.Error()
|
d.Status = err.Error()
|
||||||
// op.MustSaveDriverStorage(d)
|
op.MustSaveDriverStorage(d)
|
||||||
// return err
|
return err
|
||||||
// }
|
}
|
||||||
// if e.ErrorCode != 0 {
|
if e.ErrorCode != 0 {
|
||||||
// if e.ErrorCode == 4126 {
|
if e.ErrorCode == 4126 {
|
||||||
// // refresh_token invalid, re-login
|
// refresh_token invalid, re-login
|
||||||
// return d.login()
|
return d.login()
|
||||||
// }
|
}
|
||||||
// d.Status = e.Error()
|
d.Status = e.Error()
|
||||||
// op.MustSaveDriverStorage(d)
|
op.MustSaveDriverStorage(d)
|
||||||
// return errors.New(e.Error())
|
return errors.New(e.Error())
|
||||||
// }
|
}
|
||||||
// data := res.Body()
|
data := res.Body()
|
||||||
// d.Status = "work"
|
d.Status = "work"
|
||||||
// d.RefreshToken = jsoniter.Get(data, "refresh_token").ToString()
|
d.RefreshToken = jsoniter.Get(data, "refresh_token").ToString()
|
||||||
// d.AccessToken = jsoniter.Get(data, "access_token").ToString()
|
d.AccessToken = jsoniter.Get(data, "access_token").ToString()
|
||||||
// d.Common.SetUserID(jsoniter.Get(data, "sub").ToString())
|
d.Common.SetUserID(jsoniter.Get(data, "sub").ToString())
|
||||||
// d.Addition.RefreshToken = d.RefreshToken
|
d.Addition.RefreshToken = d.RefreshToken
|
||||||
// op.MustSaveDriverStorage(d)
|
op.MustSaveDriverStorage(d)
|
||||||
// return nil
|
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) {
|
func (d *PikPak) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||||
req := base.RestyClient.R()
|
req := base.RestyClient.R()
|
||||||
@ -154,13 +229,15 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
|
|||||||
"X-Device-ID": d.GetDeviceID(),
|
"X-Device-ID": d.GetDeviceID(),
|
||||||
"X-Captcha-Token": d.GetCaptchaToken(),
|
"X-Captcha-Token": d.GetCaptchaToken(),
|
||||||
})
|
})
|
||||||
if d.oauth2Token != nil {
|
if d.RefreshTokenMethod == "oauth2" {
|
||||||
// 使用oauth2 获取 access_token
|
// 使用oauth2 获取 access_token
|
||||||
token, err := d.oauth2Token.Token()
|
token, err := d.oauth2Token.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken)
|
req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken)
|
||||||
|
} else {
|
||||||
|
req.SetHeader("Authorization", "Bearer "+d.AccessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
@ -181,22 +258,19 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
|
|||||||
return res.Body(), nil
|
return res.Body(), nil
|
||||||
case 4122, 4121, 16:
|
case 4122, 4121, 16:
|
||||||
// access_token 过期
|
// access_token 过期
|
||||||
|
if d.RefreshTokenMethod == "oauth2" {
|
||||||
//if err1 := d.refreshToken(); err1 != nil {
|
if err1 := d.refreshTokenByOAuth2(); err1 != nil {
|
||||||
// return nil, err1
|
return nil, err1
|
||||||
//}
|
}
|
||||||
t, err := d.oauth2Token.Token()
|
} else {
|
||||||
if err != nil {
|
if err1 := d.refreshToken(d.RefreshToken); err1 != nil {
|
||||||
return nil, err
|
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)
|
return d.request(url, method, callback, resp)
|
||||||
case 9: // 验证码token过期
|
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 nil, err
|
||||||
}
|
}
|
||||||
return d.request(url, method, callback, resp)
|
return d.request(url, method, callback, resp)
|
||||||
@ -254,6 +328,7 @@ type Common struct {
|
|||||||
UserAgent string
|
UserAgent string
|
||||||
// 验证码token刷新成功回调
|
// 验证码token刷新成功回调
|
||||||
RefreshCTokenCk func(token string)
|
RefreshCTokenCk func(token string)
|
||||||
|
LowLatencyAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateDeviceSign(deviceID, packageName string) string {
|
func generateDeviceSign(deviceID, packageName string) string {
|
||||||
@ -337,6 +412,10 @@ func (c *Common) GetDeviceID() string {
|
|||||||
return c.DeviceID
|
return c.DeviceID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Common) GetUserID() string {
|
||||||
|
return c.UserID
|
||||||
|
}
|
||||||
|
|
||||||
// RefreshCaptchaTokenAtLogin 刷新验证码token(登录后)
|
// RefreshCaptchaTokenAtLogin 刷新验证码token(登录后)
|
||||||
func (d *PikPak) RefreshCaptchaTokenAtLogin(action, userID string) error {
|
func (d *PikPak) RefreshCaptchaTokenAtLogin(action, userID string) error {
|
||||||
metas := map[string]string{
|
metas := map[string]string{
|
||||||
@ -640,3 +719,46 @@ func OssOption(params *S3Params) []oss.Option {
|
|||||||
}
|
}
|
||||||
return options
|
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"
|
"context"
|
||||||
"github.com/alist-org/alist/v3/internal/op"
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/internal/driver"
|
"github.com/alist-org/alist/v3/internal/driver"
|
||||||
@ -36,6 +37,7 @@ func (d *PikPakShare) Init(ctx context.Context) error {
|
|||||||
d.Common.CaptchaToken = token
|
d.Common.CaptchaToken = token
|
||||||
op.MustSaveDriverStorage(d)
|
op.MustSaveDriverStorage(d)
|
||||||
},
|
},
|
||||||
|
LowLatencyAddr: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +62,21 @@ func (d *PikPakShare) Init(ctx context.Context) error {
|
|||||||
d.PackageName = WebPackageName
|
d.PackageName = WebPackageName
|
||||||
d.Algorithms = WebAlgorithms
|
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"
|
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
|
// 获取CaptchaToken
|
||||||
@ -71,6 +88,7 @@ func (d *PikPakShare) Init(ctx context.Context) error {
|
|||||||
if d.SharePwd != "" {
|
if d.SharePwd != "" {
|
||||||
return d.getSharePassToken()
|
return d.getSharePassToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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)
|
var _ driver.Driver = (*PikPakShare)(nil)
|
||||||
|
@ -7,11 +7,13 @@ import (
|
|||||||
|
|
||||||
type Addition struct {
|
type Addition struct {
|
||||||
driver.RootID
|
driver.RootID
|
||||||
ShareId string `json:"share_id" required:"true"`
|
ShareId string `json:"share_id" required:"true"`
|
||||||
SharePwd string `json:"share_pwd"`
|
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:""`
|
DeviceID string `json:"device_id" required:"false" default:""`
|
||||||
UseTransCodingAddress bool `json:"use_transcoding_address" required:"true" default:"false"`
|
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{
|
var config = driver.Config{
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/drivers/base"
|
"github.com/alist-org/alist/v3/drivers/base"
|
||||||
@ -17,21 +18,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var AndroidAlgorithms = []string{
|
var AndroidAlgorithms = []string{
|
||||||
"Gez0T9ijiI9WCeTsKSg3SMlx",
|
"aDhgaSE3MsjROCmpmsWqP1sJdFJ",
|
||||||
"zQdbalsolyb1R/",
|
"+oaVkqdd8MJuKT+uMr2AYKcd9tdWge3XPEPR2hcePUknd",
|
||||||
"ftOjr52zt51JD68C3s",
|
"u/sd2GgT2fTytRcKzGicHodhvIltMntA3xKw2SRv7S48OdnaQIS5mn",
|
||||||
"yeOBMH0JkbQdEFNNwQ0RI9T3wU/v",
|
"2WZiae2QuqTOxBKaaqCNHCW3olu2UImelkDzBn",
|
||||||
"BRJrQZiTQ65WtMvwO",
|
"/vJ3upic39lgmrkX855Qx",
|
||||||
"je8fqxKPdQVJiy1DM6Bc9Nb1",
|
"yNc9ruCVMV7pGV7XvFeuLMOcy1",
|
||||||
"niV",
|
"4FPq8mT3JQ1jzcVxMVfwFftLQm33M7i",
|
||||||
"9hFCW2R1",
|
"xozoy5e3Ea",
|
||||||
"sHKHpe2i96",
|
|
||||||
"p7c5E6AcXQ/IJUuAEC9W6",
|
|
||||||
"",
|
|
||||||
"aRv9hjc9P+Pbn+u3krN6",
|
|
||||||
"BzStcgE8qVdqjEH16l4",
|
|
||||||
"SqgeZvL5j9zoHP95xWHt",
|
|
||||||
"zVof5yaJkPe3VFpadPof",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var WebAlgorithms = []string{
|
var WebAlgorithms = []string{
|
||||||
@ -52,19 +46,75 @@ var WebAlgorithms = []string{
|
|||||||
"NhXXU9rg4XXdzo7u5o",
|
"NhXXU9rg4XXdzo7u5o",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var PCAlgorithms = []string{
|
||||||
|
"KHBJ07an7ROXDoK7Db",
|
||||||
|
"G6n399rSWkl7WcQmw5rpQInurc1DkLmLJqE",
|
||||||
|
"JZD1A3M4x+jBFN62hkr7VDhkkZxb9g3rWqRZqFAAb",
|
||||||
|
"fQnw/AmSlbbI91Ik15gpddGgyU7U",
|
||||||
|
"/Dv9JdPYSj3sHiWjouR95NTQff",
|
||||||
|
"yGx2zuTjbWENZqecNI+edrQgqmZKP",
|
||||||
|
"ljrbSzdHLwbqcRn",
|
||||||
|
"lSHAsqCkGDGxQqqwrVu",
|
||||||
|
"TsWXI81fD1",
|
||||||
|
"vk7hBjawK/rOSrSWajtbMk95nfgf3",
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AndroidClientID = "YNxT9w7GMdWvEOKa"
|
AndroidClientID = "YNxT9w7GMdWvEOKa"
|
||||||
AndroidClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
AndroidClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||||
AndroidClientVersion = "1.47.1"
|
AndroidClientVersion = "1.48.3"
|
||||||
AndroidPackageName = "com.pikcloud.pikpak"
|
AndroidPackageName = "com.pikcloud.pikpak"
|
||||||
AndroidSdkVersion = "2.0.4.204000"
|
AndroidSdkVersion = "2.0.4.204101"
|
||||||
WebClientID = "YUMx5nI8ZU8Ap8pm"
|
WebClientID = "YUMx5nI8ZU8Ap8pm"
|
||||||
WebClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
WebClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
|
||||||
WebClientVersion = "2.0.0"
|
WebClientVersion = "2.0.0"
|
||||||
WebPackageName = "mypikpak.com"
|
WebPackageName = "mypikpak.com"
|
||||||
WebSdkVersion = "8.0.3"
|
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) {
|
func (d *PikPakShare) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||||
req := base.RestyClient.R()
|
req := base.RestyClient.R()
|
||||||
req.SetHeaders(map[string]string{
|
req.SetHeaders(map[string]string{
|
||||||
@ -177,6 +227,7 @@ type Common struct {
|
|||||||
UserAgent string
|
UserAgent string
|
||||||
// 验证码token刷新成功回调
|
// 验证码token刷新成功回调
|
||||||
RefreshCTokenCk func(token string)
|
RefreshCTokenCk func(token string)
|
||||||
|
LowLatencyAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Common) SetUserAgent(userAgent 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)
|
d.Common.SetCaptchaToken(resp.CaptchaToken)
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
17
go.mod
17
go.mod
@ -14,7 +14,7 @@ require (
|
|||||||
github.com/blevesearch/bleve/v2 v2.4.2
|
github.com/blevesearch/bleve/v2 v2.4.2
|
||||||
github.com/caarlos0/env/v9 v9.0.0
|
github.com/caarlos0/env/v9 v9.0.0
|
||||||
github.com/charmbracelet/bubbles v0.19.0
|
github.com/charmbracelet/bubbles v0.19.0
|
||||||
github.com/charmbracelet/bubbletea v0.27.0
|
github.com/charmbracelet/bubbletea v1.1.0
|
||||||
github.com/charmbracelet/lipgloss v0.13.0
|
github.com/charmbracelet/lipgloss v0.13.0
|
||||||
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e
|
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e
|
||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||||
@ -42,7 +42,7 @@ require (
|
|||||||
github.com/meilisearch/meilisearch-go v0.27.2
|
github.com/meilisearch/meilisearch-go v0.27.2
|
||||||
github.com/minio/sio v0.4.0
|
github.com/minio/sio v0.4.0
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
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/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pkg/sftp v1.13.6
|
github.com/pkg/sftp v1.13.6
|
||||||
@ -59,7 +59,7 @@ require (
|
|||||||
github.com/xhofe/wopan-sdk-go v0.1.3
|
github.com/xhofe/wopan-sdk-go v0.1.3
|
||||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
||||||
golang.org/x/crypto v0.26.0
|
golang.org/x/crypto v0.26.0
|
||||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
|
||||||
golang.org/x/image v0.19.0
|
golang.org/x/image v0.19.0
|
||||||
golang.org/x/net v0.28.0
|
golang.org/x/net v0.28.0
|
||||||
golang.org/x/oauth2 v0.22.0
|
golang.org/x/oauth2 v0.22.0
|
||||||
@ -77,16 +77,13 @@ require (
|
|||||||
github.com/blevesearch/go-faiss v1.0.20 // indirect
|
github.com/blevesearch/go-faiss v1.0.20 // indirect
|
||||||
github.com/blevesearch/zapx/v16 v16.1.5 // indirect
|
github.com/blevesearch/zapx/v16 v16.1.5 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.1.4 // indirect
|
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
||||||
github.com/charmbracelet/x/input v0.1.0 // indirect
|
github.com/charmbracelet/x/term v0.2.0 // indirect
|
||||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
|
||||||
github.com/charmbracelet/x/windows v0.1.0 // indirect
|
|
||||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/ipfs/boxo v0.12.0 // indirect
|
github.com/ipfs/boxo v0.12.0 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -225,8 +222,8 @@ require (
|
|||||||
golang.org/x/text v0.17.0 // indirect
|
golang.org/x/text v0.17.0 // indirect
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
google.golang.org/api v0.169.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/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
||||||
google.golang.org/grpc v1.65.0
|
google.golang.org/grpc v1.66.0
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||||
|
34
go.sum
34
go.sum
@ -98,20 +98,16 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
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 h1:gKZkKXPP6GlDk6EcfujDK19PCQqRjaJZQ7QRERx1UF0=
|
||||||
github.com/charmbracelet/bubbles v0.19.0/go.mod h1:WILteEqZ+krG5c3ntGEMeG99nCupcuIk7V0/zOP0tOA=
|
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 v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c=
|
||||||
github.com/charmbracelet/bubbletea v0.27.0/go.mod h1:5MdP9XH6MbQkgGhnlxUqCNmBXf9I74KRQ8HIidRxV1Y=
|
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 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
|
||||||
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
|
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.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY=
|
||||||
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
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 h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q=
|
||||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
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/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
|
||||||
github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28=
|
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
|
||||||
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/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
|
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/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=
|
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e h1:GLC8iDDcbt1H8+RkNao2nRGjyNTIo81e1rAJT9/uWYA=
|
||||||
@ -385,8 +381,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/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 h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
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.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
|
||||||
github.com/ncw/swift/v2 v2.0.2/go.mod h1:z0A9RVdYPjNjXVo2pDOPxZ4eu3oarO1P91fTItcb+Kg=
|
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 h1:K3T3eu4h5aYIOzUtLjN08L4Qt4WGaJONMgcaD0ayBJQ=
|
||||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831/go.mod h1:lSHD4lC4zlMl+zcoysdJcd5KFzsWwOD8BJbyg1Ws9Ng=
|
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=
|
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
|
||||||
@ -512,8 +508,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/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 h1:J58X6v+n25ewBZjb05pKOr7AWGohb+Rdll4CThGh6+A=
|
||||||
github.com/xhofe/wopan-sdk-go v0.1.3/go.mod h1:dcY9yA28fnaoZPnXZiVTFSkcd7GnIPTpTIIlfSI5z5Q=
|
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.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/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=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
@ -554,8 +548,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
|
|||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
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 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
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-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
||||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
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.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 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||||
@ -681,10 +675,10 @@ 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.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
|
||||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
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-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
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-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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
@ -102,7 +102,13 @@ func initURL() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CleanTempDir() {
|
func CleanTempDir() {
|
||||||
if err := os.RemoveAll(conf.Conf.TempDir); err != nil {
|
files, err := os.ReadDir(conf.Conf.TempDir)
|
||||||
log.Errorln("failed delete temp file: ", err)
|
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
|
sendSize := size
|
||||||
var sendContent io.ReadCloser
|
var sendContent io.ReadCloser
|
||||||
ranges, err := http_range.ParseRange(rangeReq, size)
|
ranges, err := http_range.ParseRange(rangeReq, size)
|
||||||
switch err {
|
switch {
|
||||||
case nil:
|
case err == nil:
|
||||||
case http_range.ErrNoOverlap:
|
case errors.Is(err, http_range.ErrNoOverlap):
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
// Some clients add a Range header to all requests to
|
// Some clients add a Range header to all requests to
|
||||||
// limit the size of the response. If the file is empty,
|
// 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
|
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
|
// 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.
|
// or unknown file size, ignore the range request.
|
||||||
ranges = nil
|
ranges = nil
|
||||||
@ -174,6 +174,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, name string, modTime time
|
|||||||
pw.Close()
|
pw.Close()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
defer sendContent.Close()
|
||||||
|
|
||||||
w.Header().Set("Accept-Ranges", "bytes")
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
if w.Header().Get("Content-Encoding") == "" {
|
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)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//defer sendContent.Close()
|
|
||||||
}
|
}
|
||||||
func ProcessHeader(origin, override http.Header) http.Header {
|
func ProcessHeader(origin, override http.Header) http.Header {
|
||||||
result := 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
|
return link, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if storage.Config().OnlyLocal {
|
||||||
|
link, err := fn()
|
||||||
|
return link, file, err
|
||||||
|
}
|
||||||
|
|
||||||
link, err, _ := linkG.Do(key, fn)
|
link, err, _ := linkG.Do(key, fn)
|
||||||
return link, file, err
|
return link, file, err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user