feat: add pikpak offline download function (#6648)

* add pikpak offline download function

* 完善PikPak离线下载功能

* 删除多余的代码

* add task cache to avoid too many requests about API

* 优化Status函数

* 完善所有功能,目前测试无BUG

* 减少缓存时间,优化添加离线任务的参数
This commit is contained in:
Muione
2024-07-07 16:50:05 +08:00
committed by GitHub
parent ca30849e24
commit 3a3d0adfa0
7 changed files with 339 additions and 3 deletions

View File

@ -2,8 +2,10 @@ package pikpak
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/alist-org/alist/v3/drivers/base"
@ -207,4 +209,92 @@ func (d *PikPak) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
return err
}
// 离线下载文件
func (d *PikPak) OfflineDownload(ctx context.Context, fileUrl string, parentDir model.Obj, fileName string) (*OfflineTask, error) {
requestBody := base.Json{
"kind": "drive#file",
"name": fileName,
"upload_type": "UPLOAD_TYPE_URL",
"url": base.Json{
"url": fileUrl,
},
"parent_id": parentDir.GetID(),
"folder_type": "",
}
var resp OfflineDownloadResp
_, err := d.request("https://api-drive.mypikpak.com/drive/v1/files", http.MethodPost, func(req *resty.Request) {
req.SetBody(requestBody)
}, &resp)
if err != nil {
return nil, err
}
return &resp.Task, err
}
/*
获取离线下载任务列表
phase 可能的取值:
PHASE_TYPE_RUNNING, PHASE_TYPE_ERROR, PHASE_TYPE_COMPLETE, PHASE_TYPE_PENDING
*/
func (d *PikPak) OfflineList(ctx context.Context, nextPageToken string, phase []string) ([]OfflineTask, error) {
res := make([]OfflineTask, 0)
url := "https://api-drive.mypikpak.com/drive/v1/tasks"
if len(phase) == 0 {
phase = []string{"PHASE_TYPE_RUNNING", "PHASE_TYPE_ERROR", "PHASE_TYPE_COMPLETE", "PHASE_TYPE_PENDING"}
}
params := map[string]string{
"type": "offline",
"thumbnail_size": "SIZE_SMALL",
"limit": "10000",
"page_token": nextPageToken,
"with": "reference_resource",
}
// 处理 phase 参数
if len(phase) > 0 {
filters := base.Json{
"phase": map[string]string{
"in": strings.Join(phase, ","),
},
}
filtersJSON, err := json.Marshal(filters)
if err != nil {
return nil, fmt.Errorf("failed to marshal filters: %w", err)
}
params["filters"] = string(filtersJSON)
}
var resp OfflineListResp
_, err := d.request(url, http.MethodGet, func(req *resty.Request) {
req.SetContext(ctx).
SetQueryParams(params)
}, &resp)
if err != nil {
return nil, fmt.Errorf("failed to get offline list: %w", err)
}
res = append(res, resp.Tasks...)
return res, nil
}
func (d *PikPak) DeleteOfflineTasks(ctx context.Context, taskIDs []string, deleteFiles bool) error {
url := "https://api-drive.mypikpak.com/drive/v1/tasks"
params := map[string]string{
"task_ids": strings.Join(taskIDs, ","),
"delete_files": strconv.FormatBool(deleteFiles),
}
_, err := d.request(url, http.MethodDelete, func(req *resty.Request) {
req.SetContext(ctx).
SetQueryParams(params)
}, nil)
if err != nil {
return fmt.Errorf("failed to delete tasks %v: %w", taskIDs, err)
}
return nil
}
var _ driver.Driver = (*PikPak)(nil)

View File

@ -99,3 +99,72 @@ type UploadTaskData struct {
File File `json:"file"`
}
// 添加离线下载响应
type OfflineDownloadResp struct {
File *string `json:"file"`
Task OfflineTask `json:"task"`
UploadType string `json:"upload_type"`
URL struct {
Kind string `json:"kind"`
} `json:"url"`
}
// 离线下载列表
type OfflineListResp struct {
ExpiresIn int64 `json:"expires_in"`
NextPageToken string `json:"next_page_token"`
Tasks []OfflineTask `json:"tasks"`
}
// offlineTask
type OfflineTask struct {
Callback string `json:"callback"`
CreatedTime string `json:"created_time"`
FileID string `json:"file_id"`
FileName string `json:"file_name"`
FileSize string `json:"file_size"`
IconLink string `json:"icon_link"`
ID string `json:"id"`
Kind string `json:"kind"`
Message string `json:"message"`
Name string `json:"name"`
Params Params `json:"params"`
Phase string `json:"phase"` // PHASE_TYPE_RUNNING, PHASE_TYPE_ERROR, PHASE_TYPE_COMPLETE, PHASE_TYPE_PENDING
Progress int64 `json:"progress"`
ReferenceResource ReferenceResource `json:"reference_resource"`
Space string `json:"space"`
StatusSize int64 `json:"status_size"`
Statuses []string `json:"statuses"`
ThirdTaskID string `json:"third_task_id"`
Type string `json:"type"`
UpdatedTime string `json:"updated_time"`
UserID string `json:"user_id"`
}
type Params struct {
Age string `json:"age"`
MIMEType *string `json:"mime_type,omitempty"`
PredictType string `json:"predict_type"`
URL string `json:"url"`
}
type ReferenceResource struct {
Type string `json:"@type"`
Audit interface{} `json:"audit"`
Hash string `json:"hash"`
IconLink string `json:"icon_link"`
ID string `json:"id"`
Kind string `json:"kind"`
Medias []Media `json:"medias"`
MIMEType string `json:"mime_type"`
Name string `json:"name"`
Params map[string]interface{} `json:"params"`
ParentID string `json:"parent_id"`
Phase string `json:"phase"`
Size string `json:"size"`
Space string `json:"space"`
Starred bool `json:"starred"`
Tags []string `json:"tags"`
ThumbnailLink string `json:"thumbnail_link"`
}