first commit
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/bluele/gcache"
|
||||
subsonic "github.com/dweymouth/go-subsonic"
|
||||
)
|
||||
|
||||
type AlbumIterator interface {
|
||||
Next() *subsonic.AlbumID3
|
||||
NextN(int, func(*subsonic.AlbumID3))
|
||||
}
|
||||
|
||||
type LibraryManager struct {
|
||||
s *subsonic.Client
|
||||
albumCache gcache.Cache
|
||||
}
|
||||
|
||||
func NewLibraryManager(s *subsonic.Client) *LibraryManager {
|
||||
cache := gcache.New(250).LRU().Build()
|
||||
return &LibraryManager{
|
||||
s: s,
|
||||
albumCache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LibraryManager) RecentlyAddedIter() AlbumIterator {
|
||||
return l.newBaseIter("newest")
|
||||
}
|
||||
|
||||
func (l *LibraryManager) RecentlyPlayedIter() AlbumIterator {
|
||||
return l.newBaseIter("recent")
|
||||
}
|
||||
|
||||
func (l *LibraryManager) StarredIter() AlbumIterator {
|
||||
return l.newBaseIter("starred")
|
||||
}
|
||||
|
||||
func (l *LibraryManager) FrequentlyPlayedIter() AlbumIterator {
|
||||
return l.newBaseIter("frequent")
|
||||
}
|
||||
|
||||
func (l *LibraryManager) CacheAlbum(a *subsonic.AlbumID3) {
|
||||
l.albumCache.Set(a.ID, a)
|
||||
}
|
||||
|
||||
func (l *LibraryManager) GetAlbum(id string) (*subsonic.AlbumID3, error) {
|
||||
if l.albumCache.Has(id) {
|
||||
if a, err := l.albumCache.Get(id); err == nil {
|
||||
return a.(*subsonic.AlbumID3), nil
|
||||
}
|
||||
}
|
||||
a, err := l.s.GetAlbum(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.albumCache.Set(a.ID, a)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
type baseIter struct {
|
||||
listType string
|
||||
pos int
|
||||
l *LibraryManager
|
||||
s *subsonic.Client
|
||||
prefetched []*subsonic.AlbumID3
|
||||
prefetchedPos int
|
||||
done bool
|
||||
}
|
||||
|
||||
func (l *LibraryManager) newBaseIter(listType string) *baseIter {
|
||||
return &baseIter{
|
||||
listType: listType,
|
||||
l: l,
|
||||
s: l.s,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: figure out why the iterator sometimes returns an album twice
|
||||
|
||||
func (r *baseIter) Next() *subsonic.AlbumID3 {
|
||||
if r.done {
|
||||
return nil
|
||||
}
|
||||
if r.prefetched != nil {
|
||||
a := r.prefetched[r.prefetchedPos]
|
||||
r.prefetchedPos++
|
||||
if r.prefetchedPos == len(r.prefetched) {
|
||||
r.prefetched = nil
|
||||
r.prefetchedPos = 0
|
||||
}
|
||||
r.pos++
|
||||
|
||||
r.l.CacheAlbum(a)
|
||||
return a
|
||||
}
|
||||
albums, err := r.s.GetAlbumList2(r.listType, map[string]string{"size": "20", "offset": strconv.Itoa(r.pos)})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
albums = nil
|
||||
}
|
||||
if len(albums) == 0 {
|
||||
r.done = true
|
||||
return nil
|
||||
} else if len(albums) == 1 {
|
||||
r.l.CacheAlbum(albums[0])
|
||||
r.done = true
|
||||
return albums[0]
|
||||
}
|
||||
r.prefetched = albums
|
||||
r.prefetchedPos = 1
|
||||
|
||||
r.l.CacheAlbum(r.prefetched[0])
|
||||
return r.prefetched[0]
|
||||
}
|
||||
|
||||
func (r *baseIter) NextN(n int, cb func(*subsonic.AlbumID3)) {
|
||||
go func() {
|
||||
for i := 0; i < n; i++ {
|
||||
a := r.Next()
|
||||
cb(a)
|
||||
if a == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user