mirror of
https://github.com/AlistGo/alist.git
synced 2025-11-25 03:15:10 +08:00
* feat(bitqiu): Add Bitqiu cloud drive support - Implement the new Bitqiu cloud drive. - Add core driver logic, metadata handling, and utility functions. - Register the Bitqiu driver for use. * feat(driver): Implement GetLink, CreateDir, and Move operations - Implement `GetLink` method to retrieve download links for files. - Implement `CreateDir` method to create new directories. - Implement `Move` method to relocate files and directories. - Add new API endpoints and data structures for download and directory creation responses. - Integrate retry logic with re-authentication for API calls in implemented methods. - Update HTTP request headers to include `x-requested-with`. * feat(bitqiu): Add rename, copy, and delete operations - Implement `Rename` operation with retry logic and API calls. - Implement `Copy` operation, including asynchronous handling, polling for completion, and status checks. - Implement `Remove` operation with retry logic and API calls. - Add new API endpoint URLs for rename, copy, and delete, and a new copy success code. - Introduce `AsyncManagerData`, `AsyncTask`, and `AsyncTaskInfo` types to support async copy status monitoring. - Add utility functions `updateObjectName` and `parentPathOf` for object manipulation. - Integrate login retry mechanism for all file operations. * feat(bitqiu-upload): Implement chunked file upload support - Implement multi-part chunked upload logic for the BitQiu service. - Introduce `UploadInitData` and `ChunkUploadResponse` structs for structured API communication. - Refactor the `Save` method to orchestrate initial upload, chunked data transfer, and finalization. - Add `uploadFileInChunks` function to handle sequential uploading of file parts. - Add `completeChunkUpload` function to finalize the chunked upload process on the server. - Ensure proper temporary file cleanup using `defer tmpFile.Close()`. * feat(driver): Implement automatic root folder ID retrieval - Add `userInfoURL` constant for fetching user information. - Implement `ensureRootFolderID` function to retrieve and set the driver's root folder ID if not already present. - Integrate `ensureRootFolderID` into the driver's `Init` process. - Define `UserInfoData` struct to parse the `rootDirId` from user information responses. * feat(client): Implement configurable user agent * Introduce a configurable `UserAgent` field in the client's settings. * Add a `userAgent()` method to retrieve the user agent, prioritizing the custom setting or using a predefined default. * Apply the determined user agent to all outbound HTTP requests made by the `BitQiu` client.
103 lines
1.9 KiB
Go
103 lines
1.9 KiB
Go
package bitqiu
|
|
|
|
import (
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/alist-org/alist/v3/internal/model"
|
|
"github.com/alist-org/alist/v3/pkg/utils"
|
|
)
|
|
|
|
type Object struct {
|
|
model.Object
|
|
ParentID string
|
|
}
|
|
|
|
func (r Resource) toObject(parentID, parentPath string) (model.Obj, error) {
|
|
id := r.ResourceID
|
|
if id == "" {
|
|
id = r.ResourceUID
|
|
}
|
|
obj := &Object{
|
|
Object: model.Object{
|
|
ID: id,
|
|
Name: r.Name,
|
|
IsFolder: r.ResourceType == 1,
|
|
},
|
|
ParentID: parentID,
|
|
}
|
|
if r.Size != nil {
|
|
if size, err := (*r.Size).Int64(); err == nil {
|
|
obj.Size = size
|
|
}
|
|
}
|
|
if ct := parseBitQiuTime(r.CreateTime); !ct.IsZero() {
|
|
obj.Ctime = ct
|
|
}
|
|
if mt := parseBitQiuTime(r.UpdateTime); !mt.IsZero() {
|
|
obj.Modified = mt
|
|
}
|
|
if r.FileMD5 != "" {
|
|
obj.HashInfo = utils.NewHashInfo(utils.MD5, strings.ToLower(r.FileMD5))
|
|
}
|
|
obj.SetPath(path.Join(parentPath, obj.Name))
|
|
return obj, nil
|
|
}
|
|
|
|
func parseBitQiuTime(value *string) time.Time {
|
|
if value == nil {
|
|
return time.Time{}
|
|
}
|
|
trimmed := strings.TrimSpace(*value)
|
|
if trimmed == "" {
|
|
return time.Time{}
|
|
}
|
|
if ts, err := time.ParseInLocation("2006-01-02 15:04:05", trimmed, time.Local); err == nil {
|
|
return ts
|
|
}
|
|
return time.Time{}
|
|
}
|
|
|
|
func updateObjectName(obj model.Obj, newName string) model.Obj {
|
|
newPath := path.Join(parentPathOf(obj.GetPath()), newName)
|
|
|
|
switch o := obj.(type) {
|
|
case *Object:
|
|
o.Name = newName
|
|
o.Object.Name = newName
|
|
o.SetPath(newPath)
|
|
return o
|
|
case *model.Object:
|
|
o.Name = newName
|
|
o.SetPath(newPath)
|
|
return o
|
|
}
|
|
|
|
if setter, ok := obj.(model.SetPath); ok {
|
|
setter.SetPath(newPath)
|
|
}
|
|
|
|
return &model.Object{
|
|
ID: obj.GetID(),
|
|
Path: newPath,
|
|
Name: newName,
|
|
Size: obj.GetSize(),
|
|
Modified: obj.ModTime(),
|
|
Ctime: obj.CreateTime(),
|
|
IsFolder: obj.IsDir(),
|
|
HashInfo: obj.GetHash(),
|
|
}
|
|
}
|
|
|
|
func parentPathOf(p string) string {
|
|
if p == "" {
|
|
return ""
|
|
}
|
|
dir := path.Dir(p)
|
|
if dir == "." {
|
|
return ""
|
|
}
|
|
return dir
|
|
}
|