add album cover scaling and caching

This commit is contained in:
Duncan Overbruck
2020-07-24 16:47:15 +02:00
committed by Senan Kelly
parent ed5ab1f06a
commit ae98a18b52
3 changed files with 55 additions and 17 deletions

1
go.mod
View File

@@ -5,6 +5,7 @@ require (
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/cespare/xxhash v1.1.0
github.com/disintegration/imaging v1.6.2
github.com/dustin/go-humanize v1.0.0
github.com/faiface/beep v1.0.2
github.com/google/uuid v1.1.1 // indirect

3
go.sum
View File

@@ -20,6 +20,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
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/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
@@ -169,6 +171,7 @@ golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMx
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20180806140643-507816974b79 h1:t2JRgCWkY7Qaa1J2jal+wqC9OjbyHCHwIA9rVlRUSMo=

View File

@@ -1,12 +1,15 @@
package ctrlsubsonic
import (
"fmt"
"io"
"log"
"net/http"
"os"
"path"
"time"
"github.com/disintegration/imaging"
"github.com/jinzhu/gorm"
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
@@ -53,30 +56,61 @@ func streamUpdateStats(dbc *db.DB, userID, albumID int) {
dbc.Save(&play)
}
const (
coverDefaultSize = 600
coverCacheFormat = "png"
)
func (c *Controller) ServeGetCoverArt(w http.ResponseWriter, r *http.Request) *spec.Response {
params := r.Context().Value(CtxParams).(params.Params)
id, err := params.GetID("id")
if err != nil {
return spec.NewError(10, "please provide an `id` parameter")
}
folder := &db.Album{}
err = c.DB.
Select("id, left_path, right_path, cover").
First(folder, id.Value).
Error
if gorm.IsRecordNotFoundError(err) {
return spec.NewError(10, "could not find a cover with that id")
size := params.GetOrInt("size", coverDefaultSize)
cacheFile := fmt.Sprintf("%s/%s-%d.%s", c.CachePath, id.String(), size,
coverCacheFormat)
_, err = os.Stat(cacheFile)
if os.IsNotExist(err) {
log.Printf("serving cover `%s`: cache [%s/%d] miss!\n",
cacheFile, coverCacheFormat, size)
folder := &db.Album{}
err = c.DB.
Select("id, left_path, right_path, cover").
First(folder, id.Value).
Error
if gorm.IsRecordNotFoundError(err) {
return spec.NewError(10, "could not find a cover with that id")
}
if folder.Cover == "" {
return spec.NewError(10, "no cover found for that folder")
}
absPath := path.Join(
c.MusicPath,
folder.LeftPath,
folder.RightPath,
folder.Cover,
)
src, err := imaging.Open(absPath)
if err != nil {
log.Printf("resizing cover `%s`: error: %v\n", absPath, err)
return nil
}
width := size
if width > src.Bounds().Dx() {
// don't upscale images
width = src.Bounds().Dx()
}
err = imaging.Save(imaging.Resize(src, width, 0, imaging.Lanczos), cacheFile)
if err != nil {
log.Printf("caching cover `%s`: error: %v\n", cacheFile, err)
return nil
}
} else {
log.Printf("serving cover `%s`: cache [%s/%d] hit!\n",
cacheFile, coverCacheFormat, size)
}
if folder.Cover == "" {
return spec.NewError(10, "no cover found for that folder")
}
absPath := path.Join(
c.MusicPath,
folder.LeftPath,
folder.RightPath,
folder.Cover,
)
http.ServeFile(w, r, absPath)
http.ServeFile(w, r, cacheFile)
return nil
}