From ba8edd25a71bf3f6d7c46737287061814c2d3474 Mon Sep 17 00:00:00 2001 From: AlistDev Date: Sat, 5 Jul 2025 09:48:41 +0800 Subject: [PATCH] fix: enhance file deletion handling and add option to hide uploading files and fix cloudreve refresh_token get error --- drivers/cloudreve_v4/driver.go | 61 +++++++++++++++++++++++++++++----- drivers/cloudreve_v4/meta.go | 1 + drivers/cloudreve_v4/types.go | 16 ++++++++- drivers/cloudreve_v4/util.go | 7 ++-- 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/drivers/cloudreve_v4/driver.go b/drivers/cloudreve_v4/driver.go index 32a22f62..f2beddcf 100644 --- a/drivers/cloudreve_v4/driver.go +++ b/drivers/cloudreve_v4/driver.go @@ -91,6 +91,13 @@ func (d *CloudreveV4) List(ctx context.Context, dir model.Obj, args model.ListAr break } params["next_page_token"] = r.Pagination.NextToken + + if d.HideUploading { + f = utils.SliceFilter(f, func(src File) bool { + // Filter out files that are currently being uploaded + return src.Metadata == nil || src.Metadata[MetadataUploadSessionID] == nil + }) + } } return utils.SliceConvert(f, func(src File) (model.Obj, error) { @@ -105,7 +112,7 @@ func (d *CloudreveV4) List(ctx context.Context, dir model.Obj, args model.ListAr } } var thumb model.Thumbnail - if d.EnableThumb && src.Type == 0 { + if d.EnableThumb && src.Type == 0 && src.Metadata != nil && src.Metadata[MetadataThumbDisabled] != nil { var t FileThumbResp err := d.request(http.MethodGet, "/file/thumb", func(req *resty.Request) { req.SetQueryParam("uri", src.Path) @@ -173,7 +180,7 @@ func (d *CloudreveV4) Move(ctx context.Context, srcObj, dstDir model.Obj) error } func (d *CloudreveV4) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - return d.request(http.MethodPost, "/file/create", func(req *resty.Request) { + return d.request(http.MethodPost, "/file/rename", func(req *resty.Request) { req.SetBody(base.Json{ "new_name": newName, "uri": srcObj.GetPath(), @@ -192,14 +199,52 @@ func (d *CloudreveV4) Copy(ctx context.Context, srcObj, dstDir model.Obj) error }, nil) } -func (d *CloudreveV4) Remove(ctx context.Context, obj model.Obj) error { - return d.request(http.MethodDelete, "/file", func(req *resty.Request) { - req.SetBody(base.Json{ - "uris": []string{obj.GetPath()}, +func (c *CloudreveV4) Remove(ctx context.Context, target model.Obj) error { + path := target.GetPath() + + deletePayload := func() base.Json { + return base.Json{ + "uris": []string{path}, "unlink": false, "skip_soft_delete": true, - }) - }, nil) + } + } + + var resp FileDeleteResp + del := func() error { + return c.request(http.MethodDelete, "/file", func(req *resty.Request) { + req.SetBody(deletePayload()) + req.SetResult(&resp) + }, nil) + } + + // 尝试第一次删除 + if err := del(); err != nil { + return err + } + if resp.Code == 0 { + return nil + } + + // 若存在锁冲突,则先清除锁再重试 + if resp.Code == 40073 && resp.Msg == "Lock conflict" && len(resp.Data) > 0 { + var lockTokens []string + for _, entry := range resp.Data { + lockTokens = append(lockTokens, entry.Token) + } + + // 先解锁 + if err := c.request(http.MethodDelete, "/file/lock", func(req *resty.Request) { + req.SetBody(base.Json{"tokens": lockTokens}) + }, nil); err != nil { + return err + } + + // 再次尝试删除 + return del() + } + + return errors.New(resp.Msg) } func (d *CloudreveV4) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) error { diff --git a/drivers/cloudreve_v4/meta.go b/drivers/cloudreve_v4/meta.go index bfaa14f8..089266fe 100644 --- a/drivers/cloudreve_v4/meta.go +++ b/drivers/cloudreve_v4/meta.go @@ -19,6 +19,7 @@ type Addition struct { EnableFolderSize bool `json:"enable_folder_size"` EnableThumb bool `json:"enable_thumb"` EnableVersionUpload bool `json:"enable_version_upload"` + HideUploading bool `json:"hide_uploading"` OrderBy string `json:"order_by" type:"select" options:"name,size,updated_at,created_at" default:"name" required:"true"` OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc" required:"true"` } diff --git a/drivers/cloudreve_v4/types.go b/drivers/cloudreve_v4/types.go index e81226d3..fdf06efb 100644 --- a/drivers/cloudreve_v4/types.go +++ b/drivers/cloudreve_v4/types.go @@ -6,6 +6,11 @@ import ( "github.com/alist-org/alist/v3/internal/model" ) +const ( + MetadataUploadSessionID = "sys:upload_session_id" + MetadataThumbDisabled = "thumb:disabled" +) + type Object struct { model.Object StoragePolicy StoragePolicy @@ -88,7 +93,7 @@ type File struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` Size int64 `json:"size"` - Metadata interface{} `json:"metadata"` + Metadata map[any]any `json:"metadata"` Path string `json:"path"` Capability string `json:"capability"` Owned bool `json:"owned"` @@ -147,6 +152,15 @@ type FileUploadResp struct { Credential string `json:"credential,omitempty"` // for local } +type FileDeleteResp struct { + Resp + Data []struct { + Path string `json:"path"` + Token string `json:"token"` + Type int `json:"type"` + } `json:"data,omitempty"` +} + type FileThumbResp struct { URL string `json:"url"` Expires time.Time `json:"expires"` diff --git a/drivers/cloudreve_v4/util.go b/drivers/cloudreve_v4/util.go index cf2337f2..4e57e5bd 100644 --- a/drivers/cloudreve_v4/util.go +++ b/drivers/cloudreve_v4/util.go @@ -175,8 +175,8 @@ func (d *CloudreveV4) doLogin(needCaptcha bool) error { } func (d *CloudreveV4) refreshToken() error { - var token Token - if token.RefreshToken == "" { + //var token Token + if d.RefreshToken == "" { if d.Username != "" { err := d.login() if err != nil { @@ -185,6 +185,7 @@ func (d *CloudreveV4) refreshToken() error { } return nil } + var token Token err := d.request(http.MethodPost, "/session/token/refresh", func(req *resty.Request) { req.SetBody(base.Json{ "refresh_token": d.RefreshToken, @@ -470,7 +471,7 @@ func (d *CloudreveV4) upS3(ctx context.Context, file model.FileStreamer, u FileU } // 上传成功发送回调请求 - return d.request(http.MethodPost, "/callback/s3/"+u.SessionID+"/"+u.CallbackSecret, func(req *resty.Request) { + return d.request(http.MethodGet, "/callback/s3/"+u.SessionID+"/"+u.CallbackSecret, func(req *resty.Request) { req.SetBody("{}") }, nil) }