package scrobbler import ( "database/sql" "log" "time" "golang.fcuny.net/mpd-stats/internal/mpd" ) type Scrobbler struct { player *mpd.Player db *sql.DB } func NewScrobbler(net string, addr string, dbpath string) (*Scrobbler, error) { p, err := mpd.NewPlayer(net, addr) if err != nil { return nil, err } db, err := opendatabase(dbpath) if err != nil { return nil, err } s := Scrobbler{ player: p, db: db, } return &s, nil } func (s *Scrobbler) Close() error { return s.player.Close() } func (s *Scrobbler) Run() error { var ( currentRecord *Record previousRecord *Record ) for { e := <-s.player.Watcher.Event if e == mpd.SubSystemPlayer { status, err := s.player.Client.Status() if err != nil { log.Printf("could not read the status: %v", err) } if status["state"] == "stop" { if currentRecord != nil { if err := s.update(currentRecord); err != nil { log.Printf("failed to update record %s: %s", currentRecord.Id, err) } currentRecord = nil } continue } attrs, err := s.player.Client.CurrentSong() if err != nil { log.Printf("could not get current song: %v", err) } if currentRecord == nil { currentRecord, err = NewRecord(attrs) if err != nil { log.Printf("could not create a log: %v", err) } previousRecord = currentRecord if err := s.save(currentRecord); err != nil { log.Printf("failed to insert record %s: %s", currentRecord.Id, err) } continue } if !currentRecord.EqualAttrs(attrs) { currentRecord, err = NewRecord(attrs) if err != nil { log.Printf("could not create a log: %v", err) } } if currentRecord.Id != previousRecord.Id { if err := s.update(previousRecord); err != nil { log.Printf("failed to update record %s: %s", previousRecord.Id, err) } previousRecord = currentRecord s.save(currentRecord) } } } } func (s *Scrobbler) save(record *Record) error { _, err := s.db.Exec("insert into records(id, title, artist, album, duration, playtime, time) values(?, ?, ?, ?, ?, 0, ?)", record.Id, record.Title, record.Artist, record.Album, int(record.Duration.Seconds()), record.Timestamp, ) return err } func (s *Scrobbler) update(record *Record) error { tnow := time.Now() playtime := tnow.Sub(record.Timestamp).Seconds() _, err := s.db.Exec("update records set playtime = ? where id = ?", int(playtime), record.Id, ) return err }