mirror of
https://github.com/AlistGo/alist.git
synced 2025-11-25 03:15:10 +08:00
Compare commits
3 Commits
b4d9beb49c
...
3cddb6b7ed
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cddb6b7ed | ||
|
|
ce41587095 | ||
|
|
0cbc7ebc92 |
@@ -80,9 +80,10 @@ func (d *Cloud189) Link(ctx context.Context, file model.Obj, args model.LinkArgs
|
||||
}
|
||||
|
||||
func (d *Cloud189) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
||||
safeName := d.sanitizeName(dirName)
|
||||
form := map[string]string{
|
||||
"parentFolderId": parentDir.GetID(),
|
||||
"folderName": dirName,
|
||||
"folderName": safeName,
|
||||
}
|
||||
_, err := d.request("https://cloud.189.cn/api/open/file/createFolder.action", http.MethodPost, func(req *resty.Request) {
|
||||
req.SetFormData(form)
|
||||
@@ -126,9 +127,10 @@ func (d *Cloud189) Rename(ctx context.Context, srcObj model.Obj, newName string)
|
||||
idKey = "folderId"
|
||||
nameKey = "destFolderName"
|
||||
}
|
||||
safeName := d.sanitizeName(newName)
|
||||
form := map[string]string{
|
||||
idKey: srcObj.GetID(),
|
||||
nameKey: newName,
|
||||
nameKey: safeName,
|
||||
}
|
||||
_, err := d.request(url, http.MethodPost, func(req *resty.Request) {
|
||||
req.SetFormData(form)
|
||||
|
||||
@@ -6,9 +6,10 @@ import (
|
||||
)
|
||||
|
||||
type Addition struct {
|
||||
Username string `json:"username" required:"true"`
|
||||
Password string `json:"password" required:"true"`
|
||||
Cookie string `json:"cookie" help:"Fill in the cookie if need captcha"`
|
||||
Username string `json:"username" required:"true"`
|
||||
Password string `json:"password" required:"true"`
|
||||
Cookie string `json:"cookie" help:"Fill in the cookie if need captcha"`
|
||||
StripEmoji bool `json:"strip_emoji" help:"Remove four-byte characters (e.g., emoji) before upload"`
|
||||
driver.RootID
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/alist-org/alist/v3/drivers/base"
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
@@ -222,13 +224,37 @@ func (d *Cloud189) getFiles(fileId string) ([]model.Obj, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (d *Cloud189) sanitizeName(name string) string {
|
||||
if !d.StripEmoji {
|
||||
return name
|
||||
}
|
||||
b := strings.Builder{}
|
||||
for _, r := range name {
|
||||
if utf8.RuneLen(r) == 4 {
|
||||
continue
|
||||
}
|
||||
b.WriteRune(r)
|
||||
}
|
||||
sanitized := b.String()
|
||||
if sanitized == "" {
|
||||
ext := path.Ext(name)
|
||||
if ext != "" {
|
||||
sanitized = "file" + ext
|
||||
} else {
|
||||
sanitized = "file"
|
||||
}
|
||||
}
|
||||
return sanitized
|
||||
}
|
||||
|
||||
func (d *Cloud189) oldUpload(dstDir model.Obj, file model.FileStreamer) error {
|
||||
safeName := d.sanitizeName(file.GetName())
|
||||
res, err := d.client.R().SetMultipartFormData(map[string]string{
|
||||
"parentId": dstDir.GetID(),
|
||||
"sessionKey": "??",
|
||||
"opertype": "1",
|
||||
"fname": file.GetName(),
|
||||
}).SetMultipartField("Filedata", file.GetName(), file.GetMimetype(), file).Post("https://hb02.upload.cloud.189.cn/v1/DCIWebUploadAction")
|
||||
"fname": safeName,
|
||||
}).SetMultipartField("Filedata", safeName, file.GetMimetype(), file).Post("https://hb02.upload.cloud.189.cn/v1/DCIWebUploadAction")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -313,9 +339,10 @@ func (d *Cloud189) newUpload(ctx context.Context, dstDir model.Obj, file model.F
|
||||
const DEFAULT int64 = 10485760
|
||||
var count = int64(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
|
||||
|
||||
safeName := d.sanitizeName(file.GetName())
|
||||
res, err := d.uploadRequest("/person/initMultiUpload", map[string]string{
|
||||
"parentFolderId": dstDir.GetID(),
|
||||
"fileName": encode(file.GetName()),
|
||||
"fileName": encode(safeName),
|
||||
"fileSize": strconv.FormatInt(file.GetSize(), 10),
|
||||
"sliceSize": strconv.FormatInt(DEFAULT, 10),
|
||||
"lazyCheck": "1",
|
||||
|
||||
@@ -205,10 +205,11 @@ func (y *Cloud189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName s
|
||||
fullUrl += "/createFolder.action"
|
||||
|
||||
var newFolder Cloud189Folder
|
||||
safeName := y.sanitizeName(dirName)
|
||||
_, err := y.post(fullUrl, func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
req.SetQueryParams(map[string]string{
|
||||
"folderName": dirName,
|
||||
"folderName": safeName,
|
||||
"relativePath": "",
|
||||
})
|
||||
if isFamily {
|
||||
@@ -225,6 +226,7 @@ func (y *Cloud189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName s
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newFolder.Name = safeName
|
||||
return &newFolder, nil
|
||||
}
|
||||
|
||||
@@ -258,21 +260,29 @@ func (y *Cloud189PC) Rename(ctx context.Context, srcObj model.Obj, newName strin
|
||||
}
|
||||
|
||||
var newObj model.Obj
|
||||
safeName := y.sanitizeName(newName)
|
||||
switch f := srcObj.(type) {
|
||||
case *Cloud189File:
|
||||
fullUrl += "/renameFile.action"
|
||||
queryParam["fileId"] = srcObj.GetID()
|
||||
queryParam["destFileName"] = newName
|
||||
queryParam["destFileName"] = safeName
|
||||
newObj = &Cloud189File{Icon: f.Icon} // 复用预览
|
||||
case *Cloud189Folder:
|
||||
fullUrl += "/renameFolder.action"
|
||||
queryParam["folderId"] = srcObj.GetID()
|
||||
queryParam["destFolderName"] = newName
|
||||
queryParam["destFolderName"] = safeName
|
||||
newObj = &Cloud189Folder{}
|
||||
default:
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
switch obj := newObj.(type) {
|
||||
case *Cloud189File:
|
||||
obj.Name = safeName
|
||||
case *Cloud189Folder:
|
||||
obj.Name = safeName
|
||||
}
|
||||
|
||||
_, err := y.request(fullUrl, method, func(req *resty.Request) {
|
||||
req.SetContext(ctx).SetQueryParams(queryParam)
|
||||
}, nil, newObj, isFamily)
|
||||
|
||||
@@ -6,9 +6,10 @@ import (
|
||||
)
|
||||
|
||||
type Addition struct {
|
||||
Username string `json:"username" required:"true"`
|
||||
Password string `json:"password" required:"true"`
|
||||
VCode string `json:"validate_code"`
|
||||
Username string `json:"username" required:"true"`
|
||||
Password string `json:"password" required:"true"`
|
||||
VCode string `json:"validate_code"`
|
||||
StripEmoji bool `json:"strip_emoji" help:"Remove four-byte characters (e.g., emoji) before upload"`
|
||||
driver.RootID
|
||||
OrderBy string `json:"order_by" type:"select" options:"filename,filesize,lastOpTime" default:"filename"`
|
||||
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
|
||||
|
||||
@@ -12,11 +12,13 @@ import (
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/sync/semaphore"
|
||||
|
||||
@@ -57,6 +59,29 @@ const (
|
||||
CHANNEL_ID = "web_cloud.189.cn"
|
||||
)
|
||||
|
||||
func (y *Cloud189PC) sanitizeName(name string) string {
|
||||
if !y.StripEmoji {
|
||||
return name
|
||||
}
|
||||
b := strings.Builder{}
|
||||
for _, r := range name {
|
||||
if utf8.RuneLen(r) == 4 {
|
||||
continue
|
||||
}
|
||||
b.WriteRune(r)
|
||||
}
|
||||
sanitized := b.String()
|
||||
if sanitized == "" {
|
||||
ext := path.Ext(name)
|
||||
if ext != "" {
|
||||
sanitized = "file" + ext
|
||||
} else {
|
||||
sanitized = "file"
|
||||
}
|
||||
}
|
||||
return sanitized
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) SignatureHeader(url, method, params string, isFamily bool) map[string]string {
|
||||
dateOfGmt := getHttpDateStr()
|
||||
sessionKey := y.getTokenInfo().SessionKey
|
||||
@@ -475,10 +500,11 @@ func (y *Cloud189PC) refreshSession() (err error) {
|
||||
func (y *Cloud189PC) StreamUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress, isFamily bool, overwrite bool) (model.Obj, error) {
|
||||
size := file.GetSize()
|
||||
sliceSize := partSize(size)
|
||||
safeName := y.sanitizeName(file.GetName())
|
||||
|
||||
params := Params{
|
||||
"parentFolderId": dstDir.GetID(),
|
||||
"fileName": url.QueryEscape(file.GetName()),
|
||||
"fileName": url.QueryEscape(safeName),
|
||||
"fileSize": fmt.Sprint(file.GetSize()),
|
||||
"sliceSize": fmt.Sprint(sliceSize),
|
||||
"lazyCheck": "1",
|
||||
@@ -596,7 +622,8 @@ func (y *Cloud189PC) RapidUpload(ctx context.Context, dstDir model.Obj, stream m
|
||||
return nil, errors.New("invalid hash")
|
||||
}
|
||||
|
||||
uploadInfo, err := y.OldUploadCreate(ctx, dstDir.GetID(), fileMd5, stream.GetName(), fmt.Sprint(stream.GetSize()), isFamily)
|
||||
safeName := y.sanitizeName(stream.GetName())
|
||||
uploadInfo, err := y.OldUploadCreate(ctx, dstDir.GetID(), fileMd5, safeName, fmt.Sprint(stream.GetSize()), isFamily)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -615,6 +642,7 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
||||
tmpF *os.File
|
||||
err error
|
||||
)
|
||||
safeName := y.sanitizeName(file.GetName())
|
||||
size := file.GetSize()
|
||||
if _, ok := cache.(io.ReaderAt); !ok && size > 0 {
|
||||
tmpF, err = os.CreateTemp(conf.Conf.TempDir, "file-*")
|
||||
@@ -697,7 +725,7 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
||||
//step.2 预上传
|
||||
params := Params{
|
||||
"parentFolderId": dstDir.GetID(),
|
||||
"fileName": url.QueryEscape(file.GetName()),
|
||||
"fileName": url.QueryEscape(safeName),
|
||||
"fileSize": fmt.Sprint(file.GetSize()),
|
||||
"fileMd5": fileMd5Hex,
|
||||
"sliceSize": fmt.Sprint(sliceSize),
|
||||
@@ -833,9 +861,10 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
||||
return nil, err
|
||||
}
|
||||
rateLimited := driver.NewLimitedUploadStream(ctx, io.NopCloser(tempFile))
|
||||
safeName := y.sanitizeName(file.GetName())
|
||||
|
||||
// 创建上传会话
|
||||
uploadInfo, err := y.OldUploadCreate(ctx, dstDir.GetID(), fileMd5, file.GetName(), fmt.Sprint(file.GetSize()), isFamily)
|
||||
uploadInfo, err := y.OldUploadCreate(ctx, dstDir.GetID(), fileMd5, safeName, fmt.Sprint(file.GetSize()), isFamily)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
_ "github.com/alist-org/alist/v3/drivers/dropbox"
|
||||
_ "github.com/alist-org/alist/v3/drivers/febbox"
|
||||
_ "github.com/alist-org/alist/v3/drivers/ftp"
|
||||
_ "github.com/alist-org/alist/v3/drivers/gitee"
|
||||
_ "github.com/alist-org/alist/v3/drivers/github"
|
||||
_ "github.com/alist-org/alist/v3/drivers/github_releases"
|
||||
_ "github.com/alist-org/alist/v3/drivers/gofile"
|
||||
|
||||
224
drivers/gitee/driver.go
Normal file
224
drivers/gitee/driver.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package gitee
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
stdpath "path"
|
||||
"strings"
|
||||
|
||||
"github.com/alist-org/alist/v3/drivers/base"
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
"github.com/alist-org/alist/v3/internal/errs"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type Gitee struct {
|
||||
model.Storage
|
||||
Addition
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func (d *Gitee) Config() driver.Config {
|
||||
return config
|
||||
}
|
||||
|
||||
func (d *Gitee) GetAddition() driver.Additional {
|
||||
return &d.Addition
|
||||
}
|
||||
|
||||
func (d *Gitee) Init(ctx context.Context) error {
|
||||
d.RootFolderPath = utils.FixAndCleanPath(d.RootFolderPath)
|
||||
d.Endpoint = strings.TrimSpace(d.Endpoint)
|
||||
if d.Endpoint == "" {
|
||||
d.Endpoint = "https://gitee.com/api/v5"
|
||||
}
|
||||
d.Endpoint = strings.TrimSuffix(d.Endpoint, "/")
|
||||
d.Owner = strings.TrimSpace(d.Owner)
|
||||
d.Repo = strings.TrimSpace(d.Repo)
|
||||
d.Token = strings.TrimSpace(d.Token)
|
||||
d.DownloadProxy = strings.TrimSpace(d.DownloadProxy)
|
||||
if d.Owner == "" || d.Repo == "" {
|
||||
return errors.New("owner and repo are required")
|
||||
}
|
||||
d.client = base.NewRestyClient().
|
||||
SetBaseURL(d.Endpoint).
|
||||
SetHeader("Accept", "application/json")
|
||||
repo, err := d.getRepo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Ref = strings.TrimSpace(d.Ref)
|
||||
if d.Ref == "" {
|
||||
d.Ref = repo.DefaultBranch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Gitee) Drop(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Gitee) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
|
||||
relPath := d.relativePath(dir.GetPath())
|
||||
contents, err := d.listContents(relPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objs := make([]model.Obj, 0, len(contents))
|
||||
for i := range contents {
|
||||
objs = append(objs, contents[i].toModelObj())
|
||||
}
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
func (d *Gitee) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||
var downloadURL string
|
||||
if obj, ok := file.(*Object); ok {
|
||||
downloadURL = obj.DownloadURL
|
||||
if downloadURL == "" {
|
||||
relPath := d.relativePath(file.GetPath())
|
||||
content, err := d.getContent(relPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if content.DownloadURL == "" {
|
||||
return nil, errors.New("empty download url")
|
||||
}
|
||||
obj.DownloadURL = content.DownloadURL
|
||||
downloadURL = content.DownloadURL
|
||||
}
|
||||
} else {
|
||||
relPath := d.relativePath(file.GetPath())
|
||||
content, err := d.getContent(relPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if content.DownloadURL == "" {
|
||||
return nil, errors.New("empty download url")
|
||||
}
|
||||
downloadURL = content.DownloadURL
|
||||
}
|
||||
url := d.applyProxy(downloadURL)
|
||||
return &model.Link{
|
||||
URL: url,
|
||||
Header: http.Header{
|
||||
"Cookie": {d.Cookie},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Gitee) newRequest() *resty.Request {
|
||||
req := d.client.R()
|
||||
if d.Token != "" {
|
||||
req.SetQueryParam("access_token", d.Token)
|
||||
}
|
||||
if d.Ref != "" {
|
||||
req.SetQueryParam("ref", d.Ref)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
func (d *Gitee) apiPath(path string) string {
|
||||
escapedOwner := url.PathEscape(d.Owner)
|
||||
escapedRepo := url.PathEscape(d.Repo)
|
||||
if path == "" {
|
||||
return fmt.Sprintf("/repos/%s/%s/contents", escapedOwner, escapedRepo)
|
||||
}
|
||||
return fmt.Sprintf("/repos/%s/%s/contents/%s", escapedOwner, escapedRepo, encodePath(path))
|
||||
}
|
||||
|
||||
func (d *Gitee) listContents(path string) ([]Content, error) {
|
||||
res, err := d.newRequest().Get(d.apiPath(path))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.IsError() {
|
||||
return nil, toErr(res)
|
||||
}
|
||||
var contents []Content
|
||||
if err := utils.Json.Unmarshal(res.Body(), &contents); err != nil {
|
||||
var single Content
|
||||
if err2 := utils.Json.Unmarshal(res.Body(), &single); err2 == nil && single.Type != "" {
|
||||
if single.Type != "dir" {
|
||||
return nil, errs.NotFolder
|
||||
}
|
||||
return []Content{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
for i := range contents {
|
||||
contents[i].Path = joinPath(path, contents[i].Name)
|
||||
}
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func (d *Gitee) getContent(path string) (*Content, error) {
|
||||
res, err := d.newRequest().Get(d.apiPath(path))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.IsError() {
|
||||
return nil, toErr(res)
|
||||
}
|
||||
var content Content
|
||||
if err := utils.Json.Unmarshal(res.Body(), &content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if content.Type == "" {
|
||||
return nil, errors.New("invalid response")
|
||||
}
|
||||
if content.Path == "" {
|
||||
content.Path = path
|
||||
}
|
||||
return &content, nil
|
||||
}
|
||||
|
||||
func (d *Gitee) relativePath(full string) string {
|
||||
full = utils.FixAndCleanPath(full)
|
||||
root := utils.FixAndCleanPath(d.RootFolderPath)
|
||||
if root == "/" {
|
||||
return strings.TrimPrefix(full, "/")
|
||||
}
|
||||
if utils.PathEqual(full, root) {
|
||||
return ""
|
||||
}
|
||||
prefix := utils.PathAddSeparatorSuffix(root)
|
||||
if strings.HasPrefix(full, prefix) {
|
||||
return strings.TrimPrefix(full, prefix)
|
||||
}
|
||||
return strings.TrimPrefix(full, "/")
|
||||
}
|
||||
|
||||
func (d *Gitee) applyProxy(raw string) string {
|
||||
if raw == "" || d.DownloadProxy == "" {
|
||||
return raw
|
||||
}
|
||||
proxy := d.DownloadProxy
|
||||
if !strings.HasSuffix(proxy, "/") {
|
||||
proxy += "/"
|
||||
}
|
||||
return proxy + strings.TrimLeft(raw, "/")
|
||||
}
|
||||
|
||||
func encodePath(p string) string {
|
||||
if p == "" {
|
||||
return ""
|
||||
}
|
||||
parts := strings.Split(p, "/")
|
||||
for i, part := range parts {
|
||||
parts[i] = url.PathEscape(part)
|
||||
}
|
||||
return strings.Join(parts, "/")
|
||||
}
|
||||
|
||||
func joinPath(base, name string) string {
|
||||
if base == "" {
|
||||
return name
|
||||
}
|
||||
return strings.TrimPrefix(stdpath.Join(base, name), "./")
|
||||
}
|
||||
29
drivers/gitee/meta.go
Normal file
29
drivers/gitee/meta.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package gitee
|
||||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
)
|
||||
|
||||
type Addition struct {
|
||||
driver.RootPath
|
||||
Endpoint string `json:"endpoint" type:"string" help:"Gitee API endpoint, default https://gitee.com/api/v5"`
|
||||
Token string `json:"token" type:"string"`
|
||||
Owner string `json:"owner" type:"string" required:"true"`
|
||||
Repo string `json:"repo" type:"string" required:"true"`
|
||||
Ref string `json:"ref" type:"string" help:"Branch, tag or commit SHA, defaults to repository default branch"`
|
||||
DownloadProxy string `json:"download_proxy" type:"string" help:"Prefix added before download URLs, e.g. https://mirror.example.com/"`
|
||||
Cookie string `json:"cookie" type:"string" help:"Cookie returned from user info request"`
|
||||
}
|
||||
|
||||
var config = driver.Config{
|
||||
Name: "Gitee",
|
||||
LocalSort: true,
|
||||
DefaultRoot: "/",
|
||||
}
|
||||
|
||||
func init() {
|
||||
op.RegisterDriver(func() driver.Driver {
|
||||
return &Gitee{}
|
||||
})
|
||||
}
|
||||
60
drivers/gitee/types.go
Normal file
60
drivers/gitee/types.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package gitee
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
)
|
||||
|
||||
type Links struct {
|
||||
Self string `json:"self"`
|
||||
Html string `json:"html"`
|
||||
}
|
||||
|
||||
type Content struct {
|
||||
Type string `json:"type"`
|
||||
Size *int64 `json:"size"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Sha string `json:"sha"`
|
||||
URL string `json:"url"`
|
||||
HtmlURL string `json:"html_url"`
|
||||
DownloadURL string `json:"download_url"`
|
||||
Links Links `json:"_links"`
|
||||
}
|
||||
|
||||
func (c Content) toModelObj() model.Obj {
|
||||
size := int64(0)
|
||||
if c.Size != nil {
|
||||
size = *c.Size
|
||||
}
|
||||
return &Object{
|
||||
Object: model.Object{
|
||||
ID: c.Path,
|
||||
Name: c.Name,
|
||||
Size: size,
|
||||
Modified: time.Unix(0, 0),
|
||||
IsFolder: c.Type == "dir",
|
||||
},
|
||||
DownloadURL: c.DownloadURL,
|
||||
HtmlURL: c.HtmlURL,
|
||||
}
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
model.Object
|
||||
DownloadURL string
|
||||
HtmlURL string
|
||||
}
|
||||
|
||||
func (o *Object) URL() string {
|
||||
return o.DownloadURL
|
||||
}
|
||||
|
||||
type Repo struct {
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
}
|
||||
|
||||
type ErrResp struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
44
drivers/gitee/util.go
Normal file
44
drivers/gitee/util.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package gitee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
func (d *Gitee) getRepo() (*Repo, error) {
|
||||
req := d.client.R()
|
||||
if d.Token != "" {
|
||||
req.SetQueryParam("access_token", d.Token)
|
||||
}
|
||||
if d.Cookie != "" {
|
||||
req.SetHeader("Cookie", d.Cookie)
|
||||
}
|
||||
escapedOwner := url.PathEscape(d.Owner)
|
||||
escapedRepo := url.PathEscape(d.Repo)
|
||||
res, err := req.Get(fmt.Sprintf("/repos/%s/%s", escapedOwner, escapedRepo))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.IsError() {
|
||||
return nil, toErr(res)
|
||||
}
|
||||
var repo Repo
|
||||
if err := utils.Json.Unmarshal(res.Body(), &repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if repo.DefaultBranch == "" {
|
||||
return nil, fmt.Errorf("failed to fetch default branch")
|
||||
}
|
||||
return &repo, nil
|
||||
}
|
||||
|
||||
func toErr(res *resty.Response) error {
|
||||
var errMsg ErrResp
|
||||
if err := utils.Json.Unmarshal(res.Body(), &errMsg); err == nil && errMsg.Message != "" {
|
||||
return fmt.Errorf("%s: %s", res.Status(), errMsg.Message)
|
||||
}
|
||||
return fmt.Errorf(res.Status())
|
||||
}
|
||||
@@ -430,17 +430,35 @@ func (d *LanZou) getFilesByShareUrl(shareID, pwd string, sharePageData string) (
|
||||
file.Time = timeFindReg.FindString(sharePageData)
|
||||
|
||||
// 重定向获取真实链接
|
||||
res, err := base.NoRedirectClient.R().SetHeaders(map[string]string{
|
||||
headers := map[string]string{
|
||||
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
||||
}).Get(downloadUrl)
|
||||
}
|
||||
res, err := base.NoRedirectClient.R().SetHeaders(headers).Get(downloadUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rPageData := res.String()
|
||||
if findAcwScV2Reg.MatchString(rPageData) {
|
||||
log.Debug("lanzou: detected acw_sc__v2 challenge, recalculating cookie")
|
||||
acwScV2, err := CalcAcwScV2(rPageData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// retry with calculated cookie to bypass anti-crawler validation
|
||||
res, err = base.NoRedirectClient.R().
|
||||
SetHeaders(headers).
|
||||
SetCookie(&http.Cookie{Name: "acw_sc__v2", Value: acwScV2}).
|
||||
Get(downloadUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rPageData = res.String()
|
||||
}
|
||||
|
||||
file.Url = res.Header().Get("location")
|
||||
|
||||
// 触发验证
|
||||
rPageData := res.String()
|
||||
if res.StatusCode() != 302 {
|
||||
param, err = htmlJsonToMap(rPageData)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user