mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-09-20 12:46:17 +08:00
feat(quark): add transcoding link api (#470)
This commit is contained in:
@ -48,35 +48,18 @@ func (d *QuarkOrUC) List(ctx context.Context, dir model.Obj, args model.ListArgs
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
func (d *QuarkOrUC) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||||
data := base.Json{
|
f := file.(*File)
|
||||||
"fids": []string{file.GetID()},
|
|
||||||
}
|
if d.UseTransCodingAddress && d.config.Name == "Quark" && f.Category == 1 && f.Size > 0 {
|
||||||
var resp DownResp
|
return d.getTranscodingLink(file)
|
||||||
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{
|
return d.getDownloadLink(file)
|
||||||
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) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
func (d *QuarkOrUC) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
||||||
|
@ -10,6 +10,8 @@ type Addition struct {
|
|||||||
driver.RootID
|
driver.RootID
|
||||||
OrderBy string `json:"order_by" type:"select" options:"none,file_type,file_name,updated_at" default:"none"`
|
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"`
|
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 {
|
type Conf struct {
|
||||||
@ -24,7 +26,7 @@ func init() {
|
|||||||
return &QuarkOrUC{
|
return &QuarkOrUC{
|
||||||
config: driver.Config{
|
config: driver.Config{
|
||||||
Name: "Quark",
|
Name: "Quark",
|
||||||
OnlyLocal: true,
|
OnlyLocal: false,
|
||||||
DefaultRoot: "0",
|
DefaultRoot: "0",
|
||||||
NoOverwriteUpload: true,
|
NoOverwriteUpload: true,
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package quark
|
package quark
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/OpenListTeam/OpenList/pkg/utils"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/internal/model"
|
"github.com/OpenListTeam/OpenList/internal/model"
|
||||||
@ -14,17 +15,19 @@ type Resp struct {
|
|||||||
//Timestamp int `json:"timestamp"`
|
//Timestamp int `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ model.Obj = (*File)(nil)
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
Fid string `json:"fid"`
|
Fid string `json:"fid"`
|
||||||
FileName string `json:"file_name"`
|
FileName string `json:"file_name"`
|
||||||
//PdirFid string `json:"pdir_fid"`
|
//PdirFid string `json:"pdir_fid"`
|
||||||
//Category int `json:"category"`
|
Category int `json:"category"`
|
||||||
//FileType int `json:"file_type"`
|
//FileType int `json:"file_type"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
//FormatType string `json:"format_type"`
|
//FormatType string `json:"format_type"`
|
||||||
//Status int `json:"status"`
|
//Status int `json:"status"`
|
||||||
//Tags string `json:"tags,omitempty"`
|
//Tags string `json:"tags,omitempty"`
|
||||||
//LCreatedAt int64 `json:"l_created_at"`
|
LCreatedAt int64 `json:"l_created_at"`
|
||||||
LUpdatedAt int64 `json:"l_updated_at"`
|
LUpdatedAt int64 `json:"l_updated_at"`
|
||||||
//NameSpace int `json:"name_space"`
|
//NameSpace int `json:"name_space"`
|
||||||
//IncludeItems int `json:"include_items,omitempty"`
|
//IncludeItems int `json:"include_items,omitempty"`
|
||||||
@ -33,7 +36,7 @@ type File struct {
|
|||||||
//Duration int `json:"duration"`
|
//Duration int `json:"duration"`
|
||||||
//FileSource string `json:"file_source"`
|
//FileSource string `json:"file_source"`
|
||||||
File bool `json:"file"`
|
File bool `json:"file"`
|
||||||
//CreatedAt int64 `json:"created_at"`
|
CreatedAt int64 `json:"created_at"`
|
||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
//PrivateExtra struct {} `json:"_private_extra"`
|
//PrivateExtra struct {} `json:"_private_extra"`
|
||||||
//ObjCategory string `json:"obj_category,omitempty"`
|
//ObjCategory string `json:"obj_category,omitempty"`
|
||||||
@ -46,10 +49,43 @@ func fileToObj(f File) *model.Object {
|
|||||||
Name: f.FileName,
|
Name: f.FileName,
|
||||||
Size: f.Size,
|
Size: f.Size,
|
||||||
Modified: time.UnixMilli(f.UpdatedAt),
|
Modified: time.UnixMilli(f.UpdatedAt),
|
||||||
|
Ctime: time.UnixMilli(f.CreatedAt),
|
||||||
IsFolder: !f.File,
|
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 {
|
type SortResp struct {
|
||||||
Resp
|
Resp
|
||||||
Data struct {
|
Data struct {
|
||||||
@ -100,6 +136,82 @@ type DownResp struct {
|
|||||||
//} `json:"metadata"`
|
//} `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 {
|
type UpPreResp struct {
|
||||||
Resp
|
Resp
|
||||||
Data struct {
|
Data struct {
|
||||||
|
@ -50,14 +50,23 @@ func (d *QuarkOrUC) request(pathname string, method string, callback base.ReqCal
|
|||||||
d.Cookie = cookie.SetStr(d.Cookie, "__puus", __puus.Value)
|
d.Cookie = cookie.SetStr(d.Cookie, "__puus", __puus.Value)
|
||||||
op.MustSaveDriverStorage(d)
|
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 {
|
if e.Status >= 400 || e.Code != 0 {
|
||||||
return nil, errors.New(e.Message)
|
return nil, errors.New(e.Message)
|
||||||
}
|
}
|
||||||
return res.Body(), nil
|
return res.Body(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *QuarkOrUC) GetFiles(parent string) ([]File, error) {
|
func (d *QuarkOrUC) GetFiles(parent string) ([]model.Obj, error) {
|
||||||
files := make([]File, 0)
|
files := make([]model.Obj, 0)
|
||||||
page := 1
|
page := 1
|
||||||
size := 100
|
size := 100
|
||||||
query := map[string]string{
|
query := map[string]string{
|
||||||
@ -77,15 +86,72 @@ func (d *QuarkOrUC) GetFiles(parent string) ([]File, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if page*size >= resp.Metadata.Total {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
page++
|
page++
|
||||||
}
|
}
|
||||||
|
|
||||||
return files, nil
|
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) {
|
func (d *QuarkOrUC) upPre(file model.FileStreamer, parentId string) (UpPreResp, error) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
data := base.Json{
|
data := base.Json{
|
||||||
|
Reference in New Issue
Block a user