diff --git a/drivers/local/driver.go b/drivers/local/driver.go index 3535df94..7bceeb87 100644 --- a/drivers/local/driver.go +++ b/drivers/local/driver.go @@ -1,7 +1,6 @@ package local import ( - "bytes" "context" "errors" "fmt" @@ -20,7 +19,6 @@ import ( "github.com/alist-org/alist/v3/internal/sign" "github.com/alist-org/alist/v3/pkg/utils" "github.com/alist-org/alist/v3/server/common" - "github.com/disintegration/imaging" _ "golang.org/x/image/webp" ) @@ -54,6 +52,12 @@ func (d *Local) Init(ctx context.Context) error { } d.Addition.RootFolderPath = abs } + if d.ThumbCacheFolder != "" && !utils.Exists(d.ThumbCacheFolder) { + err := os.MkdirAll(d.ThumbCacheFolder, os.FileMode(d.mkdirPerm)) + if err != nil { + return err + } + } return nil } @@ -135,36 +139,18 @@ func (d *Local) Link(ctx context.Context, file model.Obj, args model.LinkArgs) ( fullPath := file.GetPath() var link model.Link if args.Type == "thumb" && utils.Ext(file.GetName()) != "svg" { - var srcBuf *bytes.Buffer - if utils.GetFileType(file.GetName()) == conf.VIDEO { - videoBuf, err := GetSnapshot(fullPath, 10) - if err != nil { - return nil, err - } - srcBuf = videoBuf - } else { - imgData, err := os.ReadFile(fullPath) - if err != nil { - return nil, err - } - imgBuf := bytes.NewBuffer(imgData) - srcBuf = imgBuf - } - - image, err := imaging.Decode(srcBuf) + buf, thumbPath, err := d.getThumb(file) 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)}, + "Content-Type": []string{"image/png"}, + } + if thumbPath != nil { + link.FilePath = thumbPath + } else { + link.Data = io.NopCloser(buf) + link.Header.Set("Content-Length", strconv.Itoa(buf.Len())) } } else { link.FilePath = &fullPath diff --git a/drivers/local/meta.go b/drivers/local/meta.go index efaad4c9..00c8f5ce 100644 --- a/drivers/local/meta.go +++ b/drivers/local/meta.go @@ -7,9 +7,10 @@ import ( type Addition struct { driver.RootPath - Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"` - ShowHidden bool `json:"show_hidden" default:"true" required:"false" help:"show hidden directories and files"` - MkdirPerm string `json:"mkdir_perm" default:"777"` + Thumbnail bool `json:"thumbnail" required:"true" help:"enable thumbnail"` + ThumbCacheFolder string `json:"thumb_cache_folder"` + ShowHidden bool `json:"show_hidden" default:"true" required:"false" help:"show hidden directories and files"` + MkdirPerm string `json:"mkdir_perm" default:"777"` } var config = driver.Config{ diff --git a/drivers/local/util.go b/drivers/local/util.go index d782783d..0985ea99 100644 --- a/drivers/local/util.go +++ b/drivers/local/util.go @@ -7,7 +7,12 @@ import ( "os" "path/filepath" "sort" + "strings" + "github.com/alist-org/alist/v3/internal/conf" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/utils" + "github.com/disintegration/imaging" ffmpeg "github.com/u2takey/ffmpeg-go" ) @@ -55,3 +60,52 @@ func readDir(dirname string) ([]fs.FileInfo, error) { sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) return list, nil } + +func (d *Local) getThumb(file model.Obj) (*bytes.Buffer, *string, error) { + fullPath := file.GetPath() + thumbPrefix := "alist_thumb_" + thumbName := thumbPrefix + utils.GetMD5Encode(fullPath) + ".png" + if d.ThumbCacheFolder != "" { + // skip if the file is a thumbnail + if strings.HasPrefix(file.GetName(), thumbPrefix) { + return nil, &fullPath, nil + } + thumbPath := filepath.Join(d.ThumbCacheFolder, thumbName) + if utils.Exists(thumbPath) { + return nil, &thumbPath, nil + } + } + var srcBuf *bytes.Buffer + if utils.GetFileType(file.GetName()) == conf.VIDEO { + videoBuf, err := GetSnapshot(fullPath, 10) + if err != nil { + return nil, nil, err + } + srcBuf = videoBuf + } else { + imgData, err := os.ReadFile(fullPath) + if err != nil { + return nil, nil, err + } + imgBuf := bytes.NewBuffer(imgData) + srcBuf = imgBuf + } + + image, err := imaging.Decode(srcBuf) + if err != nil { + return nil, 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, nil, err + } + if d.ThumbCacheFolder != "" { + err = os.WriteFile(filepath.Join(d.ThumbCacheFolder, thumbName), buf.Bytes(), 0666) + if err != nil { + return nil, nil, err + } + } + return &buf, nil, nil +}