ali path and link

pull/548/head
微凉 2021-10-28 22:50:09 +08:00
parent 98f7dffed9
commit 0a50fbd080
13 changed files with 207 additions and 41 deletions

View File

@ -2,9 +2,9 @@ package bootstrap
import ( import (
"github.com/Xhofe/alist/conf" "github.com/Xhofe/alist/conf"
"github.com/allegro/bigcache/v3"
"github.com/eko/gocache/v2/cache" "github.com/eko/gocache/v2/cache"
"github.com/eko/gocache/v2/store" "github.com/eko/gocache/v2/store"
goCache "github.com/patrickmn/go-cache"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"time" "time"
) )
@ -12,9 +12,7 @@ import (
// InitCache init cache // InitCache init cache
func InitCache() { func InitCache() {
log.Infof("init cache...") log.Infof("init cache...")
bigCacheConfig := bigcache.DefaultConfig(60 * time.Minute) goCacheClient := goCache.New(60*time.Minute, 120*time.Minute)
bigCacheConfig.HardMaxCacheSize = 512 goCacheStore := store.NewGoCache(goCacheClient, nil)
bigCacheClient, _ := bigcache.NewBigCache(bigCacheConfig) conf.Cache = cache.New(goCacheStore)
bigCacheStore := store.NewBigcache(bigCacheClient, nil) }
conf.Cache = cache.New(bigCacheStore)
}

View File

@ -67,7 +67,7 @@ func InitModel() {
log.Fatalf("not supported database type: %s", config.Type) log.Fatalf("not supported database type: %s", config.Type)
} }
log.Infof("auto migrate model") log.Infof("auto migrate model")
err := conf.DB.AutoMigrate(&model.SettingItem{}, &model.Account{}) err := conf.DB.AutoMigrate(&model.SettingItem{}, &model.Account{},&model.Meta{})
if err != nil { if err != nil {
log.Fatalf("failed to auto migrate") log.Fatalf("failed to auto migrate")
} }
@ -87,7 +87,7 @@ func initAccounts() {
model.RegisterAccount(account) model.RegisterAccount(account)
driver, ok := drivers.GetDriver(account.Type) driver, ok := drivers.GetDriver(account.Type)
if !ok { if !ok {
log.Error("no [%s] driver", driver) log.Errorf("no [%s] driver", driver)
} else { } else {
err := driver.Save(&account, nil) err := driver.Save(&account, nil)
if err != nil { if err != nil {

View File

@ -8,6 +8,7 @@ import (
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"path/filepath"
"time" "time"
) )
@ -29,17 +30,23 @@ type AliRespError struct {
Message string `json:"message"` Message string `json:"message"`
} }
type AliFiles struct {
Items []AliFile `json:"items"`
NextMarker string `json:"next_marker"`
}
type AliFile struct { type AliFile struct {
DriveId string `json:"drive_id"` DriveId string `json:"drive_id"`
CreatedAt *time.Time `json:"created_at"` CreatedAt *time.Time `json:"created_at"`
FileExtension string `json:"file_extension"` FileExtension string `json:"file_extension"`
FileId string `json:"file_id"` FileId string `json:"file_id"`
Name string `json:"name"` Type string `json:"type"`
ParentFileId string `json:"parent_file_id"` Name string `json:"name"`
UpdatedAt *time.Time `json:"updated_at"` ParentFileId string `json:"parent_file_id"`
Size int64 `json:"size"` UpdatedAt *time.Time `json:"updated_at"`
//Thumbnail string `json:"thumbnail"` Size int64 `json:"size"`
Url string `json:"url"` Thumbnail string `json:"thumbnail"`
Url string `json:"url"`
} }
func AliToFile(file AliFile) *model.File { func AliToFile(file AliFile) *model.File {
@ -51,31 +58,135 @@ func AliToFile(file AliFile) *model.File {
} }
} }
func (a AliDrive) GetFiles(fileId string, account *model.Account) ([]AliFile, error) {
marker := "first"
res := make([]AliFile, 0)
for marker != "" {
if marker == "first" {
marker = ""
}
var resp AliFiles
var e AliRespError
_, err := aliClient.R().
SetResult(&resp).
SetError(&e).
SetHeader("authorization", "Bearer\t"+account.AccessToken).
SetBody(JsonStr(Json{
"drive_id": account.DriveId,
"fields": "*",
"image_thumbnail_process": "image/resize,w_50",
"image_url_process": "image/resize,w_1920/format,jpeg",
"limit": account.Limit,
"marker": marker,
"order_by": account.OrderBy,
"order_direction": account.OrderDirection,
"parent_file_id": fileId,
"video_thumbnail_process": "video/snapshot,t_0,f_jpg,w_50",
})).Post("https://api.aliyundrive.com/v2/file/list")
if err != nil {
return nil, err
}
if e.Code != "" {
return nil, fmt.Errorf("%s", e.Message)
}
marker = resp.NextMarker
res = append(res, resp.Items...)
}
return res, nil
}
// path: /aaa/bbb // path: /aaa/bbb
func (a AliDrive) Path(path string, account *model.Account) (*model.File, []*model.File, error) { func (a AliDrive) Path(path string, account *model.Account) (*model.File, []*model.File, error) {
path = utils.ParsePath(path)
log.Debugf("ali path: %s", path)
cache, err := conf.Cache.Get(conf.Ctx, path) cache, err := conf.Cache.Get(conf.Ctx, path)
if err == nil { if err == nil {
file,ok := cache.(AliFile) file, ok := cache.(AliFile)
if ok { if ok {
return AliToFile(file), nil, nil return AliToFile(file), nil, nil
}else { } else {
files,_ := cache.([]AliFile) files, _ := cache.([]AliFile)
res := make([]*model.File,0) res := make([]*model.File, 0)
for _,file = range files{ for _, file = range files {
res = append(res, AliToFile(file)) res = append(res, AliToFile(file))
} }
return nil, res, nil return nil, res, nil
} }
}else { } else {
fileId := account.RootFolder
if path != "/" { if path != "/" {
dir, name := filepath.Split(path)
dir = utils.ParsePath(dir)
_, _, err = a.Path(dir, account)
if err != nil {
return nil, nil, err
}
parentFiles_, _ := conf.Cache.Get(conf.Ctx, dir)
parentFiles, _ := parentFiles_.([]AliFile)
found := false
for _, file := range parentFiles {
if file.Name == name {
found = true
if file.Type == "file" {
return AliToFile(file), nil, nil
} else {
fileId = file.FileId
break
}
}
}
if !found {
return nil, nil, fmt.Errorf("path not found")
}
} }
files, err := a.GetFiles(fileId, account)
if err != nil {
return nil, nil, err
}
_ = conf.Cache.Set(conf.Ctx, path, files, nil)
res := make([]*model.File, 0)
for _, file := range files {
res = append(res, AliToFile(file))
}
return nil, res, nil
} }
panic("implement me")
} }
func (a AliDrive) Link(path string, account *model.Account) (string, error) { func (a AliDrive) Link(path string, account *model.Account) (string, error) {
panic("implement me") dir, name := filepath.Split(path)
dir = utils.ParsePath(dir)
_, _, err := a.Path(dir, account)
if err != nil {
return "", err
}
parentFiles_, _ := conf.Cache.Get(conf.Ctx, dir)
parentFiles, _ := parentFiles_.([]AliFile)
for _, file := range parentFiles {
if file.Name == name {
if file.Type == "file" {
var resp Json
var e AliRespError
_, err = aliClient.R().SetResult(&resp).
SetError(&e).
SetHeader("authorization", "Bearer\t"+account.AccessToken).
SetBody(Json{
"drive_id": account.DriveId,
"file_id": file.FileId,
"expire_sec": 14400,
}).Post("https://api.aliyundrive.com/v2/file/get_download_url")
if err != nil {
return "", err
}
if e.Code != "" {
return "", fmt.Errorf("%s",e.Message)
}
return resp["url"].(string), nil
} else {
return "", fmt.Errorf("can't down folder")
}
}
}
return "", fmt.Errorf("path not found")
} }
type AliTokenResp struct { type AliTokenResp struct {
@ -111,6 +222,13 @@ func (a AliDrive) Save(account *model.Account, old *model.Account) error {
if err != nil { if err != nil {
return err return err
} }
var resp Json
_, _ = aliClient.R().SetResult(&resp).
SetBody("{}").
SetHeader("authorization", "Bearer\t"+access).
Post("https://api.aliyundrive.com/v2/user/get")
log.Debugf("user info: %+v", resp)
account.DriveId = resp["default_drive_id"].(string)
account.RefreshToken, account.AccessToken = refresh, access account.RefreshToken, account.AccessToken = refresh, access
cronId, err := conf.Cron.AddFunc("@every 2h", func() { cronId, err := conf.Cron.AddFunc("@every 2h", func() {
name := account.Name name := account.Name

6
go.mod
View File

@ -3,10 +3,12 @@ module github.com/Xhofe/alist
go 1.17 go 1.17
require ( require (
github.com/allegro/bigcache/v3 v3.0.1
github.com/eko/gocache/v2 v2.1.0 github.com/eko/gocache/v2 v2.1.0
github.com/go-playground/validator/v10 v10.9.0 github.com/go-playground/validator/v10 v10.9.0
github.com/go-resty/resty/v2 v2.6.0
github.com/gofiber/fiber/v2 v2.20.2 github.com/gofiber/fiber/v2 v2.20.2
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/robfig/cron/v3 v3.0.0
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
gorm.io/driver/mysql v1.1.2 gorm.io/driver/mysql v1.1.2
gorm.io/driver/postgres v1.1.2 gorm.io/driver/postgres v1.1.2
@ -25,7 +27,6 @@ require (
github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-redis/redis/v8 v8.9.0 // indirect github.com/go-redis/redis/v8 v8.9.0 // indirect
github.com/go-resty/resty/v2 v2.6.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang/protobuf v1.4.3 // indirect github.com/golang/protobuf v1.4.3 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect
@ -47,7 +48,6 @@ require (
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.18.0 // indirect github.com/prometheus/common v0.18.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect
github.com/robfig/cron/v3 v3.0.0 // indirect
github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cast v1.3.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.31.0 // indirect github.com/valyala/fasthttp v1.31.0 // indirect

2
go.sum
View File

@ -22,8 +22,6 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/allegro/bigcache/v2 v2.2.5 h1:mRc8r6GQjuJsmSKQNPsR5jQVXc8IJ1xsW5YXUYMLfqI= github.com/allegro/bigcache/v2 v2.2.5 h1:mRc8r6GQjuJsmSKQNPsR5jQVXc8IJ1xsW5YXUYMLfqI=
github.com/allegro/bigcache/v2 v2.2.5/go.mod h1:FppZsIO+IZk7gCuj5FiIDHGygD9xvWQcqg1uIPMb6tY= github.com/allegro/bigcache/v2 v2.2.5/go.mod h1:FppZsIO+IZk7gCuj5FiIDHGygD9xvWQcqg1uIPMb6tY=
github.com/allegro/bigcache/v3 v3.0.1 h1:Q4Xl3chywXuJNOw7NV+MeySd3zGQDj4KCpkCg0te8mc=
github.com/allegro/bigcache/v3 v3.0.1/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM= github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=

View File

@ -13,7 +13,7 @@ import (
"net/http" "net/http"
) )
func init() { func Init() {
flag.StringVar(&conf.ConfigFile, "conf", "config.json", "config file") flag.StringVar(&conf.ConfigFile, "conf", "config.json", "config file")
flag.BoolVar(&conf.Debug,"debug",false,"start with debug mode") flag.BoolVar(&conf.Debug,"debug",false,"start with debug mode")
flag.Parse() flag.Parse()
@ -25,6 +25,7 @@ func init() {
} }
func main() { func main() {
Init()
app := fiber.New() app := fiber.New()
app.Use("/",filesystem.New(filesystem.Config{ app.Use("/",filesystem.New(filesystem.Config{
Root: http.FS(public.Public), Root: http.FS(public.Public),

12
main_test.go Normal file
View File

@ -0,0 +1,12 @@
package main
import (
"fmt"
"net/url"
"testing"
)
func TestUrl(t *testing.T) {
s,_ := url.QueryUnescape("/ali/%E7%8C%AA%E5%A4%B4%E7%9A%84%E6%96%87%E4%BB%B6%5B%E5%98%BF%E5%98%BF%5D/%E9%82%B9%E9%82%B9%E7%9A%84%E6%96%87%E4%BB%B6/%E6%A1%8C%E9%9D%A2%E5%A3%81%E7%BA%B8/v2-e8f266ba17ae387eefed1cb22b2b5e4e_r.jpg")
fmt.Print(s)
}

View File

@ -15,6 +15,7 @@ type Account struct {
Status string Status string
CronId int CronId int
DriveId string DriveId string
Limit int `json:"limit"`
OrderBy string `json:"order_by"` OrderBy string `json:"order_by"`
OrderDirection string `json:"order_direction"` OrderDirection string `json:"order_direction"`
} }
@ -79,4 +80,3 @@ func GetAccounts() []*Account {
} }
return accounts return accounts
} }

View File

@ -1,8 +1,20 @@
package model package model
import "github.com/Xhofe/alist/conf"
type Meta struct { type Meta struct {
Path string `json:"path" gorm:"primaryKey"` Path string `json:"path" gorm:"primaryKey"`
Password string `json:"password"` Password string `json:"password"`
Hide bool `json:"hide"` Hide bool `json:"hide"`
Ignore bool `json:"ignore"` Ignore bool `json:"ignore"`
} }
func GetMetaByPath(path string) (*Meta,error) {
var meta Meta
meta.Path = path
err := conf.DB.First(&meta).Error
if err != nil {
return nil, err
}
return &meta, nil
}

View File

@ -27,7 +27,7 @@ func ParsePath(rawPath string) (*model.Account,string,drivers.Driver,error) {
break break
default: default:
paths := strings.Split(rawPath,"/") paths := strings.Split(rawPath,"/")
path = strings.Join(paths[2:],"/") path = "/" + strings.Join(paths[2:],"/")
name = paths[1] name = paths[1]
} }
account,ok := model.GetAccount(name) account,ok := model.GetAccount(name)

View File

@ -1,9 +1,19 @@
package server package server
import "github.com/gofiber/fiber/v2" import (
"github.com/Xhofe/alist/utils"
"github.com/gofiber/fiber/v2"
log "github.com/sirupsen/logrus"
"net/url"
)
func Down(ctx *fiber.Ctx) error { func Down(ctx *fiber.Ctx) error {
rawPath := ctx.Params("*") rawPath, err:= url.QueryUnescape(ctx.Params("*"))
if err != nil {
return ErrorResp(ctx,err,500)
}
rawPath = utils.ParsePath(rawPath)
log.Debugf("down: %s",rawPath)
account, path, driver, err := ParsePath(rawPath) account, path, driver, err := ParsePath(rawPath)
if err != nil { if err != nil {
return ErrorResp(ctx, err, 500) return ErrorResp(ctx, err, 500)

View File

@ -1,9 +1,11 @@
package server package server
import ( import (
"fmt"
"github.com/Xhofe/alist/model" "github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"strings" log "github.com/sirupsen/logrus"
) )
type PathReq struct { type PathReq struct {
@ -16,8 +18,14 @@ func Path(ctx *fiber.Ctx) error {
if err := ctx.BodyParser(&req); err != nil { if err := ctx.BodyParser(&req); err != nil {
return ErrorResp(ctx, err, 400) return ErrorResp(ctx, err, 400)
} }
if !strings.HasPrefix(req.Path, "/") { req.Path = utils.ParsePath(req.Path)
req.Path = "/"+req.Path log.Debugf("path: %s",req.Path)
meta, err := model.GetMetaByPath(req.Path)
if err == nil {
if meta.Password != "" && meta.Password!= req.Password {
return ErrorResp(ctx,fmt.Errorf("wrong password"),401)
}
// TODO hide or ignore?
} }
if model.AccountsCount() > 1 && req.Path == "/" { if model.AccountsCount() > 1 && req.Path == "/" {
return ctx.JSON(Resp{ return ctx.JSON(Resp{

View File

@ -7,6 +7,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
) )
// Exists determine whether the file exists // Exists determine whether the file exists
@ -75,4 +76,12 @@ func WriteToJson(src string, conf interface{}) bool {
return false return false
} }
return true return true
}
func ParsePath(path string) string {
path = strings.TrimRight(path, "/")
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
return path
} }