feat(quark): add transcoding link api (#470)

This commit is contained in:
Dgs
2025-06-30 16:20:45 +08:00
committed by GitHub
parent 103abc942e
commit 3d13d5213b
4 changed files with 197 additions and 34 deletions

View File

@ -48,35 +48,18 @@ func (d *QuarkOrUC) List(ctx context.Context, dir model.Obj, args model.ListArgs
if err != nil {
return nil, err
}
return utils.SliceConvert(files, func(src File) (model.Obj, error) {
return fileToObj(src), nil
})
return files, nil
}
func (d *QuarkOrUC) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
data := base.Json{
"fids": []string{file.GetID()},
}
var resp DownResp
ua := d.conf.ua
_, err := d.request("/file/download", http.MethodPost, func(req *resty.Request) {
req.SetHeader("User-Agent", ua).
SetBody(data)
}, &resp)
if err != nil {
return nil, err
f := file.(*File)
if d.UseTransCodingAddress && d.config.Name == "Quark" && f.Category == 1 && f.Size > 0 {
return d.getTranscodingLink(file)
}
return &model.Link{
URL: resp.Data[0].DownloadUrl,
Header: http.Header{
"Cookie": []string{d.Cookie},
"Referer": []string{d.conf.referer},
"User-Agent": []string{ua},
},
Concurrency: 3,
PartSize: 10 * utils.MB,
}, nil
return d.getDownloadLink(file)
}
func (d *QuarkOrUC) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {

View File

@ -8,8 +8,10 @@ import (
type Addition struct {
Cookie string `json:"cookie" required:"true"`
driver.RootID
OrderBy string `json:"order_by" type:"select" options:"none,file_type,file_name,updated_at" default:"none"`
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
OrderBy string `json:"order_by" type:"select" options:"none,file_type,file_name,updated_at" default:"none"`
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
UseTransCodingAddress bool `json:"use_transcoding_address" help:"You can watch the transcoded video and support 302 redirection" required:"true" default:"false"`
OnlyListVideoFile bool `json:"only_list_video_file" default:"false"`
}
type Conf struct {
@ -24,7 +26,7 @@ func init() {
return &QuarkOrUC{
config: driver.Config{
Name: "Quark",
OnlyLocal: true,
OnlyLocal: false,
DefaultRoot: "0",
NoOverwriteUpload: true,
},

View File

@ -1,6 +1,7 @@
package quark
import (
"github.com/OpenListTeam/OpenList/pkg/utils"
"time"
"github.com/OpenListTeam/OpenList/internal/model"
@ -14,17 +15,19 @@ type Resp struct {
//Timestamp int `json:"timestamp"`
}
var _ model.Obj = (*File)(nil)
type File struct {
Fid string `json:"fid"`
FileName string `json:"file_name"`
//PdirFid string `json:"pdir_fid"`
//Category int `json:"category"`
Category int `json:"category"`
//FileType int `json:"file_type"`
Size int64 `json:"size"`
//FormatType string `json:"format_type"`
//Status int `json:"status"`
//Tags string `json:"tags,omitempty"`
//LCreatedAt int64 `json:"l_created_at"`
LCreatedAt int64 `json:"l_created_at"`
LUpdatedAt int64 `json:"l_updated_at"`
//NameSpace int `json:"name_space"`
//IncludeItems int `json:"include_items,omitempty"`
@ -32,8 +35,8 @@ type File struct {
//BackupSign int `json:"backup_sign"`
//Duration int `json:"duration"`
//FileSource string `json:"file_source"`
File bool `json:"file"`
//CreatedAt int64 `json:"created_at"`
File bool `json:"file"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
//PrivateExtra struct {} `json:"_private_extra"`
//ObjCategory string `json:"obj_category,omitempty"`
@ -46,10 +49,43 @@ func fileToObj(f File) *model.Object {
Name: f.FileName,
Size: f.Size,
Modified: time.UnixMilli(f.UpdatedAt),
Ctime: time.UnixMilli(f.CreatedAt),
IsFolder: !f.File,
}
}
func (f *File) GetSize() int64 {
return f.Size
}
func (f *File) GetName() string {
return f.FileName
}
func (f *File) ModTime() time.Time {
return time.UnixMilli(f.UpdatedAt)
}
func (f *File) CreateTime() time.Time {
return time.UnixMilli(f.CreatedAt)
}
func (f *File) IsDir() bool {
return !f.File
}
func (f *File) GetHash() utils.HashInfo {
return utils.HashInfo{}
}
func (f *File) GetID() string {
return f.Fid
}
func (f *File) GetPath() string {
return ""
}
type SortResp struct {
Resp
Data struct {
@ -100,6 +136,82 @@ type DownResp struct {
//} `json:"metadata"`
}
type TranscodingResp struct {
Resp
Data struct {
DefaultResolution string `json:"default_resolution"`
OriginDefaultResolution string `json:"origin_default_resolution"`
VideoList []struct {
Resolution string `json:"resolution"`
VideoInfo struct {
Duration int `json:"duration"`
Size int64 `json:"size"`
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Bitrate float64 `json:"bitrate"`
Codec string `json:"codec"`
Fps float64 `json:"fps"`
Rotate int `json:"rotate"`
Audio struct {
Duration int `json:"duration"`
Bitrate float64 `json:"bitrate"`
Codec string `json:"codec"`
Channels int `json:"channels"`
} `json:"audio"`
UpdateTime int `json:"update_time"`
URL string `json:"url"`
Resolution string `json:"resolution"`
HlsType string `json:"hls_type"`
Finish bool `json:"finish"`
Resoultion string `json:"resoultion"`
Success bool `json:"success"`
} `json:"video_info,omitempty"`
//Right string `json:"right"`
//MemberRight string `json:"member_right"`
//TransStatus string `json:"trans_status"`
//Accessable bool `json:"accessable"`
//SupportsFormat string `json:"supports_format"`
//VideoFuncType string `json:"video_func_type,omitempty"`
} `json:"video_list"`
//AudioList []interface{} `json:"audio_list"`
FileName string `json:"file_name"`
NameSpace int `json:"name_space"`
Size int64 `json:"size"`
Thumbnail string `json:"thumbnail"`
//LastPlayInfo struct {
// Time int `json:"time"`
//} `json:"last_play_info"`
//SeekPreviewData struct {
// TotalFrameCount int `json:"total_frame_count"`
// TotalSpriteCount int `json:"total_sprite_count"`
// FrameWidth int `json:"frame_width"`
// FrameHeight int `json:"frame_height"`
// SpriteRow int `json:"sprite_row"`
// SpriteColumn int `json:"sprite_column"`
// PreviewSpriteInfos []struct {
// URL string `json:"url"`
// FrameCount int `json:"frame_count"`
// Times []int `json:"times"`
// } `json:"preview_sprite_infos"`
//} `json:"seek_preview_data"`
//ObjKey string `json:"obj_key"`
//Meta struct {
// Duration int `json:"duration"`
// Size int64 `json:"size"`
// Format string `json:"format"`
// Width int `json:"width"`
// Height int `json:"height"`
// Bitrate float64 `json:"bitrate"`
// Codec string `json:"codec"`
// Fps float64 `json:"fps"`
// Rotate int `json:"rotate"`
//} `json:"meta"`
//PreloadLevel int `json:"preload_level"`
//HasSeekPreviewData bool `json:"has_seek_preview_data"`
} `json:"data"`
}
type UpPreResp struct {
Resp
Data struct {

View File

@ -50,14 +50,23 @@ func (d *QuarkOrUC) request(pathname string, method string, callback base.ReqCal
d.Cookie = cookie.SetStr(d.Cookie, "__puus", __puus.Value)
op.MustSaveDriverStorage(d)
}
if d.UseTransCodingAddress && d.config.Name == "Quark" {
__pus := cookie.GetCookie(res.Cookies(), "__pus")
if __pus != nil {
d.Cookie = cookie.SetStr(d.Cookie, "__pus", __pus.Value)
op.MustSaveDriverStorage(d)
}
}
if e.Status >= 400 || e.Code != 0 {
return nil, errors.New(e.Message)
}
return res.Body(), nil
}
func (d *QuarkOrUC) GetFiles(parent string) ([]File, error) {
files := make([]File, 0)
func (d *QuarkOrUC) GetFiles(parent string) ([]model.Obj, error) {
files := make([]model.Obj, 0)
page := 1
size := 100
query := map[string]string{
@ -77,15 +86,72 @@ func (d *QuarkOrUC) GetFiles(parent string) ([]File, error) {
if err != nil {
return nil, err
}
files = append(files, resp.Data.List...)
for _, file := range resp.Data.List {
if d.OnlyListVideoFile {
// 开启后 只列出视频文件和文件夹
if file.IsDir() || file.Category == 1 {
files = append(files, &file)
}
} else {
files = append(files, &file)
}
}
if page*size >= resp.Metadata.Total {
break
}
page++
}
return files, nil
}
func (d *QuarkOrUC) getDownloadLink(file model.Obj) (*model.Link, error) {
data := base.Json{
"fids": []string{file.GetID()},
}
var resp DownResp
ua := d.conf.ua
_, err := d.request("/file/download", http.MethodPost, func(req *resty.Request) {
req.SetHeader("User-Agent", ua).
SetBody(data)
}, &resp)
if err != nil {
return nil, err
}
return &model.Link{
URL: resp.Data[0].DownloadUrl,
Header: http.Header{
"Cookie": []string{d.Cookie},
"Referer": []string{d.conf.referer},
"User-Agent": []string{ua},
},
Concurrency: 3,
PartSize: 10 * utils.MB,
}, nil
}
func (d *QuarkOrUC) getTranscodingLink(file model.Obj) (*model.Link, error) {
data := base.Json{
"fid": file.GetID(),
"resolutions": "low,normal,high,super,2k,4k",
"supports": "fmp4_av,m3u8,dolby_vision",
}
var resp TranscodingResp
ua := d.conf.ua
_, err := d.request("/file/v2/play/project", http.MethodPost, func(req *resty.Request) {
req.SetHeader("User-Agent", ua).
SetBody(data)
}, &resp)
if err != nil {
return nil, err
}
return &model.Link{URL: resp.Data.VideoList[0].VideoInfo.URL}, nil
}
func (d *QuarkOrUC) upPre(file model.FileStreamer, parentId string) (UpPreResp, error) {
now := time.Now()
data := base.Json{