quintodrome/scanner_legacy/importer.go

250 lines
6.1 KiB
Go
Raw Normal View History

2020-01-14 17:51:35 -09:00
package scanner_legacy
import (
2016-03-02 09:18:39 -09:00
"fmt"
"os"
"strconv"
"time"
2017-04-01 05:47:14 -08:00
"github.com/cloudsonic/sonic-server/conf"
2020-01-08 16:45:07 -09:00
"github.com/cloudsonic/sonic-server/log"
2020-01-14 18:22:34 -09:00
"github.com/cloudsonic/sonic-server/model"
)
type Scanner interface {
ScanLibrary(lastModifiedSince time.Time, path string) (int, error)
2020-01-14 18:22:34 -09:00
MediaFiles() map[string]*model.MediaFile
Albums() map[string]*model.Album
Artists() map[string]*model.Artist
Playlists() map[string]*model.Playlist
}
type Importer struct {
scanner Scanner
mediaFolder string
2020-01-14 18:22:34 -09:00
mfRepo model.MediaFileRepository
albumRepo model.AlbumRepository
artistRepo model.ArtistRepository
plsRepo model.PlaylistRepository
propertyRepo model.PropertyRepository
lastScan time.Time
lastCheck time.Time
}
func NewImporter(mediaFolder string, scanner Scanner, mfRepo model.MediaFileRepository, albumRepo model.AlbumRepository, artistRepo model.ArtistRepository, plsRepo model.PlaylistRepository, propertyRepo model.PropertyRepository) *Importer {
return &Importer{
scanner: scanner,
mediaFolder: mediaFolder,
mfRepo: mfRepo,
albumRepo: albumRepo,
artistRepo: artistRepo,
plsRepo: plsRepo,
propertyRepo: propertyRepo,
}
}
func (i *Importer) CheckForUpdates(force bool) {
if force {
i.lastCheck = time.Time{}
}
i.startImport()
}
func (i *Importer) startImport() {
go func() {
info, err := os.Stat(i.mediaFolder)
if err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
return
}
if i.lastCheck.After(info.ModTime()) {
return
}
i.lastCheck = time.Now()
i.scan()
}()
}
func (i *Importer) scan() {
i.lastScan = i.lastModifiedSince()
2016-03-10 05:37:35 -09:00
2016-03-15 13:37:17 -08:00
if i.lastScan.IsZero() {
2020-01-08 16:45:07 -09:00
log.Info("Starting first iTunes Library scan. This can take a while...")
2016-03-15 13:37:17 -08:00
}
2016-03-10 05:37:35 -09:00
total, err := i.scanner.ScanLibrary(i.lastScan, i.mediaFolder)
if err != nil {
2020-01-08 16:45:07 -09:00
log.Error("Error importing iTunes Library", err)
2016-03-04 12:42:09 -09:00
return
}
2016-03-10 05:37:35 -09:00
2020-01-11 09:58:25 -09:00
log.Debug("Totals informed by the scanner", "tracks", total,
2020-01-08 16:45:07 -09:00
"songs", len(i.scanner.MediaFiles()),
"albums", len(i.scanner.Albums()),
"artists", len(i.scanner.Artists()),
"playlists", len(i.scanner.Playlists()))
2016-03-10 05:37:35 -09:00
2016-03-04 12:42:09 -09:00
if err := i.importLibrary(); err != nil {
2020-01-08 16:45:07 -09:00
log.Error("Error persisting data", err)
2016-03-04 12:42:09 -09:00
}
2016-03-15 13:37:17 -08:00
if i.lastScan.IsZero() {
2020-01-08 16:45:07 -09:00
log.Info("Finished first iTunes Library import")
2016-03-15 13:37:17 -08:00
} else {
2020-01-08 16:45:07 -09:00
log.Debug("Finished updating tracks from iTunes Library")
2016-03-15 13:37:17 -08:00
}
}
func (i *Importer) lastModifiedSince() time.Time {
2020-01-14 18:22:34 -09:00
ms, err := i.propertyRepo.Get(model.PropLastScan)
if err != nil {
2020-01-08 16:45:07 -09:00
log.Warn("Couldn't read LastScan", err)
return time.Time{}
}
2016-03-11 08:10:37 -09:00
if ms == "" {
2020-01-08 16:45:07 -09:00
log.Debug("First scan")
2016-03-11 08:10:37 -09:00
return time.Time{}
}
s, _ := strconv.ParseInt(ms, 10, 64)
return time.Unix(0, s*int64(time.Millisecond))
}
2016-03-04 12:42:09 -09:00
func (i *Importer) importLibrary() (err error) {
2016-03-15 13:06:23 -08:00
arc, _ := i.artistRepo.CountAll()
alc, _ := i.albumRepo.CountAll()
mfc, _ := i.mfRepo.CountAll()
plc, _ := i.plsRepo.CountAll()
2016-02-28 09:50:05 -09:00
2020-01-08 16:45:07 -09:00
log.Debug("Saving updated data")
mfs, mfu := i.importMediaFiles()
2020-01-11 09:58:25 -09:00
log.Debug("Imported media files", "total", len(mfs), "updated", mfu)
als, alu := i.importAlbums()
2020-01-11 09:58:25 -09:00
log.Debug("Imported albums", "total", len(als), "updated", alu)
ars := i.importArtists()
2020-01-11 09:58:25 -09:00
log.Debug("Imported artists", "total", len(ars))
pls := i.importPlaylists()
2020-01-11 09:58:25 -09:00
log.Debug("Imported playlists", "total", len(pls))
2020-01-08 16:45:07 -09:00
log.Debug("Purging old data")
if err := i.mfRepo.PurgeInactive(mfs); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
}
if err := i.albumRepo.PurgeInactive(als); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
}
if err := i.artistRepo.PurgeInactive(ars); err != nil {
log.Error("Deleting inactive artists", err)
}
if _, err := i.plsRepo.PurgeInactive(pls); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
}
arc2, _ := i.artistRepo.CountAll()
alc2, _ := i.albumRepo.CountAll()
mfc2, _ := i.mfRepo.CountAll()
plc2, _ := i.plsRepo.CountAll()
if arc != arc2 || alc != alc2 || mfc != mfc2 || plc != plc2 {
2020-01-08 16:45:07 -09:00
log.Info(fmt.Sprintf("Updated library totals: %d(%+d) artists, %d(%+d) albums, %d(%+d) songs, %d(%+d) playlists", arc2, arc2-arc, alc2, alc2-alc, mfc2, mfc2-mfc, plc2, plc2-plc))
}
if alu > 0 || mfu > 0 {
2020-01-08 16:45:07 -09:00
log.Info(fmt.Sprintf("Updated items: %d album(s), %d song(s)", alu, mfu))
}
if err == nil {
millis := time.Now().UnixNano() / int64(time.Millisecond)
2020-01-14 18:22:34 -09:00
i.propertyRepo.Put(model.PropLastScan, fmt.Sprint(millis))
2020-01-08 16:45:07 -09:00
log.Debug("LastScan", "timestamp", millis)
}
return err
}
2020-01-14 18:22:34 -09:00
func (i *Importer) importMediaFiles() (model.MediaFiles, int) {
mfs := make(model.MediaFiles, len(i.scanner.MediaFiles()))
updates := 0
j := 0
2016-03-04 12:42:09 -09:00
for _, mf := range i.scanner.MediaFiles() {
mfs[j] = *mf
j++
if mf.UpdatedAt.Before(i.lastScan) {
continue
}
if mf.Starred {
original, err := i.mfRepo.Get(mf.ID)
if err != nil || !original.Starred {
mf.StarredAt = mf.UpdatedAt
2016-03-22 17:32:22 -08:00
} else {
mf.StarredAt = original.StarredAt
}
}
2016-03-04 12:42:09 -09:00
if err := i.mfRepo.Put(mf); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
2016-03-04 12:42:09 -09:00
}
updates++
2016-03-11 08:10:37 -09:00
if !i.lastScan.IsZero() {
2020-01-08 16:45:07 -09:00
log.Debug(fmt.Sprintf(`-- Updated Track: "%s"`, mf.Title))
2016-03-11 08:10:37 -09:00
}
2016-03-04 12:42:09 -09:00
}
return mfs, updates
}
2016-03-04 12:42:09 -09:00
2020-01-14 18:22:34 -09:00
func (i *Importer) importAlbums() (model.Albums, int) {
als := make(model.Albums, len(i.scanner.Albums()))
updates := 0
j := 0
2016-03-04 12:42:09 -09:00
for _, al := range i.scanner.Albums() {
als[j] = *al
j++
if al.UpdatedAt.Before(i.lastScan) {
continue
}
if al.Starred {
original, err := i.albumRepo.Get(al.ID)
if err != nil || !original.Starred {
al.StarredAt = al.UpdatedAt
2016-03-22 17:32:22 -08:00
} else {
al.StarredAt = original.StarredAt
}
}
2016-03-04 12:42:09 -09:00
if err := i.albumRepo.Put(al); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
2016-03-04 12:42:09 -09:00
}
updates++
2016-03-11 08:10:37 -09:00
if !i.lastScan.IsZero() {
2020-01-08 16:45:07 -09:00
log.Debug(fmt.Sprintf(`-- Updated Album: "%s" from "%s"`, al.Name, al.Artist))
2016-03-11 08:10:37 -09:00
}
2016-03-04 12:42:09 -09:00
}
return als, updates
}
2016-03-04 12:42:09 -09:00
2020-01-14 18:22:34 -09:00
func (i *Importer) importArtists() model.Artists {
ars := make(model.Artists, len(i.scanner.Artists()))
j := 0
2016-03-04 12:42:09 -09:00
for _, ar := range i.scanner.Artists() {
ars[j] = *ar
j++
2016-03-04 12:42:09 -09:00
if err := i.artistRepo.Put(ar); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
2016-03-04 12:42:09 -09:00
}
}
return ars
}
2020-01-14 18:22:34 -09:00
func (i *Importer) importPlaylists() model.Playlists {
pls := make(model.Playlists, len(i.scanner.Playlists()))
j := 0
2016-03-09 09:51:17 -09:00
for _, pl := range i.scanner.Playlists() {
2016-03-21 08:26:55 -08:00
pl.Public = true
2017-04-01 05:47:14 -08:00
pl.Owner = conf.Sonic.User
2016-03-24 09:28:20 -08:00
pl.Comment = "Original: " + pl.FullPath
2016-03-09 09:51:17 -09:00
pls[j] = *pl
j++
if err := i.plsRepo.Put(pl); err != nil {
2020-01-08 16:45:07 -09:00
log.Error(err)
2016-03-09 09:51:17 -09:00
}
}
return pls
2016-02-26 23:35:01 -09:00
}