From 1bc68c20fc87e082d4f7bf2f7e950f26b02cbf95 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 4 Apr 2020 22:23:20 -0400 Subject: [PATCH] Create and configure image cache --- Makefile | 4 ++++ conf/configuration.go | 1 + consts/consts.go | 7 ++++++- engine/cover.go | 34 ++++++++++++++++++++++++++++++---- engine/media_streamer.go | 8 +++++--- engine/wire_providers.go | 1 + wire_gen.go | 10 +++++++--- 7 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 94fd3a880..2dcb60631 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,10 @@ server: check_go_env @reflex -d none -c reflex.conf .PHONY: server +wire: check_go_env + wire ./... +.PHONY: wire + watch: check_go_env ginkgo watch -notify ./... .PHONY: watch diff --git a/conf/configuration.go b/conf/configuration.go index 30256c4ba..5ee4b5dde 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -26,6 +26,7 @@ type nd struct { IndexGroups string `default:"A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)"` TranscodingCacheSize string `default:"100MB"` // in MB + ImageCacheSize string `default:"100MB"` // in MB ProbeCommand string `default:"ffmpeg -i %s -f ffmetadata"` // DevFlags. These are used to enable/disable debugging and incomplete features diff --git a/consts/consts.go b/consts/consts.go index 270de6e83..bf4e7ff5b 100644 --- a/consts/consts.go +++ b/consts/consts.go @@ -20,11 +20,16 @@ const ( UIAssetsLocalPath = "ui/build" - CacheDir = "cache" + TranscodingCacheDir = "cache/transcoding" DefaultTranscodingCacheSize = 100 * 1024 * 1024 // 100MB DefaultTranscodingCacheMaxItems = 0 // Unlimited DefaultTranscodingCachePurgeInterval = 10 * time.Minute + ImageCacheDir = "cache/images" + DefaultImageCacheSize = 100 * 1024 * 1024 // 100MB + DefaultImageCacheMaxItems = 0 // Unlimited + DefaultImageCachePurgeInterval = 10 * time.Minute + DevInitialUserName = "admin" DevInitialName = "Dev Admin" diff --git a/engine/cover.go b/engine/cover.go index 123df1a40..95c349345 100644 --- a/engine/cover.go +++ b/engine/cover.go @@ -11,24 +11,33 @@ import ( "io" "net/http" "os" + "path/filepath" "strings" + "github.com/deluan/navidrome/conf" + "github.com/deluan/navidrome/consts" + "github.com/deluan/navidrome/log" "github.com/deluan/navidrome/model" "github.com/deluan/navidrome/static" "github.com/dhowden/tag" "github.com/disintegration/imaging" + "github.com/djherbis/fscache" + "github.com/dustin/go-humanize" ) type Cover interface { Get(ctx context.Context, id string, size int, out io.Writer) error } -type cover struct { - ds model.DataStore +type ImageCache fscache.Cache + +func NewCover(ds model.DataStore, cache ImageCache) Cover { + return &cover{ds: ds, cache: cache} } -func NewCover(ds model.DataStore) Cover { - return &cover{ds} +type cover struct { + ds model.DataStore + cache fscache.Cache } func (c *cover) getCoverPath(ctx context.Context, id string) (string, error) { @@ -116,3 +125,20 @@ func readFromTag(path string) (io.Reader, error) { } return bytes.NewReader(picture.Data), nil } + +func NewImageCache() (ImageCache, error) { + cacheSize, err := humanize.ParseBytes(conf.Server.ImageCacheSize) + if err != nil { + cacheSize = consts.DefaultImageCacheSize + } + lru := fscache.NewLRUHaunter(consts.DefaultImageCacheMaxItems, int64(cacheSize), consts.DefaultImageCachePurgeInterval) + h := fscache.NewLRUHaunterStrategy(lru) + cacheFolder := filepath.Join(conf.Server.DataFolder, consts.ImageCacheDir) + log.Info("Creating image cache", "path", cacheFolder, "maxSize", humanize.Bytes(cacheSize), + "cleanUpInterval", consts.DefaultImageCachePurgeInterval) + fs, err := fscache.NewFs(cacheFolder, 0755) + if err != nil { + return nil, err + } + return fscache.NewCacheWithHaunter(fs, h) +} diff --git a/engine/media_streamer.go b/engine/media_streamer.go index 835908a0f..f6aa1d1bd 100644 --- a/engine/media_streamer.go +++ b/engine/media_streamer.go @@ -22,7 +22,9 @@ type MediaStreamer interface { NewStream(ctx context.Context, id string, reqFormat string, reqBitRate int) (*Stream, error) } -func NewMediaStreamer(ds model.DataStore, ffm transcoder.Transcoder, cache fscache.Cache) MediaStreamer { +type TranscodingCache fscache.Cache + +func NewMediaStreamer(ds model.DataStore, ffm transcoder.Transcoder, cache TranscodingCache) MediaStreamer { return &mediaStreamer{ds: ds, ffm: ffm, cache: cache} } @@ -205,14 +207,14 @@ func getFinalCachedSize(r fscache.ReadAtCloser) int64 { return -1 } -func NewTranscodingCache() (fscache.Cache, error) { +func NewTranscodingCache() (TranscodingCache, error) { cacheSize, err := humanize.ParseBytes(conf.Server.TranscodingCacheSize) if err != nil { cacheSize = consts.DefaultTranscodingCacheSize } lru := fscache.NewLRUHaunter(consts.DefaultTranscodingCacheMaxItems, int64(cacheSize), consts.DefaultTranscodingCachePurgeInterval) h := fscache.NewLRUHaunterStrategy(lru) - cacheFolder := filepath.Join(conf.Server.DataFolder, consts.CacheDir) + cacheFolder := filepath.Join(conf.Server.DataFolder, consts.TranscodingCacheDir) log.Info("Creating transcoding cache", "path", cacheFolder, "maxSize", humanize.Bytes(cacheSize), "cleanUpInterval", consts.DefaultTranscodingCachePurgeInterval) fs, err := fscache.NewFs(cacheFolder, 0755) diff --git a/engine/wire_providers.go b/engine/wire_providers.go index 17d76f8ec..58fd05d40 100644 --- a/engine/wire_providers.go +++ b/engine/wire_providers.go @@ -18,5 +18,6 @@ var Set = wire.NewSet( NewMediaStreamer, transcoder.New, NewTranscodingCache, + NewImageCache, NewPlayers, ) diff --git a/wire_gen.go b/wire_gen.go index 36f7296ad..6ff1c97e4 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -34,7 +34,11 @@ func CreateAppRouter() *app.Router { func CreateSubsonicAPIRouter() (*subsonic.Router, error) { dataStore := persistence.New() browser := engine.NewBrowser(dataStore) - cover := engine.NewCover(dataStore) + imageCache, err := engine.NewImageCache() + if err != nil { + return nil, err + } + cover := engine.NewCover(dataStore, imageCache) nowPlayingRepository := engine.NewNowPlayingRepository() listGenerator := engine.NewListGenerator(dataStore, nowPlayingRepository) users := engine.NewUsers(dataStore) @@ -43,11 +47,11 @@ func CreateSubsonicAPIRouter() (*subsonic.Router, error) { scrobbler := engine.NewScrobbler(dataStore, nowPlayingRepository) search := engine.NewSearch(dataStore) transcoderTranscoder := transcoder.New() - cache, err := engine.NewTranscodingCache() + transcodingCache, err := engine.NewTranscodingCache() if err != nil { return nil, err } - mediaStreamer := engine.NewMediaStreamer(dataStore, transcoderTranscoder, cache) + mediaStreamer := engine.NewMediaStreamer(dataStore, transcoderTranscoder, transcodingCache) players := engine.NewPlayers(dataStore) router := subsonic.New(browser, cover, listGenerator, users, playlists, ratings, scrobbler, search, mediaStreamer, players) return router, nil