🚧 MediaTrack support

pull/548/head
微凉 2022-01-06 01:14:32 +08:00
parent 36b533cb16
commit 10f06fde5c
3 changed files with 458 additions and 0 deletions

View File

@ -9,6 +9,7 @@ import (
_ "github.com/Xhofe/alist/drivers/ftp" _ "github.com/Xhofe/alist/drivers/ftp"
_ "github.com/Xhofe/alist/drivers/google" _ "github.com/Xhofe/alist/drivers/google"
_ "github.com/Xhofe/alist/drivers/lanzou" _ "github.com/Xhofe/alist/drivers/lanzou"
_ "github.com/Xhofe/alist/drivers/mediatrack"
_ "github.com/Xhofe/alist/drivers/native" _ "github.com/Xhofe/alist/drivers/native"
_ "github.com/Xhofe/alist/drivers/onedrive" _ "github.com/Xhofe/alist/drivers/onedrive"
_ "github.com/Xhofe/alist/drivers/pikpak" _ "github.com/Xhofe/alist/drivers/pikpak"

View File

@ -0,0 +1,276 @@
package mediatrack
import (
"fmt"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/gin-gonic/gin"
jsoniter "github.com/json-iterator/go"
log "github.com/sirupsen/logrus"
"path/filepath"
)
type MediaTrack struct{}
func (driver MediaTrack) Config() base.DriverConfig {
return base.DriverConfig{
Name: "MediaTrack",
}
}
func (driver MediaTrack) Items() []base.Item {
return []base.Item{
{
Name: "access_token",
Label: "Token",
Type: base.TypeString,
Description: "Unknown expiration time",
},
{
Name: "root_folder",
Label: "root folder file_id",
Type: base.TypeString,
},
{
Name: "order_by",
Label: "order_by",
Type: base.TypeSelect,
Values: "updated_at,title,size",
Required: true,
},
{
Name: "order_direction",
Label: "desc",
Type: base.TypeSelect,
Values: "true,false",
Required: true,
},
}
}
func (driver MediaTrack) Save(account *model.Account, old *model.Account) error {
return nil
}
func (driver MediaTrack) File(path string, account *model.Account) (*model.File, error) {
path = utils.ParsePath(path)
if path == "/" {
return &model.File{
Id: account.RootFolder,
Name: account.Name,
Size: 0,
Type: conf.FOLDER,
Driver: driver.Config().Name,
UpdatedAt: account.UpdatedAt,
}, nil
}
dir, name := filepath.Split(path)
files, err := driver.Files(dir, account)
if err != nil {
return nil, err
}
for _, file := range files {
if file.Name == name {
return &file, nil
}
}
return nil, base.ErrPathNotFound
}
func (driver MediaTrack) Files(path string, account *model.Account) ([]model.File, error) {
path = utils.ParsePath(path)
var files []model.File
cache, err := base.GetCache(path, account)
if err == nil {
files, _ = cache.([]model.File)
} else {
file, err := driver.File(path, account)
if err != nil {
return nil, err
}
files, err = driver.GetFiles(file.Id, account)
if err != nil {
return nil, err
}
if len(files) > 0 {
_ = base.SetCache(path, files, account)
}
}
return files, nil
}
func (driver MediaTrack) Link(args base.Args, account *model.Account) (*base.Link, error) {
file, err := driver.File(args.Path, account)
if err != nil {
return nil, err
}
pre := "https://jayce.api.mediatrack.cn/v3/assets/" + file.Id
body, err := driver.Request(pre+"/token", base.Get, nil, nil, nil, nil, nil, account)
if err != nil {
return nil, err
}
url := pre + "/raw"
res, err := base.NoRedirectClient.R().SetQueryParam("token", jsoniter.Get(body, "data").ToString()).Get(url)
return &base.Link{Url: res.Header().Get("location")}, nil
}
func (driver MediaTrack) Path(path string, account *model.Account) (*model.File, []model.File, error) {
path = utils.ParsePath(path)
log.Debugf("MediaTrack path: %s", path)
file, err := driver.File(path, account)
if err != nil {
return nil, nil, err
}
if !file.IsDir() {
return file, nil, nil
}
files, err := driver.Files(path, account)
if err != nil {
return nil, nil, err
}
return nil, files, nil
}
func (driver MediaTrack) Proxy(c *gin.Context, account *model.Account) {
}
func (driver MediaTrack) Preview(path string, account *model.Account) (interface{}, error) {
return nil, base.ErrNotImplement
}
func (driver MediaTrack) MakeDir(path string, account *model.Account) error {
parentFile, err := driver.File(utils.Dir(path), account)
if err != nil {
return err
}
url := fmt.Sprintf("https://jayce.api.mediatrack.cn/v4/assets/%s/children", parentFile.Id)
_, err = driver.Request(url, base.Post, nil, nil, nil, base.Json{
"type": 1,
"title": utils.Base(path),
}, nil, account)
return err
}
func (driver MediaTrack) Move(src string, dst string, account *model.Account) error {
srcFile, err := driver.File(src, account)
if err != nil {
return err
}
dstParentFile, err := driver.File(utils.Dir(dst), account)
if err != nil {
return err
}
data := base.Json{
"parent_id": dstParentFile.Id,
"ids": []string{srcFile.Id},
}
url := "https://jayce.api.mediatrack.cn/v4/assets/batch/move"
_, err = driver.Request(url, base.Post, nil, nil, nil, data, nil, account)
return err
}
func (driver MediaTrack) Rename(src string, dst string, account *model.Account) error {
srcFile, err := driver.File(src, account)
if err != nil {
return err
}
url := "https://jayce.api.mediatrack.cn/v3/assets/" + srcFile.Id
data := base.Json{
"title": utils.Base(dst),
}
_, err = driver.Request(url, base.Put, nil, nil, nil, data, nil, account)
return err
}
func (driver MediaTrack) Copy(src string, dst string, account *model.Account) error {
srcFile, err := driver.File(src, account)
if err != nil {
return err
}
dstParentFile, err := driver.File(utils.Dir(dst), account)
if err != nil {
return err
}
data := base.Json{
"parent_id": dstParentFile.Id,
"ids": []string{srcFile.Id},
}
url := "https://jayce.api.mediatrack.cn/v4/assets/batch/clone"
_, err = driver.Request(url, base.Post, nil, nil, nil, data, nil, account)
return err
}
func (driver MediaTrack) Delete(path string, account *model.Account) error {
parentFile, err := driver.File(utils.Dir(path), account)
if err != nil {
return err
}
file, err := driver.File(path, account)
if err != nil {
return err
}
data := base.Json{
"origin_id": parentFile.Id,
"ids": []string{file.Id},
}
url := "https://jayce.api.mediatrack.cn/v4/assets/batch/delete"
_, err = driver.Request(url, base.Delete, nil, nil, nil, data, nil, account)
return err
}
func (driver MediaTrack) Upload(file *model.FileStream, account *model.Account) error {
parentFile, err := driver.File(file.ParentPath, account)
if err != nil {
return err
}
src := "assets/56461b45-6d08-40a0-bfbf-0a47689bffaa" // random?
var resp UploadResp
_, err = driver.Request("https://jayce.api.mediatrack.cn/v3/storage/tokens/asset", base.Get, nil, map[string]string{
"src": src,
}, nil, nil, &resp, account)
if err != nil {
return err
}
credential := resp.Data.Credentials
cfg := &aws.Config{
Credentials: credentials.NewStaticCredentials(credential.TmpSecretID, credential.TmpSecretKey, credential.Token),
Region: &resp.Data.Region,
Endpoint: aws.String("cos.accelerate.myqcloud.com"),
}
s, err := session.NewSession(cfg)
if err != nil {
return err
}
uploader := s3manager.NewUploader(s)
input := &s3manager.UploadInput{
Bucket: &resp.Data.Bucket,
Key: &resp.Data.Object,
Body: file,
}
_, err = uploader.Upload(input)
if err != nil {
return err
}
url := fmt.Sprintf("https://jayce.api.mediatrack.cn/v3/assets/%s/children", parentFile.Id)
data := base.Json{
"category": 10,
"description": file.GetFileName(),
"hash": "c459fda4d79554d692555932a5d5e6c1",
"mime": file.MIMEType,
"size": file.GetSize(),
"src": src,
"title": file.GetFileName(),
"type": 0,
}
_, err = driver.Request(url, base.Post, nil, nil, nil, data, nil, account)
return err
}
var _ base.Driver = (*MediaTrack)(nil)

View File

@ -0,0 +1,181 @@
package mediatrack
import (
"errors"
"fmt"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/go-resty/resty/v2"
"path"
"strconv"
"time"
)
type BaseResp struct {
Status string `json:"status"`
Message string `json:"message"`
}
type T struct {
BaseResp
}
func (driver MediaTrack) Request(url string, method int, headers, query, form map[string]string, data interface{}, resp interface{}, account *model.Account) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeader("Authorization", "Bearer "+account.AccessToken)
if headers != nil {
req.SetHeaders(headers)
}
if query != nil {
req.SetQueryParams(query)
}
if form != nil {
req.SetFormData(form)
}
if data != nil {
req.SetBody(data)
}
var e BaseResp
req.SetResult(&e)
var err error
var res *resty.Response
switch method {
case base.Get:
res, err = req.Get(url)
case base.Post:
res, err = req.Post(url)
case base.Delete:
res, err = req.Delete(url)
case base.Patch:
res, err = req.Patch(url)
case base.Put:
res, err = req.Put(url)
default:
return nil, base.ErrNotSupport
}
if err != nil {
return nil, err
}
if e.Status != "SUCCESS" {
return nil, errors.New(e.Message)
}
if resp != nil {
err = utils.Json.Unmarshal(res.Body(), resp)
}
return res.Body(), err
}
type File struct {
Category int `json:"category"`
ChildAssets []interface{} `json:"childAssets"`
CommentCount int `json:"comment_count"`
CoverAsset interface{} `json:"cover_asset"`
CoverAssetID string `json:"cover_asset_id"`
CreatedAt time.Time `json:"created_at"`
DeletedAt string `json:"deleted_at"`
Description string `json:"description"`
File struct {
Cover string `json:"cover"`
Src string `json:"src"`
} `json:"file"`
//FileID string `json:"file_id"`
ID string `json:"id"`
Size string `json:"size"`
Thumbnails []interface{} `json:"thumbnails"`
Title string `json:"title"`
UpdatedAt time.Time `json:"updated_at"`
}
func (driver MediaTrack) formatFile(file *File) *model.File {
f := model.File{
Id: file.ID,
Name: file.Title,
Size: 0,
Driver: driver.Config().Name,
UpdatedAt: &file.UpdatedAt,
}
if file.Category == 0 {
// folder
f.Type = conf.FOLDER
} else {
size, _ := strconv.ParseInt(file.Size, 10, 64)
f.Size = size
f.Type = utils.GetFileType(path.Ext(file.Title))
if file.File.Cover != "" {
f.Thumbnail = "https://nano.mtres.cn/" + file.File.Cover
}
}
return &f
}
type ChildrenResp struct {
Status string `json:"status"`
Data struct {
Total int `json:"total"`
Assets []File `json:"assets"`
} `json:"data"`
Path string `json:"path"`
TraceID string `json:"trace_id"`
RequestID string `json:"requestId"`
}
func (driver MediaTrack) GetFiles(parentId string, account *model.Account) ([]model.File, error) {
files := make([]model.File, 0)
url := fmt.Sprintf("https://jayce.api.mediatrack.cn/v4/assets/%s/children", parentId)
sort := ""
if account.OrderBy != "" {
if account.OrderDirection == "true" {
sort = "-"
}
sort += account.OrderBy
}
page := 1
for {
var resp ChildrenResp
_, err := driver.Request(url, base.Get, nil, map[string]string{
"page": strconv.Itoa(page),
"size": "50",
"sort": sort,
}, nil, nil, &resp, account)
if err != nil {
return nil, err
}
if len(resp.Data.Assets) == 0 {
break
}
page++
for _, file := range resp.Data.Assets {
files = append(files, *driver.formatFile(&file))
}
}
return files, nil
}
type UploadResp struct {
Status string `json:"status"`
Data struct {
Credentials struct {
TmpSecretID string `json:"TmpSecretId"`
TmpSecretKey string `json:"TmpSecretKey"`
Token string `json:"Token"`
ExpiredTime int `json:"ExpiredTime"`
Expiration time.Time `json:"Expiration"`
StartTime int `json:"StartTime"`
} `json:"credentials"`
Object string `json:"object"`
Bucket string `json:"bucket"`
Region string `json:"region"`
URL string `json:"url"`
Size string `json:"size"`
} `json:"data"`
Path string `json:"path"`
TraceID string `json:"trace_id"`
RequestID string `json:"requestId"`
}
func init() {
base.RegisterDriver(&MediaTrack{})
}