mirror of https://github.com/Xhofe/alist
🚧 MediaTrack support
parent
36b533cb16
commit
10f06fde5c
|
@ -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"
|
||||||
|
|
|
@ -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)
|
|
@ -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{})
|
||||||
|
}
|
Loading…
Reference in New Issue