Implemented artists indexing, with Gomate

This commit is contained in:
Deluan 2016-03-10 23:19:13 -05:00
parent 7c75084249
commit df957814a0
9 changed files with 79 additions and 26 deletions

View File

@ -9,6 +9,7 @@ github.com/smartystreets/goconvey = commit:899ed5a
github.com/karlkfi/inject = commit:fe06da2 github.com/karlkfi/inject = commit:fe06da2
github.com/dhowden/tag = commit:bccc91e github.com/dhowden/tag = commit:bccc91e
github.com/nfnt/resize = commit:4d93a29 github.com/nfnt/resize = commit:4d93a29
github.com/deluan/gomate =
[res] [res]
include = conf include = conf

View File

@ -16,6 +16,7 @@ install:
- go get github.com/smartystreets/goconvey - go get github.com/smartystreets/goconvey
- go get github.com/dhowden/tag - go get github.com/dhowden/tag
- go get github.com/nfnt/resize - go get github.com/nfnt/resize
- go get github.com/deluan/gomate
script: script:
- go test ./... -v - go test ./... -v

View File

@ -1,10 +1,13 @@
package conf package conf
import ( import (
"github.com/deluan/gomate"
"github.com/deluan/gosonic/domain" "github.com/deluan/gosonic/domain"
"github.com/deluan/gosonic/engine" "github.com/deluan/gosonic/engine"
"github.com/deluan/gosonic/persistence" "github.com/deluan/gosonic/persistence"
"github.com/deluan/gosonic/utils" "github.com/deluan/gosonic/utils"
"github.com/deluan/gosonic/scanner"
) )
func init() { func init() {
@ -22,4 +25,11 @@ func init() {
utils.DefineSingleton(new(engine.ListGenerator), engine.NewListGenerator) utils.DefineSingleton(new(engine.ListGenerator), engine.NewListGenerator)
utils.DefineSingleton(new(engine.Cover), engine.NewCover) utils.DefineSingleton(new(engine.Cover), engine.NewCover)
utils.DefineSingleton(new(engine.Playlists), engine.NewPlaylists) utils.DefineSingleton(new(engine.Playlists), engine.NewPlaylists)
utils.DefineSingleton(new(engine.Search), engine.NewSearch)
// Other dependencies
utils.DefineSingleton(new(scanner.Scanner), scanner.NewItunesScanner)
utils.DefineSingleton(new(gomate.Indexer), func() gomate.Indexer {
return gomate.NewIndexer(gomate.NewLedisEmbeddedDB(persistence.Db()))
})
} }

29
engine/search.go Normal file
View File

@ -0,0 +1,29 @@
package engine
import (
"strings"
"github.com/deluan/gomate"
"github.com/deluan/gosonic/domain"
)
type Search interface {
IndexArtist(ar *domain.Artist) error
//IndexAlbum(al domain.Album) error
//IndexMediaFile(mf domain.MediaFile) error
}
type search struct {
artistRepo domain.ArtistRepository
albumRepo domain.AlbumRepository
mfileRepo domain.MediaFileRepository
indexer gomate.Indexer
}
func NewSearch(ar domain.ArtistRepository, alr domain.AlbumRepository, mr domain.MediaFileRepository, idx gomate.Indexer) Search {
return search{ar, alr, mr, idx}
}
func (s search) IndexArtist(ar *domain.Artist) error {
return s.indexer.Index(ar.Id, strings.ToLower(ar.Name))
}

View File

@ -1,10 +1,11 @@
package persistence package persistence
import ( import (
"sync"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/siddontang/ledisdb/config" "github.com/siddontang/ledisdb/config"
"github.com/siddontang/ledisdb/ledis" "github.com/siddontang/ledisdb/ledis"
"sync"
) )
var ( var (
@ -13,7 +14,7 @@ var (
once sync.Once once sync.Once
) )
func db() *ledis.DB { func Db() *ledis.DB {
once.Do(func() { once.Do(func() {
config := config.NewConfigDefault() config := config.NewConfigDefault()
config.DataDir = beego.AppConfig.String("dbPath") config.DataDir = beego.AppConfig.String("dbPath")
@ -29,6 +30,6 @@ func db() *ledis.DB {
} }
func dropDb() { func dropDb() {
db() Db()
_ledisInstance.FlushAll() _ledisInstance.FlushAll()
} }

View File

@ -41,13 +41,13 @@ func (r *ledisRepository) NewId(fields ...string) string {
} }
func (r *ledisRepository) CountAll() (int64, error) { func (r *ledisRepository) CountAll() (int64, error) {
size, err := db().ZCard([]byte(r.table + "s:all")) size, err := Db().ZCard([]byte(r.table + "s:all"))
return size, err return size, err
} }
func (r *ledisRepository) getAllIds() (map[string]bool, error) { func (r *ledisRepository) getAllIds() (map[string]bool, error) {
m := make(map[string]bool) m := make(map[string]bool)
pairs, err := db().ZRange([]byte(r.table+"s:all"), 0, -1) pairs, err := Db().ZRange([]byte(r.table+"s:all"), 0, -1)
if err != nil { if err != nil {
return m, err return m, err
} }
@ -66,7 +66,7 @@ func (r *ledisRepository) DeleteAll(ids map[string]bool) error {
// Delete from parent:parentId:table (ZSet) // Delete from parent:parentId:table (ZSet)
if r.parentTable != "" { if r.parentTable != "" {
parentKey := []byte(fmt.Sprintf("%s:%s:%s", r.table, id, r.parentIdField)) parentKey := []byte(fmt.Sprintf("%s:%s:%s", r.table, id, r.parentIdField))
pid, err := db().Get(parentKey) pid, err := Db().Get(parentKey)
var parentId string var parentId string
if err := json.Unmarshal(pid, &parentId); err != nil { if err := json.Unmarshal(pid, &parentId); err != nil {
return err return err
@ -75,7 +75,7 @@ func (r *ledisRepository) DeleteAll(ids map[string]bool) error {
return err return err
} }
parentKey = []byte(fmt.Sprintf("%s:%s:%ss", r.parentTable, parentId, r.table)) parentKey = []byte(fmt.Sprintf("%s:%s:%ss", r.parentTable, parentId, r.table))
if _, err := db().ZRem(parentKey, []byte(id)); err != nil { if _, err := Db().ZRem(parentKey, []byte(id)); err != nil {
return err return err
} }
} }
@ -90,19 +90,19 @@ func (r *ledisRepository) DeleteAll(ids map[string]bool) error {
} }
// Delete from table:all (ZSet) // Delete from table:all (ZSet)
_, err := db().ZRem([]byte(allKey), keys...) _, err := Db().ZRem([]byte(allKey), keys...)
return err return err
} }
func (r *ledisRepository) deleteRecord(id string) error { func (r *ledisRepository) deleteRecord(id string) error {
keys := r.getFieldKeys(id) keys := r.getFieldKeys(id)
_, err := db().Del(keys...) _, err := Db().Del(keys...)
return err return err
} }
func (r *ledisRepository) Exists(id string) (bool, error) { func (r *ledisRepository) Exists(id string) (bool, error) {
res, _ := db().ZScore([]byte(r.table+"s:all"), []byte(id)) res, _ := Db().ZScore([]byte(r.table+"s:all"), []byte(id))
return res != ledis.InvalidScore, nil return res != ledis.InvalidScore, nil
} }
@ -117,19 +117,19 @@ func (r *ledisRepository) saveOrUpdate(id string, entity interface{}) error {
for f, v := range h { for f, v := range h {
key := recordPrefix + f key := recordPrefix + f
value, _ := json.Marshal(v) value, _ := json.Marshal(v)
if err := db().Set([]byte(key), value); err != nil { if err := Db().Set([]byte(key), value); err != nil {
return err return err
} }
} }
sid := ledis.ScorePair{0, []byte(id)} sid := ledis.ScorePair{0, []byte(id)}
if _, err = db().ZAdd([]byte(allKey), sid); err != nil { if _, err = Db().ZAdd([]byte(allKey), sid); err != nil {
return err return err
} }
if parentCollectionKey := r.getParentRelationKey(entity); parentCollectionKey != "" { if parentCollectionKey := r.getParentRelationKey(entity); parentCollectionKey != "" {
_, err = db().ZAdd([]byte(parentCollectionKey), sid) _, err = Db().ZAdd([]byte(parentCollectionKey), sid)
} }
return nil return nil
} }
@ -184,7 +184,7 @@ func (r *ledisRepository) readEntity(id string) (interface{}, error) {
fieldKeys := r.getFieldKeys(id) fieldKeys := r.getFieldKeys(id)
res, err := db().MGet(fieldKeys...) res, err := Db().MGet(fieldKeys...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -229,7 +229,7 @@ func (r *ledisRepository) loadFromSet(setName string, entities interface{}, qo .
if o.SortBy != "" { if o.SortBy != "" {
sortKey = []byte(fmt.Sprintf("%s:*:%s", r.table, o.SortBy)) sortKey = []byte(fmt.Sprintf("%s:*:%s", r.table, o.SortBy))
} }
response, err := db().XZSort([]byte(setName), o.Offset, o.Size, o.Alpha, o.Desc, sortKey, r.getFieldKeys("*")) response, err := Db().XZSort([]byte(setName), o.Offset, o.Size, o.Alpha, o.Desc, sortKey, r.getFieldKeys("*"))
if err != nil { if err != nil {
return err return err
} }

View File

@ -10,7 +10,6 @@ import (
"github.com/deluan/gosonic/consts" "github.com/deluan/gosonic/consts"
"github.com/deluan/gosonic/domain" "github.com/deluan/gosonic/domain"
"github.com/deluan/gosonic/engine" "github.com/deluan/gosonic/engine"
"github.com/deluan/gosonic/persistence"
"github.com/deluan/gosonic/utils" "github.com/deluan/gosonic/utils"
) )
@ -26,16 +25,16 @@ type tempIndex map[string]domain.ArtistInfo
func StartImport() { func StartImport() {
go func() { go func() {
i := &Importer{ // TODO Move all to DI
scanner: &ItunesScanner{}, i := &Importer{mediaFolder: beego.AppConfig.String("musicFolder")}
mediaFolder: beego.AppConfig.String("musicFolder"), utils.ResolveDependency(&i.mfRepo)
mfRepo: persistence.NewMediaFileRepository(), utils.ResolveDependency(&i.albumRepo)
albumRepo: persistence.NewAlbumRepository(), utils.ResolveDependency(&i.artistRepo)
artistRepo: persistence.NewArtistRepository(), utils.ResolveDependency(&i.idxRepo)
idxRepo: persistence.NewArtistIndexRepository(), utils.ResolveDependency(&i.plsRepo)
plsRepo: persistence.NewPlaylistRepository(), utils.ResolveDependency(&i.propertyRepo)
propertyRepo: persistence.NewPropertyRepository(), utils.ResolveDependency(&i.search)
} utils.ResolveDependency(&i.scanner)
i.Run() i.Run()
}() }()
} }
@ -50,6 +49,7 @@ type Importer struct {
idxRepo domain.ArtistIndexRepository idxRepo domain.ArtistIndexRepository
plsRepo domain.PlaylistRepository plsRepo domain.PlaylistRepository
propertyRepo engine.PropertyRepository propertyRepo engine.PropertyRepository
search engine.Search
lastScan time.Time lastScan time.Time
} }
@ -124,6 +124,9 @@ func (i *Importer) importLibrary() (err error) {
if err := i.artistRepo.Put(ar); err != nil { if err := i.artistRepo.Put(ar); err != nil {
beego.Error(err) beego.Error(err)
} }
if err := i.search.IndexArtist(ar); err != nil {
beego.Error("Error indexing artist:", err)
}
i.collectIndex(indexGroups, ar, artistIndex) i.collectIndex(indexGroups, ar, artistIndex)
} }

View File

@ -31,6 +31,10 @@ type ItunesScanner struct {
lastModifiedSince time.Time lastModifiedSince time.Time
} }
func NewItunesScanner() *ItunesScanner {
return &ItunesScanner{}
}
type plsRelation struct { type plsRelation struct {
pID string pID string
parentPID string parentPID string

View File

@ -25,6 +25,10 @@ func DefineSingleton(ptr interface{}, constructor interface{}) interface{} {
return ptr return ptr
} }
func ResolveDependency(ptr interface{}) {
inject.ExtractAssignable(Graph, ptr)
}
func init() { func init() {
definitions = make(map[reflect.Type]interface{}) definitions = make(map[reflect.Type]interface{})
Graph = inject.NewGraph() Graph = inject.NewGraph()