Skip to content

Commit

Permalink
feat: add support for quark tv driver and uc tv driver (#6959)
Browse files Browse the repository at this point in the history
  • Loading branch information
Three-taile-dragon authored Aug 10, 2024
1 parent 979d0cf commit 62ed169
Show file tree
Hide file tree
Showing 5 changed files with 555 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
_ "github.com/alist-org/alist/v3/drivers/pikpak"
_ "github.com/alist-org/alist/v3/drivers/pikpak_share"
_ "github.com/alist-org/alist/v3/drivers/quark_uc"
_ "github.com/alist-org/alist/v3/drivers/quark_uc_tv"
_ "github.com/alist-org/alist/v3/drivers/quqi"
_ "github.com/alist-org/alist/v3/drivers/s3"
_ "github.com/alist-org/alist/v3/drivers/seafile"
Expand Down
174 changes: 174 additions & 0 deletions drivers/quark_uc_tv/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package quark_uc_tv

import (
"context"
"fmt"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/go-resty/resty/v2"
"strconv"
"time"

"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
)

type QuarkUCTV struct {
*QuarkUCTVCommon
model.Storage
Addition
config driver.Config
conf Conf
}

func (d *QuarkUCTV) Config() driver.Config {
return d.config
}

func (d *QuarkUCTV) GetAddition() driver.Additional {
return &d.Addition
}

func (d *QuarkUCTV) Init(ctx context.Context) error {

if d.Addition.DeviceID == "" {
d.Addition.DeviceID = utils.GetMD5EncodeStr(time.Now().String())
}
op.MustSaveDriverStorage(d)

if d.QuarkUCTVCommon == nil {
d.QuarkUCTVCommon = &QuarkUCTVCommon{
AccessToken: "",
}
}
ctx1, cancelFunc := context.WithTimeout(ctx, 5*time.Second)
defer cancelFunc()
if d.Addition.RefreshToken == "" {
if d.Addition.QueryToken == "" {
qrData, err := d.getLoginCode(ctx1)
if err != nil {
return err
}
// 展示二维码
qrTemplate := `<body>
<img src="data:image/jpeg;base64,%s"/>
</body>`
qrPage := fmt.Sprintf(qrTemplate, qrData)
return fmt.Errorf("need verify: \n%s", qrPage)
} else {
// 通过query token获取code -> refresh token
code, err := d.getCode(ctx1)
if err != nil {
return err
}
// 通过code获取refresh token
err = d.getRefreshTokenByTV(ctx1, code, false)
if err != nil {
return err
}
}
}
// 通过refresh token获取access token
if d.QuarkUCTVCommon.AccessToken == "" {
err := d.getRefreshTokenByTV(ctx1, d.Addition.RefreshToken, true)
if err != nil {
return err
}
}

// 验证 access token 是否有效
_, err := d.isLogin(ctx1)
if err != nil {
return err
}
return nil
}

func (d *QuarkUCTV) Drop(ctx context.Context) error {
return nil
}

func (d *QuarkUCTV) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
files := make([]model.Obj, 0)
pageIndex := int64(0)
pageSize := int64(100)
for {
var filesData FilesData
_, err := d.request(ctx, "/file", "GET", func(req *resty.Request) {
req.SetQueryParams(map[string]string{
"method": "list",
"parent_fid": dir.GetID(),
"order_by": "3",
"desc": "1",
"category": "",
"source": "",
"ex_source": "",
"list_all": "0",
"page_size": strconv.FormatInt(pageSize, 10),
"page_index": strconv.FormatInt(pageIndex, 10),
})
}, &filesData)
if err != nil {
return nil, err
}
for i := range filesData.Data.Files {
files = append(files, &filesData.Data.Files[i])
}
if pageIndex*pageSize >= filesData.Data.TotalCount {
break
} else {
pageIndex++
}
}
return files, nil
}

func (d *QuarkUCTV) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
files := &model.Link{}
var fileLink FileLink
_, err := d.request(ctx, "/file", "GET", func(req *resty.Request) {
req.SetQueryParams(map[string]string{
"method": "download",
"group_by": "source",
"fid": file.GetID(),
"resolution": "low,normal,high,super,2k,4k",
"support": "dolby_vision",
})
}, &fileLink)
if err != nil {
return nil, err
}
files.URL = fileLink.Data.DownloadURL
return files, nil
}

func (d *QuarkUCTV) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
return nil, errs.NotImplement
}

func (d *QuarkUCTV) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
return nil, errs.NotImplement
}

func (d *QuarkUCTV) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
return nil, errs.NotImplement
}

