package radio import ( "bytes" "strconv" "sync" "time" "github.com/pkg/errors" ) const MostListenedDateFormat string = "02 January 2006 at 15:04:05 MST" // MostListenedSong holds a metadata for a most listened song. type MostListenedSong struct { sync.RWMutex Date time.Time `json:"date"` Listeners int `json:"listeners"` Song string `json:"song"` changed bool } func (mls *MostListenedSong) Update(song Song) { mls.Lock() defer mls.Unlock() if song.Artist == "" { return } if song.MaxListeners > mls.Listeners { mls.Listeners = song.MaxListeners mls.Date = song.StartAt mls.Song = song.Artist + " - " + song.Title mls.changed = true } } func (mls *MostListenedSong) Get() *MostListenedSong { mls.RLock() defer mls.RUnlock() if mls.Date.Year() == 1 { return nil } return &MostListenedSong{ Date: mls.Date, Listeners: mls.Listeners, Song: mls.Song} } // Load parses given data and fill a MostListenedSong. func (mls *MostListenedSong) Load(data []byte) (err error) { mls.Lock() defer mls.Unlock() lines := bytes.Split(data, []byte{'\n'}) if len(lines) != 3 { return errors.New("lines count mismatch, should be 3") } var date time.Time if date, err = time.Parse(time.RFC3339, string(lines[0])); err != nil { return errors.Wrap(err, "wrong date/time format") } var listeners int if listeners, err = strconv.Atoi(string(lines[1])); err != nil { return errors.Wrap(err, "a listeners number failed to parse") } if len(lines[2]) == 0 { return errors.New("a song is empty") } mls.Date = date mls.Listeners = listeners mls.Song = string(lines[2]) return nil } // Store returns a byte slice of a marshalled to text MostListenedSong. func (mls *MostListenedSong) Store() []byte { if !mls.changed { return nil } buf := make([]byte, 0, 30+len(mls.Song)) b := bytes.NewBuffer(buf) b.WriteString(mls.Date.Format(time.RFC3339)) b.WriteByte('\n') b.WriteString(strconv.Itoa(mls.Listeners)) b.WriteByte('\n') b.WriteString(mls.Song) return b.Bytes() }