mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-11-25 03:15:19 +08:00
feat(style): add driver icons and disk usage (#1274)
* feat(style): add driver icons and disk usage * feat(driver): add disk usage for 115_open, 123_open, aliyundrive_open and baidu_netdisk * feat(driver): add disk usage for crypt, sftp and smb * chore: clean unused variable * feat(driver): add disk usage for cloudreve_v4 Signed-off-by: MadDogOwner <xiaoran@xrgzs.top> * fix(local): disk label check when getting disk usage * feat(style): return details when accessing the manage page --------- Signed-off-by: MadDogOwner <xiaoran@xrgzs.top> Co-authored-by: MadDogOwner <xiaoran@xrgzs.top>
This commit is contained in:
@@ -114,6 +114,7 @@ func InitialSettings() []model.SettingItem {
|
||||
{Key: "share_icon", Value: "🎁", Type: conf.TypeString, Group: model.STYLE},
|
||||
{Key: "home_container", Value: "max_980px", Type: conf.TypeSelect, Options: "max_980px,hope_container", Group: model.STYLE},
|
||||
{Key: "settings_layout", Value: "list", Type: conf.TypeSelect, Options: "list,responsive", Group: model.STYLE},
|
||||
{Key: conf.HideStorageDetails, Value: "false", Type: conf.TypeBool, Group: model.STYLE, Flag: model.PRIVATE},
|
||||
// preview settings
|
||||
{Key: conf.TextTypes, Value: "txt,htm,html,xml,java,properties,sql,js,md,json,conf,ini,vue,php,py,bat,gitignore,yml,go,sh,c,cpp,h,hpp,tsx,vtt,srt,ass,rs,lrc,strm", Type: conf.TypeText, Group: model.PREVIEW, Flag: model.PRIVATE},
|
||||
{Key: conf.AudioTypes, Value: "mp3,flac,ogg,m4a,wav,opus,wma", Type: conf.TypeText, Group: model.PREVIEW, Flag: model.PRIVATE},
|
||||
|
||||
@@ -17,9 +17,10 @@ const (
|
||||
AllowMounted = "allow_mounted"
|
||||
RobotsTxt = "robots_txt"
|
||||
|
||||
Logo = "logo" // multi-lines text, L1: light, EOL: dark
|
||||
Favicon = "favicon"
|
||||
MainColor = "main_color"
|
||||
Logo = "logo" // multi-lines text, L1: light, EOL: dark
|
||||
Favicon = "favicon"
|
||||
MainColor = "main_color"
|
||||
HideStorageDetails = "hide_storage_details"
|
||||
|
||||
// preview
|
||||
TextTypes = "text_types"
|
||||
|
||||
@@ -210,6 +210,11 @@ type ArchiveDecompressResult interface {
|
||||
ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) ([]model.Obj, error)
|
||||
}
|
||||
|
||||
type WithDetails interface {
|
||||
// GetDetails get storage details (total space, free space, etc.)
|
||||
GetDetails(ctx context.Context) (*model.StorageDetails, error)
|
||||
}
|
||||
|
||||
type Reference interface {
|
||||
InitReference(storage Driver) error
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@ import (
|
||||
// then pass the actual path to the op package
|
||||
|
||||
type ListArgs struct {
|
||||
Refresh bool
|
||||
NoLog bool
|
||||
Refresh bool
|
||||
NoLog bool
|
||||
WithStorageDetails bool
|
||||
}
|
||||
|
||||
func List(ctx context.Context, path string, args *ListArgs) ([]model.Obj, error) {
|
||||
@@ -35,11 +36,12 @@ func List(ctx context.Context, path string, args *ListArgs) ([]model.Obj, error)
|
||||
}
|
||||
|
||||
type GetArgs struct {
|
||||
NoLog bool
|
||||
NoLog bool
|
||||
WithStorageDetails bool
|
||||
}
|
||||
|
||||
func Get(ctx context.Context, path string, args *GetArgs) (model.Obj, error) {
|
||||
res, err := get(ctx, path)
|
||||
res, err := get(ctx, path, args)
|
||||
if err != nil {
|
||||
if !args.NoLog {
|
||||
log.Warnf("failed get %s: %s", path, err)
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func get(ctx context.Context, path string) (model.Obj, error) {
|
||||
func get(ctx context.Context, path string, args *GetArgs) (model.Obj, error) {
|
||||
path = utils.FixAndCleanPath(path)
|
||||
// maybe a virtual file
|
||||
if path != "/" {
|
||||
virtualFiles := op.GetStorageVirtualFilesByPath(stdpath.Dir(path))
|
||||
virtualFiles := op.GetStorageVirtualFilesWithDetailsByPath(ctx, stdpath.Dir(path), !args.WithStorageDetails)
|
||||
for _, f := range virtualFiles {
|
||||
if f.GetName() == stdpath.Base(path) {
|
||||
return f, nil
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
func list(ctx context.Context, path string, args *ListArgs) ([]model.Obj, error) {
|
||||
meta, _ := ctx.Value(conf.MetaKey).(*model.Meta)
|
||||
user, _ := ctx.Value(conf.UserKey).(*model.User)
|
||||
virtualFiles := op.GetStorageVirtualFilesByPath(path)
|
||||
virtualFiles := op.GetStorageVirtualFilesWithDetailsByPath(ctx, path, !args.WithStorageDetails)
|
||||
storage, actualPath, err := op.GetStorageAndActualPath(path)
|
||||
if err != nil && len(virtualFiles) == 0 {
|
||||
return nil, errors.WithMessage(err, "failed get storage")
|
||||
|
||||
@@ -55,3 +55,40 @@ func (p Proxy) Webdav302() bool {
|
||||
func (p Proxy) WebdavProxyURL() bool {
|
||||
return p.WebdavPolicy == "use_proxy_url"
|
||||
}
|
||||
|
||||
type DiskUsage struct {
|
||||
TotalSpace uint64 `json:"total_space"`
|
||||
FreeSpace uint64 `json:"free_space"`
|
||||
}
|
||||
|
||||
type StorageDetails struct {
|
||||
DiskUsage
|
||||
}
|
||||
|
||||
type StorageDetailsWithName struct {
|
||||
*StorageDetails
|
||||
DriverName string `json:"driver_name"`
|
||||
}
|
||||
|
||||
type ObjWithStorageDetails interface {
|
||||
GetStorageDetails() *StorageDetailsWithName
|
||||
}
|
||||
|
||||
type ObjStorageDetails struct {
|
||||
Obj
|
||||
StorageDetailsWithName
|
||||
}
|
||||
|
||||
func (o ObjStorageDetails) GetStorageDetails() *StorageDetailsWithName {
|
||||
return &o.StorageDetailsWithName
|
||||
}
|
||||
|
||||
func GetStorageDetails(obj Obj) (*StorageDetailsWithName, bool) {
|
||||
if obj, ok := obj.(ObjWithStorageDetails); ok {
|
||||
return obj.GetStorageDetails(), true
|
||||
}
|
||||
if unwrap, ok := obj.(ObjUnwrap); ok {
|
||||
return GetStorageDetails(unwrap.Unwrap())
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/generic_sync"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -335,6 +334,40 @@ func getStoragesByPath(path string) []driver.Driver {
|
||||
// for example, there are: /a/b,/a/c,/a/d/e,/a/b.balance1,/av
|
||||
// GetStorageVirtualFilesByPath(/a) => b,c,d
|
||||
func GetStorageVirtualFilesByPath(prefix string) []model.Obj {
|
||||
return getStorageVirtualFilesByPath(prefix, func(_ driver.Driver, obj model.Obj) model.Obj {
|
||||
return obj
|
||||
})
|
||||
}
|
||||
|
||||
func GetStorageVirtualFilesWithDetailsByPath(ctx context.Context, prefix string, hideDetails ...bool) []model.Obj {
|
||||
if utils.IsBool(hideDetails...) {
|
||||
return GetStorageVirtualFilesByPath(prefix)
|
||||
}
|
||||
return getStorageVirtualFilesByPath(prefix, func(d driver.Driver, obj model.Obj) model.Obj {
|
||||
ret := &model.ObjStorageDetails{
|
||||
Obj: obj,
|
||||
StorageDetailsWithName: model.StorageDetailsWithName{
|
||||
StorageDetails: nil,
|
||||
DriverName: d.Config().Name,
|
||||
},
|
||||
}
|
||||
storage, ok := d.(driver.WithDetails)
|
||||
if !ok {
|
||||
return ret
|
||||
}
|
||||
details, err := storage.GetDetails(ctx)
|
||||
if err != nil {
|
||||
if !errors.Is(err, errs.NotImplement) {
|
||||
log.Errorf("failed get %s storage details: %+v", d.GetStorage().MountPath, err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
ret.StorageDetails = details
|
||||
return ret
|
||||
})
|
||||
}
|
||||
|
||||
func getStorageVirtualFilesByPath(prefix string, rootCallback func(driver.Driver, model.Obj) model.Obj) []model.Obj {
|
||||
files := make([]model.Obj, 0)
|
||||
storages := storagesMap.Values()
|
||||
sort.Slice(storages, func(i, j int) bool {
|
||||
@@ -345,21 +378,30 @@ func GetStorageVirtualFilesByPath(prefix string) []model.Obj {
|
||||
})
|
||||
|
||||
prefix = utils.FixAndCleanPath(prefix)
|
||||
set := mapset.NewSet[string]()
|
||||
set := make(map[string]int)
|
||||
for _, v := range storages {
|
||||
mountPath := utils.GetActualMountPath(v.GetStorage().MountPath)
|
||||
// Exclude prefix itself and non prefix
|
||||
if len(prefix) >= len(mountPath) || !utils.IsSubPath(prefix, mountPath) {
|
||||
continue
|
||||
}
|
||||
name := strings.SplitN(strings.TrimPrefix(mountPath[len(prefix):], "/"), "/", 2)[0]
|
||||
if set.Add(name) {
|
||||
files = append(files, &model.Object{
|
||||
Name: name,
|
||||
names := strings.SplitN(strings.TrimPrefix(mountPath[len(prefix):], "/"), "/", 2)
|
||||
idx, ok := set[names[0]]
|
||||
if !ok {
|
||||
set[names[0]] = len(files)
|
||||
obj := &model.Object{
|
||||
Name: names[0],
|
||||
Size: 0,
|
||||
Modified: v.GetStorage().Modified,
|
||||
IsFolder: true,
|
||||
})
|
||||
}
|
||||
if len(names) == 1 {
|
||||
files = append(files, rootCallback(v, obj))
|
||||
} else {
|
||||
files = append(files, obj)
|
||||
}
|
||||
} else if len(names) == 1 {
|
||||
files[idx] = rootCallback(v, files[idx])
|
||||
}
|
||||
}
|
||||
return files
|
||||
|
||||
Reference in New Issue
Block a user