diff --git a/drivers/pikpak/driver.go b/drivers/pikpak/driver.go index bc15f403364..4208bb8765a 100644 --- a/drivers/pikpak/driver.go +++ b/drivers/pikpak/driver.go @@ -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 == "" { @@ -128,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 } @@ -147,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", @@ -162,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 + } + + if d.UseLowLatencyAddress && d.Common.LowLatencyAddr != "" { + // 替换为加速链接 + re := regexp.MustCompile(`https://[^/]+/download/`) + url = re.ReplaceAllString(url, "https://"+d.Common.LowLatencyAddr+"/download/") } - return &link, nil + + return &model.Link{ + URL: url, + }, nil } func (d *PikPak) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { diff --git a/drivers/pikpak/meta.go b/drivers/pikpak/meta.go index 9871c6ee77d..4d25ecc605e 100644 --- a/drivers/pikpak/meta.go +++ b/drivers/pikpak/meta.go @@ -7,14 +7,16 @@ import ( 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"` - 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"` + Username string `json:"username" required:"true"` + Password string `json:"password" required:"true"` + 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{ diff --git a/drivers/pikpak/util.go b/drivers/pikpak/util.go index 6ffcae56780..cc745d520cb 100644 --- a/drivers/pikpak/util.go +++ b/drivers/pikpak/util.go @@ -30,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{ @@ -65,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" @@ -74,16 +80,59 @@ 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 { url := "https://user.mypikpak.com/v1/auth/signin" // 使用 用户填写的 CaptchaToken —————— (验证后的captcha_token) @@ -180,13 +229,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" { // 使用oauth2 获取 access_token token, err := d.oauth2Token.Token() if err != nil { return nil, err } req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken) + } else { + req.SetHeader("Authorization", "Bearer "+d.AccessToken) } if callback != nil { @@ -277,6 +328,7 @@ type Common struct { UserAgent string // 验证码token刷新成功回调 RefreshCTokenCk func(token string) + LowLatencyAddr string } func generateDeviceSign(deviceID, packageName string) string { @@ -667,3 +719,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 +} diff --git a/drivers/pikpak_share/driver.go b/drivers/pikpak_share/driver.go index 448ad2dd94a..91cb45ca1cf 100644 --- a/drivers/pikpak_share/driver.go +++ b/drivers/pikpak_share/driver.go @@ -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) diff --git a/drivers/pikpak_share/meta.go b/drivers/pikpak_share/meta.go index e6f00cdad54..dc551e028a0 100644 --- a/drivers/pikpak_share/meta.go +++ b/drivers/pikpak_share/meta.go @@ -7,11 +7,13 @@ import ( 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"` - DeviceID string `json:"device_id" required:"false" default:""` - UseTransCodingAddress bool `json:"use_transcoding_address" required:"true" default:"false"` + ShareId string `json:"share_id" required:"true"` + SharePwd string `json:"share_pwd"` + 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{ diff --git a/drivers/pikpak_share/util.go b/drivers/pikpak_share/util.go index a9c8fffe84e..f333ca5f706 100644 --- a/drivers/pikpak_share/util.go +++ b/drivers/pikpak_share/util.go @@ -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 +}