93 lines
2.1 KiB
Go
93 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/peterbourgon/diskv"
|
|
)
|
|
|
|
// An AlbumCoverCache is used to fetch and cache Album Cover image from www.bedetheque.com
|
|
type AlbumCoverCache struct {
|
|
dv *diskv.Diskv
|
|
getter HTTPGetter
|
|
// time to live of the cache, data which is older than this TTL will be automatically removed
|
|
TTL time.Duration
|
|
}
|
|
|
|
// NewAlbumCoverCache is creating a new cache at specified location on the fs
|
|
func NewAlbumCoverCache(basepath string, maxRequest uint, window time.Duration) *AlbumCoverCache {
|
|
res := &AlbumCoverCache{
|
|
dv: diskv.New(diskv.Options{
|
|
BasePath: basepath,
|
|
CacheSizeMax: 100 * 1024 * 1024, // 100 Mb
|
|
}),
|
|
getter: NewRateLimitedGetter(maxRequest, window),
|
|
TTL: 3 * 31 * 24 * time.Hour, // 3 Months
|
|
}
|
|
return res
|
|
}
|
|
|
|
func (c *AlbumCoverCache) fetch(a *Album) (io.ReadCloser, error) {
|
|
resp, err := c.getter.Get(a.CoverURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer closeOrPanic(resp.Body, "GET "+a.CoverURL)
|
|
|
|
err = c.dv.WriteStream(c.dataKey(a), resp.Body, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
md := coverMetadata{
|
|
Age: time.Now(),
|
|
}
|
|
mdbyte, err := json.Marshal(&md)
|
|
if err == nil {
|
|
err = c.dv.Write(c.metadataKey(a), mdbyte)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return c.dv.ReadStream(c.dataKey(a), false)
|
|
}
|
|
|
|
type coverMetadata struct {
|
|
Age time.Time
|
|
}
|
|
|
|
func (c *AlbumCoverCache) metadataKey(a *Album) string {
|
|
return AlbumIDString(a.ID) + ".metadata"
|
|
}
|
|
|
|
func (c *AlbumCoverCache) dataKey(a *Album) string {
|
|
return AlbumIDString(a.ID) + ".data"
|
|
}
|
|
|
|
// GetCover retrieves from the cache or either from www.bedetheque.com the Cover of an album
|
|
func (c *AlbumCoverCache) GetCover(a *Album) (io.ReadCloser, error) {
|
|
//
|
|
if c.dv.Has(c.metadataKey(a)) == false {
|
|
return c.fetch(a)
|
|
}
|
|
|
|
mdbytes, err := c.dv.Read(c.metadataKey(a))
|
|
if err != nil {
|
|
return c.fetch(a)
|
|
}
|
|
var md coverMetadata
|
|
err = json.Unmarshal(mdbytes, &md)
|
|
if err != nil {
|
|
return c.fetch(a)
|
|
}
|
|
|
|
// check TTL
|
|
if time.Now().Add(-c.TTL).After(md.Age) == true {
|
|
return c.fetch(a)
|
|
}
|
|
|
|
return c.dv.ReadStream(c.dataKey(a), false)
|
|
}
|