New Folder Scanner - WIP
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/cloudsonic/sonic-server/log"
|
||||
"github.com/cloudsonic/sonic-server/model"
|
||||
)
|
||||
|
||||
@@ -85,7 +88,62 @@ func (r *albumRepository) toAlbums(all []Album) model.Albums {
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO Remove []string from return
|
||||
func (r *albumRepository) Refresh(ids ...string) error {
|
||||
type refreshAlbum struct {
|
||||
Album
|
||||
CurrentId string
|
||||
HasCoverArt bool
|
||||
}
|
||||
var albums []refreshAlbum
|
||||
o := Db()
|
||||
sql := fmt.Sprintf(`
|
||||
select album_id as id, album as name, f.artist, f.album_artist, f.artist_id, f.compilation, f.genre,
|
||||
max(f.year) as year, sum(f.play_count) as play_count, max(f.play_date) as play_date, sum(f.duration) as duration,
|
||||
max(f.updated_at) as updated_at, min(f.created_at) as created_at, count(*) as song_count,
|
||||
a.id as current_id, f.id as cover_art_id, f.path as cover_art_path, f.has_cover_art
|
||||
from media_file f left outer join album a on f.album_id = a.id
|
||||
where f.album_id in ('%s')
|
||||
group by album_id order by f.id`, strings.Join(ids, "','"))
|
||||
_, err := o.Raw(sql).QueryRows(&albums)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toInsert []Album
|
||||
var toUpdate []Album
|
||||
for _, al := range albums {
|
||||
if !al.HasCoverArt {
|
||||
al.CoverArtId = ""
|
||||
}
|
||||
if al.Compilation {
|
||||
al.AlbumArtist = "Various Artists"
|
||||
}
|
||||
if al.CurrentId != "" {
|
||||
toUpdate = append(toUpdate, al.Album)
|
||||
} else {
|
||||
toInsert = append(toInsert, al.Album)
|
||||
}
|
||||
}
|
||||
if len(toInsert) > 0 {
|
||||
n, err := o.InsertMulti(100, toInsert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debug("Inserted new albums", "num", n)
|
||||
}
|
||||
if len(toUpdate) > 0 {
|
||||
for _, al := range toUpdate {
|
||||
_, err := o.Update(&al, "name", "artist_id", "cover_art_path", "cover_art_id", "artist", "album_artist", "year",
|
||||
"compilation", "play_count", "song_count", "duration", "updated_at")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Debug("Updated albums", "num", len(toUpdate))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *albumRepository) PurgeInactive(activeList model.Albums) error {
|
||||
return withTx(func(o orm.Ormer) error {
|
||||
_, err := r.purgeInactive(o, activeList, func(item interface{}) string {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/cloudsonic/sonic-server/log"
|
||||
"github.com/cloudsonic/sonic-server/model"
|
||||
)
|
||||
|
||||
@@ -42,6 +46,64 @@ func (r *artistRepository) Get(id string) (*model.Artist, error) {
|
||||
return &a, nil
|
||||
}
|
||||
|
||||
func (r *artistRepository) Refresh(ids ...string) error {
|
||||
type refreshArtist struct {
|
||||
Artist
|
||||
CurrentId string
|
||||
AlbumArtist string
|
||||
Compilation bool
|
||||
}
|
||||
var artists []refreshArtist
|
||||
o := Db()
|
||||
sql := fmt.Sprintf(`
|
||||
select f.artist_id as id,
|
||||
f.artist as name,
|
||||
f.album_artist,
|
||||
f.compilation,
|
||||
count(*) as album_count,
|
||||
a.id as current_id
|
||||
from album f
|
||||
left outer join artist a on f.artist_id = a.id
|
||||
where f.artist_id in ('%s') group by f.artist_id order by f.id`, strings.Join(ids, "','"))
|
||||
_, err := o.Raw(sql).QueryRows(&artists)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toInsert []Artist
|
||||
var toUpdate []Artist
|
||||
for _, al := range artists {
|
||||
if al.Compilation {
|
||||
al.AlbumArtist = "Various Artists"
|
||||
}
|
||||
if al.AlbumArtist != "" {
|
||||
al.Name = al.AlbumArtist
|
||||
}
|
||||
if al.CurrentId != "" {
|
||||
toUpdate = append(toUpdate, al.Artist)
|
||||
} else {
|
||||
toInsert = append(toInsert, al.Artist)
|
||||
}
|
||||
}
|
||||
if len(toInsert) > 0 {
|
||||
n, err := o.InsertMulti(100, toInsert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debug("Inserted new artists", "num", n)
|
||||
}
|
||||
if len(toUpdate) > 0 {
|
||||
for _, al := range toUpdate {
|
||||
_, err := o.Update(&al, "name", "album_count")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Debug("Updated artists", "num", len(toUpdate))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *artistRepository) PurgeInactive(activeList model.Artists) error {
|
||||
return withTx(func(o orm.Ormer) error {
|
||||
_, err := r.purgeInactive(o, activeList, func(item interface{}) string {
|
||||
|
||||
@@ -2,9 +2,12 @@ package persistence
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/cloudsonic/sonic-server/conf"
|
||||
"github.com/cloudsonic/sonic-server/model"
|
||||
"github.com/cloudsonic/sonic-server/utils"
|
||||
)
|
||||
|
||||
type ArtistInfo struct {
|
||||
@@ -15,6 +18,8 @@ type ArtistInfo struct {
|
||||
AlbumCount int
|
||||
}
|
||||
|
||||
type tempIndex map[string]model.ArtistInfo
|
||||
|
||||
type artistIndexRepository struct {
|
||||
sqlRepository
|
||||
}
|
||||
@@ -25,15 +30,6 @@ func NewArtistIndexRepository() model.ArtistIndexRepository {
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) CountAll() (int64, error) {
|
||||
count := struct{ Count int64 }{}
|
||||
err := Db().Raw("select count(distinct(idx)) as count from artist_info").QueryRow(&count)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count.Count, nil
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) Put(idx *model.ArtistIndex) error {
|
||||
return withTx(func(o orm.Ormer) error {
|
||||
_, err := r.newQuery(o).Filter("idx", idx.ID).Delete()
|
||||
@@ -56,23 +52,64 @@ func (r *artistIndexRepository) Put(idx *model.ArtistIndex) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) Get(id string) (*model.ArtistIndex, error) {
|
||||
var ais []ArtistInfo
|
||||
_, err := r.newQuery(Db()).Filter("idx", id).All(&ais)
|
||||
func (r *artistIndexRepository) Refresh() error {
|
||||
o := Db()
|
||||
|
||||
indexGroups := utils.ParseIndexGroups(conf.Sonic.IndexGroups)
|
||||
artistIndex := make(map[string]tempIndex)
|
||||
|
||||
var artists []Artist
|
||||
_, err := o.QueryTable(&Artist{}).All(&artists)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
idx := &model.ArtistIndex{ID: id}
|
||||
idx.Artists = make([]model.ArtistInfo, len(ais))
|
||||
for i, a := range ais {
|
||||
idx.Artists[i] = model.ArtistInfo{
|
||||
ArtistID: a.ArtistID,
|
||||
Artist: a.Artist,
|
||||
AlbumCount: a.AlbumCount,
|
||||
for _, ar := range artists {
|
||||
r.collectIndex(indexGroups, &ar, artistIndex)
|
||||
}
|
||||
|
||||
return r.saveIndex(artistIndex)
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) collectIndex(ig utils.IndexGroups, a *Artist, artistIndex map[string]tempIndex) {
|
||||
name := a.Name
|
||||
indexName := strings.ToLower(utils.NoArticle(name))
|
||||
if indexName == "" {
|
||||
return
|
||||
}
|
||||
group := r.findGroup(ig, indexName)
|
||||
artists := artistIndex[group]
|
||||
if artists == nil {
|
||||
artists = make(tempIndex)
|
||||
artistIndex[group] = artists
|
||||
}
|
||||
artists[indexName] = model.ArtistInfo{ArtistID: a.ID, Artist: a.Name, AlbumCount: a.AlbumCount}
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) findGroup(ig utils.IndexGroups, name string) string {
|
||||
for k, v := range ig {
|
||||
key := strings.ToLower(k)
|
||||
if strings.HasPrefix(name, key) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return idx, err
|
||||
return "#"
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) saveIndex(artistIndex map[string]tempIndex) error {
|
||||
r.DeleteAll()
|
||||
for k, temp := range artistIndex {
|
||||
idx := &model.ArtistIndex{ID: k}
|
||||
for _, v := range temp {
|
||||
idx.Artists = append(idx.Artists, v)
|
||||
}
|
||||
err := r.Put(idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *artistIndexRepository) GetAll() (model.ArtistIndexes, error) {
|
||||
|
||||
@@ -35,11 +35,6 @@ var _ = Describe("Artist Index", func() {
|
||||
|
||||
Expect(repo.Put(&idx1)).To(BeNil())
|
||||
Expect(repo.Put(&idx2)).To(BeNil())
|
||||
Expect(repo.Get("D")).To(Equal(&idx1))
|
||||
Expect(repo.Get("S")).To(Equal(&idx2))
|
||||
Expect(repo.GetAll()).To(Equal(model.ArtistIndexes{idx1, idx2}))
|
||||
Expect(repo.CountAll()).To(Equal(int64(2)))
|
||||
Expect(repo.DeleteAll()).To(BeNil())
|
||||
Expect(repo.CountAll()).To(Equal(int64(0)))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -102,6 +102,26 @@ func (r *mediaFileRepository) FindByPath(path string) (model.MediaFiles, error)
|
||||
return r.toMediaFiles(filtered), nil
|
||||
}
|
||||
|
||||
func (r *mediaFileRepository) DeleteByPath(path string) error {
|
||||
o := Db()
|
||||
var mfs []MediaFile
|
||||
_, err := r.newQuery(o).Filter("path__istartswith", path).OrderBy("disc_number", "track_number").All(&mfs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var filtered []string
|
||||
path = strings.ToLower(path) + string(os.PathSeparator)
|
||||
for _, mf := range mfs {
|
||||
filename := strings.TrimPrefix(strings.ToLower(mf.Path), path)
|
||||
if len(strings.Split(filename, string(os.PathSeparator))) > 1 {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, mf.ID)
|
||||
}
|
||||
_, err = r.newQuery(o).Filter("id__in", filtered).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *mediaFileRepository) GetStarred(options ...model.QueryOptions) (model.MediaFiles, error) {
|
||||
var starred []MediaFile
|
||||
_, err := r.newQuery(Db(), options...).Filter("starred", true).All(&starred)
|
||||
|
||||
Reference in New Issue
Block a user