Implemented first repository using tiedot

This commit is contained in:
Deluan 2016-02-26 01:32:31 -05:00
parent e760952263
commit 85ddd19c3d
18 changed files with 279 additions and 53 deletions

6
.gitignore vendored
View File

@ -1,5 +1,7 @@
lastupdate.tmp
gosonic
iTunes Music Library.xml
iTunes*.xml
gosonic.index
static/Jamstash
static/Jamstash
devDb
tmp

View File

@ -5,6 +5,7 @@ path = github.com/deluan/gosonic
github.com/astaxie/beego = tag:v1.6.0
github.com/blevesearch/bleve = commit:a5bb81e
github.com/dhowden/itl = commit:35d15a3
github.com/HouzuoGuo/tiedot = tag:3.2
[res]
include = conf

View File

@ -9,7 +9,7 @@ import (
type GetMusicFoldersController struct{ beego.Controller }
func (c *GetMusicFoldersController) Get() {
repository := new(repositories.MediaFolderRepository)
repository := repositories.NewMediaFolderRepository()
mediaFolderList, _ := repository.GetAll()
folders := make([]responses.MusicFolder, len(mediaFolderList))
for i, f := range mediaFolderList {

View File

@ -5,9 +5,10 @@ autoRender = false
copyRequestBody = true
apiVersion = 1.0.0
musicFolder=.
musicFolder=./iTunes.xml
user=deluan
password=wordpass
dbPath = ./devDb
[dev]
disableValidation = true
@ -16,6 +17,8 @@ indexPath = ./gosonic.index
[test]
disableValidation = false
httpPort = 8081
enableAdmin = false
user=deluan
password=wordpass
dbPath = ./tmp/testDb

View File

@ -1 +1,15 @@
package controllers
import (
"github.com/astaxie/beego"
"github.com/deluan/gosonic/scanner"
)
type SyncController struct{ beego.Controller }
func (c *SyncController) Get() {
scanner.StartImport()
c.Ctx.WriteString("Import started. Check logs")
}

12
models/album.go Normal file
View File

@ -0,0 +1,12 @@
package models
type Album struct {
Id string
Name string
Artist *Artist
CoverArtPath string
Year int
Compilation bool
Rating int
}

6
models/artist.go Normal file
View File

@ -0,0 +1,6 @@
package models
type Artist struct {
Id string
Name string
}

View File

@ -1,8 +1,6 @@
package models
import (
"time"
)
import "time"
type MediaFile struct {
Id string

View File

@ -0,0 +1,78 @@
package repositories
import (
"encoding/json"
"github.com/HouzuoGuo/tiedot/db"
"github.com/astaxie/beego"
"fmt"
)
type BaseRepository struct {
col *db.Col
}
func (r *BaseRepository) marshal(rec interface{}) (map[string]interface{}, error) {
// Convert to JSON...
b, err := json.Marshal(rec);
if err != nil {
return nil, err
}
// ... then convert to map
var m map[string]interface{}
err = json.Unmarshal(b, &m)
return m, err
}
func (r*BaseRepository) query(q string, a ...interface{}) (map[int]struct{}, error) {
q = fmt.Sprintf(q, a)
var query interface{}
json.Unmarshal([]byte(q), &query)
queryResult := make(map[int]struct{})
err := db.EvalQuery(query, r.col, &queryResult)
if err != nil {
beego.Warn("Error '%s' - query='%s'", q, err)
}
return queryResult, err
}
func (r*BaseRepository) queryFirstKey(q string, a ...interface{}) (int, error) {
result, err := r.query(q, a)
if err != nil {
return 0, err
}
for key, _ := range result {
return key, nil
}
return 0, nil
}
func (r *BaseRepository) saveOrUpdate(rec interface{}) error {
m, err := r.marshal(rec)
if err != nil {
return err
}
docId, err := r.queryFirstKey(`{"in": ["Id"], "eq": "%s"}`, m["Id"])
if docId == 0 {
_, err = r.col.Insert(m)
return err
}
err = r.col.Update(docId, m)
if err != nil {
beego.Warn("Error updating %s[%d]: %s", r.col, docId, err)
}
return err
}
func (r *BaseRepository) Dump() {
r.col.ForEachDoc(func(id int, docContent []byte) (willMoveOn bool) {
beego.Debug("Document", id, "=", string(docContent))
return true
})
}

View File

@ -0,0 +1,37 @@
package repositories
import (
"github.com/HouzuoGuo/tiedot/db"
"github.com/astaxie/beego"
"sync"
)
var (
_dbInstance *db.DB
once sync.Once
)
func createCollection(name string) *db.Col {
col := dbInstance().Use(name)
if col != nil {
return col
}
if err := dbInstance().Create(name); err != nil {
beego.Error(err)
}
if err := col.Index([]string{"Id"}); err != nil {
beego.Error(name, err)
}
return col
}
func dbInstance() *db.DB {
once.Do(func() {
instance, err := db.OpenDB(beego.AppConfig.String("dbPath"))
if err != nil {
panic(err)
}
_dbInstance = instance
})
return _dbInstance
}

View File

@ -1,10 +1,24 @@
package repositories
//import "github.com/deluan/gosonic/models"
//
//func AddMediaFile(m models.MediaFile) string {
// m.ID = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10)
// UserList[u.Id] = &u
// return u.Id
//}
//
import (
"github.com/deluan/gosonic/models"
"fmt"
"crypto/md5"
)
type MediaFile struct {
BaseRepository
}
func NewMediaFileRepository() *MediaFile {
r := &MediaFile{}
r.col = createCollection("MediaFiles")
return r
}
func (r *MediaFile) Add(m *models.MediaFile) error {
if m.Id == "" {
m.Id = fmt.Sprintf("%x", md5.Sum([]byte(m.Path)))
}
return r.saveOrUpdate(m)
}

View File

@ -5,9 +5,14 @@ import (
"github.com/astaxie/beego"
)
type MediaFolderRepository struct {}
type MediaFolder struct {}
func (*MediaFolderRepository) GetAll() ([]*models.MediaFolder, error) {
func NewMediaFolderRepository() *MediaFolder {
return &MediaFolder{}
}
func (*MediaFolder) GetAll() ([]*models.MediaFolder, error) {
mediaFolder := models.MediaFolder{Id: "0", Name: "iTunes Library", Path: beego.AppConfig.String("musicFolder")}
result := make([]*models.MediaFolder, 1)
result[0] = &mediaFolder

View File

@ -17,6 +17,7 @@ func init() {
beego.AddNamespace(ns)
beego.Router("/", &controllers.MainController{})
beego.Router("/sync", &controllers.SyncController{})
var ValidateRequest = func(ctx *context.Context) {
api.Validate(&beego.Controller{Ctx: ctx})

34
scanner/itunes_scanner.go Normal file
View File

@ -0,0 +1,34 @@
package scanner
import (
"github.com/dhowden/itl"
"net/url"
"os"
"strings"
)
type ItunesScanner struct {}
func (s *ItunesScanner) LoadFolder(path string) []Track {
xml, _ := os.Open(path)
l, _ := itl.ReadFromXML(xml)
mediaFiles := make([]Track, len(l.Tracks))
i := 0
for id, t := range l.Tracks {
if t.Location != "" && strings.Contains(t.Kind, "audio") {
mediaFiles[i].Id = id
mediaFiles[i].Album = t.Album
mediaFiles[i].Title = t.Name
mediaFiles[i].Artist = t.Artist
path, _ = url.QueryUnescape(t.Location)
mediaFiles[i].Path = strings.TrimPrefix(path, "file://")
mediaFiles[i].CreatedAt = t.DateAdded
mediaFiles[i].UpdatedAt = t.DateModified
i++
}
}
return mediaFiles[0:i]
}
var _ Scanner = (*ItunesScanner)(nil)

42
scanner/scanner.go Normal file
View File

@ -0,0 +1,42 @@
package scanner
import (
"github.com/astaxie/beego"
"github.com/deluan/gosonic/repositories"
"github.com/deluan/gosonic/models"
)
type Scanner interface {
LoadFolder(path string) []Track
}
func StartImport() {
go doImport(beego.AppConfig.String("musicFolder"), &ItunesScanner{})
}
func doImport(mediaFolder string, scanner Scanner) {
beego.Info("Starting iTunes import from:", mediaFolder)
files := scanner.LoadFolder(mediaFolder)
updateDatastore(files)
beego.Info("Finished importing", len(files), "files")
}
func updateDatastore(files []Track) {
mfRepo := repositories.NewMediaFileRepository()
for _, t := range files {
m := &models.MediaFile{
Id: t.Id,
Album: t.Album,
Artist: t.Artist,
Title: t.Title,
Path: t.Path,
CreatedAt: t.CreatedAt,
UpdatedAt: t.UpdatedAt,
}
err := mfRepo.Add(m)
if err != nil {
beego.Error(err)
}
}
mfRepo.Dump()
}

15
scanner/track.go Normal file
View File

@ -0,0 +1,15 @@
package scanner
import (
"time"
)
type Track struct {
Id string
Path string
Album string
Artist string
Title string
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@ -1,29 +0,0 @@
package itunes
import (
"github.com/deluan/gosonic/models"
"github.com/dhowden/itl"
"net/url"
"os"
"strings"
)
func LoadFolder(path string) []models.MediaFile {
xml, _ := os.Open(path)
l, _ := itl.ReadFromXML(xml)
mediaFiles := make([]models.MediaFile, len(l.Tracks))
i := 0
for id, track := range l.Tracks {
mediaFiles[i].Id = id
mediaFiles[i].Album = track.Album
mediaFiles[i].Title = track.Name
mediaFiles[i].Artist = track.Artist
path, _ = url.QueryUnescape(track.Location)
mediaFiles[i].Path = strings.TrimPrefix(path, "file://")
mediaFiles[i].CreatedAt = track.DateAdded
mediaFiles[i].UpdatedAt = track.DateModified
i++
}
return mediaFiles
}

View File

@ -1,7 +0,0 @@
package scanners
import "github.com/deluan/gosonic/models"
type Scanner interface {
LoadFolder(path string) []models.MediaFile
}