func (d *QuarkUCTV) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
return nil, errs.NotImplement
}

func (d *QuarkUCTV) Remove(ctx context.Context, obj model.Obj) error {
return errs.NotImplement
}

func (d *QuarkUCTV) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
return nil, errs.NotImplement
}

type QuarkUCTVCommon struct {
AccessToken string
}

var _ driver.Driver = (*QuarkUCTV)(nil)
67 changes: 67 additions & 0 deletions drivers/quark_uc_tv/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package quark_uc_tv

import (
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/op"
)

type Addition struct {
// Usually one of two
driver.RootID
// define other
RefreshToken string `json:"refresh_token" required:"false" default:""`
// 必要且影响登录,由签名决定
DeviceID string `json:"device_id" required:"false" default:""`
// 登陆所用的数据 无需手动填写
QueryToken string `json:"query_token" required:"false" default:"" help:"don't edit'"`
}

type Conf struct {
api string
clientID string
signKey string
appVer string
channel string
codeApi string
}

func init() {
op.RegisterDriver(func() driver.Driver {
return &QuarkUCTV{
config: driver.Config{
Name: "QuarkTV",
OnlyLocal: false,
DefaultRoot: "0",
NoOverwriteUpload: true,
NoUpload: true,
},
conf: Conf{
api: "https://open-api-drive.quark.cn",
clientID: "d3194e61504e493eb6222857bccfed94",
signKey: "kw2dvtd7p4t3pjl2d9ed9yc8yej8kw2d",
appVer: "1.5.6",
channel: "CP",
codeApi: "http://api.extscreen.com/quarkdrive",
},
}
})
op.RegisterDriver(func() driver.Driver {
return &QuarkUCTV{
config: driver.Config{
Name: "UCTV",
OnlyLocal: false,
DefaultRoot: "0",
NoOverwriteUpload: true,
NoUpload: true,
},
conf: Conf{
api: "https://open-api-drive.uc.cn",
clientID: "5acf882d27b74502b7040b0c65519aa7",
signKey: "l3srvtd7p42l0d0x1u8d7yc8ye9kki4d",
appVer: "1.6.5",
channel: "UCTVOFFICIALWEB",
codeApi: "http://api.extscreen.com/ucdrive",
},
}
})
}
102 changes: 102 additions & 0 deletions drivers/quark_uc_tv/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package quark_uc_tv

import (
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
"time"
)

type Resp struct {
CommonRsp
Errno int `json:"errno"`
ErrorInfo string `json:"error_info"`
}

type CommonRsp struct {
Status int `json:"status"`
ReqID string `json:"req_id"`
}

type RefreshTokenAuthResp struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
Status int `json:"status"`
Errno int `json:"errno"`
ErrorInfo string `json:"error_info"`
ReqID string `json:"req_id"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope"`
} `json:"data"`
}
type Files struct {
Fid string `json:"fid"`
ParentFid string `json:"parent_fid"`
Category int `json:"category"`
Filename string `json:"filename"`
Size int64 `json:"size"`
FileType string `json:"file_type"`
SubItems int `json:"sub_items,omitempty"`
Isdir int `json:"isdir"`
Duration int `json:"duration"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
IsBackup int `json:"is_backup"`
ThumbnailURL string `json:"thumbnail_url,omitempty"`
}

func (f *Files) GetSize() int64 {
return f.Size
}

func (f *Files) GetName() string {
return f.Filename
}

func (f *Files) ModTime() time.Time {
//return time.Unix(f.UpdatedAt, 0)
return time.Unix(0, f.UpdatedAt*int64(time.Millisecond))
}

func (f *Files) CreateTime() time.Time {
//return time.Unix(f.CreatedAt, 0)
return time.Unix(0, f.CreatedAt*int64(time.Millisecond))
}

func (f *Files) IsDir() bool {
return f.Isdir == 1
}

func (f *Files) GetHash() utils.HashInfo {
return utils.HashInfo{}
}

func (f *Files) GetID() string {
return f.Fid
}

func (f *Files) GetPath() string {
return ""
}

var _ model.Obj = (*Files)(nil)

type FilesData struct {
CommonRsp
Data struct {
TotalCount int64 `json:"total_count"`
Files []Files `json:"files"`
} `json:"data"`
}

type FileLink struct {
CommonRsp
Data struct {
Fid string `json:"fid"`
FileName string `json:"file_name"`
Size int64 `json:"size"`
DownloadURL string `json:"download_url"`
} `json:"data"`
}
Loading

0 comments on commit 62ed169

Please sign in to comment.