Skip to content

Commit

Permalink
feat: local storage image thumbnail
Browse files Browse the repository at this point in the history
  • Loading branch information
xhofe committed Aug 11, 2022
1 parent fda4db7 commit af88401
Show file tree
Hide file tree
Showing 19 changed files with 178 additions and 61 deletions.
57 changes: 49 additions & 8 deletions drivers/local/driver.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
package local

import (
"bytes"
"context"
"io"
"io/ioutil"
"net/http"
"os"
stdpath "path"
"path/filepath"
"strconv"
"strings"

"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/operations"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/alist-org/alist/v3/server/common"
"github.com/disintegration/imaging"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -54,7 +62,7 @@ func (d *Local) GetAddition() driver.Additional {
return d.Addition
}

func (d *Local) List(ctx context.Context, dir model.Obj) ([]model.Obj, error) {
func (d *Local) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
fullPath := dir.GetID()
rawFiles, err := ioutil.ReadDir(fullPath)
if err != nil {
Expand All @@ -65,11 +73,22 @@ func (d *Local) List(ctx context.Context, dir model.Obj) ([]model.Obj, error) {
if strings.HasPrefix(f.Name(), ".") {
continue
}
file := model.Object{
Name: f.Name(),
Modified: f.ModTime(),
Size: f.Size(),
IsFolder: f.IsDir(),
thumb := ""
if d.Thumbnail && utils.GetFileType(f.Name()) == conf.IMAGE {
thumb = common.GetApiUrl(nil) + stdpath.Join("/d", args.ReqPath, f.Name())
thumb = utils.EncodePath(thumb, true)
thumb += "?type=thumb"
}
file := model.ObjectThumbnail{
Object: model.Object{
Name: f.Name(),
Modified: f.ModTime(),
Size: f.Size(),
IsFolder: f.IsDir(),
},
Thumbnail: model.Thumbnail{
Thumbnail: thumb,
},
}
files = append(files, &file)
}
Expand All @@ -93,8 +112,30 @@ func (d *Local) Get(ctx context.Context, path string) (model.Obj, error) {

func (d *Local) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
fullPath := file.GetID()
link := model.Link{
FilePath: &fullPath,
var link model.Link
if args.Type == "thumb" && utils.Ext(file.GetName()) != "svg" {
imgData, err := ioutil.ReadFile(fullPath)
if err != nil {
return nil, err
}
srcBuf := bytes.NewBuffer(imgData)
image, err := imaging.Decode(srcBuf)
if err != nil {
return nil, err
}
thumbImg := imaging.Resize(image, 144, 0, imaging.Lanczos)
var buf bytes.Buffer
err = imaging.Encode(&buf, thumbImg, imaging.PNG)
if err != nil {
return nil, err
}
size := buf.Len()
link.Data = io.NopCloser(&buf)
link.Header = http.Header{
"Content-Length": []string{strconv.Itoa(size)},
}
} else {
link.FilePath = &fullPath
}
return &link, nil
}
Expand Down
1 change: 1 addition & 0 deletions drivers/local/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

type Addition struct {
driver.RootFolderPath
Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"`
}

var config = driver.Config{
Expand Down
2 changes: 1 addition & 1 deletion drivers/virtual/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (d *Virtual) GetAddition() driver.Additional {
return d.Addition
}

func (d *Virtual) List(ctx context.Context, dir model.Obj) ([]model.Obj, error) {
func (d *Virtual) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
var res []model.Obj
for i := 0; i < d.NumFile; i++ {
res = append(res, model.Object{
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (

require (
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
Expand Down Expand Up @@ -53,6 +54,7 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
Expand Down Expand Up @@ -230,6 +232,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
Expand Down
2 changes: 1 addition & 1 deletion internal/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type Reader interface {
// List files in the path
// if identify files by path, need to set ID with path,like path.Join(dir.GetID(), obj.GetName())
// if identify files by id, need to set ID with corresponding id
List(ctx context.Context, dir model.Obj) ([]model.Obj, error)
List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error)
// Link get url/filepath/reader of file
Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/fs/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func copyBetween2Storages(t *task.Task[uint64], srcStorage, dstStorage driver.Dr
}
if srcObj.IsDir() {
t.SetStatus("src object is dir, listing objs")
objs, err := operations.List(t.Ctx, srcStorage, srcObjPath)
objs, err := operations.List(t.Ctx, srcStorage, srcObjPath, model.ListArgs{})
if err != nil {
return errors.WithMessagef(err, "failed list src [%s] objs", srcObjPath)
}
Expand Down
4 changes: 3 additions & 1 deletion internal/fs/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ func list(ctx context.Context, path string) ([]model.Obj, error) {
}
return nil, errors.WithMessage(err, "failed get storage")
}
objs, err := operations.List(ctx, storage, actualPath)
objs, err := operations.List(ctx, storage, actualPath, model.ListArgs{
ReqPath: path,
})
if err != nil {
log.Errorf("%+v", err)
if len(virtualFiles) != 0 {
Expand Down
5 changes: 5 additions & 0 deletions internal/model/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ import (
"time"
)

type ListArgs struct {
ReqPath string
}

type LinkArgs struct {
IP string
Header http.Header
Type string
}

type Link struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/model/obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ type URL interface {
URL() string
}

type Thumbnail interface {
Thumbnail() string
type Thumb interface {
Thumb() string
}

type SetID interface {
Expand Down
37 changes: 25 additions & 12 deletions internal/model/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,39 @@ type Object struct {
IsFolder bool
}

func (f Object) GetName() string {
return f.Name
func (o Object) GetName() string {
return o.Name
}

func (f Object) GetSize() int64 {
return f.Size
func (o Object) GetSize() int64 {
return o.Size
}

func (f Object) ModTime() time.Time {
return f.Modified
func (o Object) ModTime() time.Time {
return o.Modified
}

func (f Object) IsDir() bool {
return f.IsFolder
func (o Object) IsDir() bool {
return o.IsFolder
}

func (f Object) GetID() string {
return f.ID
func (o Object) GetID() string {
return o.ID
}

func (f *Object) SetID(id string) {
f.ID = id
func (o *Object) SetID(id string) {
o.ID = id
}

type Thumbnail struct {
Thumbnail string
}

func (t Thumbnail) Thumb() string {
return t.Thumbnail
}

type ObjectThumbnail struct {
Object
Thumbnail
}
10 changes: 5 additions & 5 deletions internal/operations/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func ClearCache(storage driver.Driver, path string) {
}

// List files in storage, not contains virtual file
func List(ctx context.Context, storage driver.Driver, path string, refresh ...bool) ([]model.Obj, error) {
func List(ctx context.Context, storage driver.Driver, path string, args model.ListArgs, refresh ...bool) ([]model.Obj, error) {
path = utils.StandardizePath(path)
log.Debugf("operations.List %s", path)
dir, err := Get(ctx, storage, path)
Expand All @@ -39,7 +39,7 @@ func List(ctx context.Context, storage driver.Driver, path string, refresh ...bo
return nil, errors.WithStack(errs.NotFolder)
}
if storage.Config().NoCache {
return storage.List(ctx, dir)
return storage.List(ctx, dir, args)
}
key := stdpath.Join(storage.GetStorage().MountPath, path)
if len(refresh) == 0 || !refresh[0] {
Expand All @@ -48,7 +48,7 @@ func List(ctx context.Context, storage driver.Driver, path string, refresh ...bo
}
}
files, err, _ := filesG.Do(key, func() ([]model.Obj, error) {
files, err := storage.List(ctx, dir)
files, err := storage.List(ctx, dir, args)
if err != nil {
return nil, errors.WithMessage(err, "failed to list files")
}
Expand Down Expand Up @@ -99,7 +99,7 @@ func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, er
}
// not root folder
dir, name := stdpath.Split(path)
files, err := List(ctx, storage, dir)
files, err := List(ctx, storage, dir, model.ListArgs{})
if err != nil {
return nil, errors.WithMessage(err, "failed get parent list")
}
Expand Down Expand Up @@ -148,7 +148,7 @@ func Link(ctx context.Context, storage driver.Driver, path string, args model.Li
return link, file, err
}

// other api
// Other api
func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (interface{}, error) {
obj, err := Get(ctx, storage, args.Path)
if err != nil {
Expand Down
24 changes: 24 additions & 0 deletions pkg/utils/path.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package utils

import (
"net/url"
stdpath "path"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -36,3 +37,26 @@ func Ext(path string) string {
}
return ext
}

func EncodePath(path string, all ...bool) string {
seg := strings.Split(path, "/")
toReplace := []struct {
Src string
Dst string
}{
{Src: "%", Dst: "%25"},
{"%", "%25"},
{"?", "%3F"},
{"#", "%23"},
}
for i := range seg {
if len(all) > 0 && all[0] {
seg[i] = url.PathEscape(seg[i])
} else {
for j := range toReplace {
seg[i] = strings.ReplaceAll(seg[i], toReplace[j].Src, toReplace[j].Dst)
}
}
}
return strings.Join(seg, "/")
}
7 changes: 7 additions & 0 deletions pkg/utils/path_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package utils

import "testing"

func TestEncodePath(t *testing.T) {
t.Log(EncodePath("http://localhost:5244/d/123#.png"))
}
20 changes: 11 additions & 9 deletions server/common/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import (
"github.com/alist-org/alist/v3/internal/setting"
)

func GetBaseUrl(r *http.Request) string {
baseUrl := setting.GetByKey(conf.ApiUrl)
func GetApiUrl(r *http.Request) string {
api := setting.GetByKey(conf.ApiUrl)
protocol := "http"
if r.TLS != nil {
protocol = "https"
if r != nil {
if r.TLS != nil {
protocol = "https"
}
if api == "" {
api = fmt.Sprintf("%s://%s", protocol, r.Host)
}
}
if baseUrl == "" {
baseUrl = fmt.Sprintf("%s://%s", protocol, r.Host)
}
strings.TrimSuffix(baseUrl, "/")
return baseUrl
strings.TrimSuffix(api, "/")
return api
}
7 changes: 6 additions & 1 deletion server/handles/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func Down(c *gin.Context) {
link, _, err := fs.Link(c, rawPath, model.LinkArgs{
IP: c.ClientIP(),
Header: c.Request.Header,
Type: c.Query("type"),
})
if err != nil {
common.ErrorResp(c, err, 500)
Expand All @@ -52,13 +53,17 @@ func Proxy(c *gin.Context) {
if downProxyUrl != "" {
_, ok := c.GetQuery("d")
if ok {
URL := fmt.Sprintf("%s%s?sign=%s", strings.Split(downProxyUrl, "\n")[0], rawPath, sign.Sign(filename))
URL := fmt.Sprintf("%s%s?sign=%s",
strings.Split(downProxyUrl, "\n")[0],
utils.EncodePath(rawPath),
sign.Sign(filename))
c.Redirect(302, URL)
return
}
}
link, file, err := fs.Link(c, rawPath, model.LinkArgs{
Header: c.Request.Header,
Type: c.Query("type"),
})
if err != nil {
common.ErrorResp(c, err, 500)
Expand Down
Loading

0 comments on commit af88401

Please sign in to comment.