mirror of https://github.com/Xhofe/alist
✨ ali path and link
parent
98f7dffed9
commit
0a50fbd080
|
@ -2,9 +2,9 @@ package bootstrap
|
|||
|
||||
import (
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/allegro/bigcache/v3"
|
||||
"github.com/eko/gocache/v2/cache"
|
||||
"github.com/eko/gocache/v2/store"
|
||||
goCache "github.com/patrickmn/go-cache"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"time"
|
||||
)
|
||||
|
@ -12,9 +12,7 @@ import (
|
|||
// InitCache init cache
|
||||
func InitCache() {
|
||||
log.Infof("init cache...")
|
||||
bigCacheConfig := bigcache.DefaultConfig(60 * time.Minute)
|
||||
bigCacheConfig.HardMaxCacheSize = 512
|
||||
bigCacheClient, _ := bigcache.NewBigCache(bigCacheConfig)
|
||||
bigCacheStore := store.NewBigcache(bigCacheClient, nil)
|
||||
conf.Cache = cache.New(bigCacheStore)
|
||||
goCacheClient := goCache.New(60*time.Minute, 120*time.Minute)
|
||||
goCacheStore := store.NewGoCache(goCacheClient, nil)
|
||||
conf.Cache = cache.New(goCacheStore)
|
||||
}
|
|
@ -67,7 +67,7 @@ func InitModel() {
|
|||
log.Fatalf("not supported database type: %s", config.Type)
|
||||
}
|
||||
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 {
|
||||
log.Fatalf("failed to auto migrate")
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ func initAccounts() {
|
|||
model.RegisterAccount(account)
|
||||
driver, ok := drivers.GetDriver(account.Type)
|
||||
if !ok {
|
||||
log.Error("no [%s] driver", driver)
|
||||
log.Errorf("no [%s] driver", driver)
|
||||
} else {
|
||||
err := driver.Save(&account, nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/go-resty/resty/v2"
|
||||
"github.com/robfig/cron/v3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -29,16 +30,22 @@ type AliRespError struct {
|
|||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type AliFiles struct {
|
||||
Items []AliFile `json:"items"`
|
||||
NextMarker string `json:"next_marker"`
|
||||
}
|
||||
|
||||
type AliFile struct {
|
||||
DriveId string `json:"drive_id"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
FileExtension string `json:"file_extension"`
|
||||
FileId string `json:"file_id"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
ParentFileId string `json:"parent_file_id"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
Size int64 `json:"size"`
|
||||
//Thumbnail string `json:"thumbnail"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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)
|
||||
if err == nil {
|
||||
file,ok := cache.(AliFile)
|
||||
file, ok := cache.(AliFile)
|
||||
if ok {
|
||||
return AliToFile(file), nil, nil
|
||||
}else {
|
||||
files,_ := cache.([]AliFile)
|
||||
res := make([]*model.File,0)
|
||||
for _,file = range files{
|
||||
} else {
|
||||
files, _ := cache.([]AliFile)
|
||||
res := make([]*model.File, 0)
|
||||
for _, file = range files {
|
||||
res = append(res, AliToFile(file))
|
||||
}
|
||||
return nil, res, nil
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
fileId := account.RootFolder
|
||||
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
|
||||
}
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -111,6 +222,13 @@ func (a AliDrive) Save(account *model.Account, old *model.Account) error {
|
|||
if err != nil {
|
||||
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
|
||||
cronId, err := conf.Cron.AddFunc("@every 2h", func() {
|
||||
name := account.Name
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,10 +3,12 @@ module github.com/Xhofe/alist
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/allegro/bigcache/v3 v3.0.1
|
||||
github.com/eko/gocache/v2 v2.1.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/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/robfig/cron/v3 v3.0.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
gorm.io/driver/mysql 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/universal-translator v0.18.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/golang/protobuf v1.4.3 // 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/common v0.18.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/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.31.0 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -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/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/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.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
|
||||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
|
|
3
main.go
3
main.go
|
@ -13,7 +13,7 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
func init() {
|
||||
func Init() {
|
||||
flag.StringVar(&conf.ConfigFile, "conf", "config.json", "config file")
|
||||
flag.BoolVar(&conf.Debug,"debug",false,"start with debug mode")
|
||||
flag.Parse()
|
||||
|
@ -25,6 +25,7 @@ func init() {
|
|||
}
|
||||
|
||||
func main() {
|
||||
Init()
|
||||
app := fiber.New()
|
||||
app.Use("/",filesystem.New(filesystem.Config{
|
||||
Root: http.FS(public.Public),
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -15,6 +15,7 @@ type Account struct {
|
|||
Status string
|
||||
CronId int
|
||||
DriveId string
|
||||
Limit int `json:"limit"`
|
||||
OrderBy string `json:"order_by"`
|
||||
OrderDirection string `json:"order_direction"`
|
||||
}
|
||||
|
@ -79,4 +80,3 @@ func GetAccounts() []*Account {
|
|||
}
|
||||
return accounts
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
package model
|
||||
|
||||
import "github.com/Xhofe/alist/conf"
|
||||
|
||||
type Meta struct {
|
||||
Path string `json:"path" gorm:"primaryKey"`
|
||||
Password string `json:"password"`
|
||||
Hide bool `json:"hide"`
|
||||
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
|
||||
}
|
|
@ -27,7 +27,7 @@ func ParsePath(rawPath string) (*model.Account,string,drivers.Driver,error) {
|
|||
break
|
||||
default:
|
||||
paths := strings.Split(rawPath,"/")
|
||||
path = strings.Join(paths[2:],"/")
|
||||
path = "/" + strings.Join(paths[2:],"/")
|
||||
name = paths[1]
|
||||
}
|
||||
account,ok := model.GetAccount(name)
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
return ErrorResp(ctx, err, 500)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"strings"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type PathReq struct {
|
||||
|
@ -16,8 +18,14 @@ func Path(ctx *fiber.Ctx) error {
|
|||
if err := ctx.BodyParser(&req); err != nil {
|
||||
return ErrorResp(ctx, err, 400)
|
||||
}
|
||||
if !strings.HasPrefix(req.Path, "/") {
|
||||
req.Path = "/"+req.Path
|
||||
req.Path = utils.ParsePath(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 == "/" {
|
||||
return ctx.JSON(Resp{
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Exists determine whether the file exists
|
||||
|
@ -76,3 +77,11 @@ func WriteToJson(src string, conf interface{}) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ParsePath(path string) string {
|
||||
path = strings.TrimRight(path, "/")
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
return path
|
||||
}
|
Loading…
Reference in New Issue