package radio import ( "encoding/json" "sync" "time" ) // Song stores artist and title of a song, a timestamp of when it started, its // duration, and a maximum number of listeners. type Song struct { Artist string Title string Duration time.Duration MaxListeners int StartAt time.Time } // DurationString returns song's duration as a string formatted as [H:]M:SS. func (s *Song) DurationString() string { if s.Duration.Hours() >= 1 { return time.UnixMilli(s.Duration.Milliseconds()).Format("3:4:05") } return time.UnixMilli(s.Duration.Milliseconds()).Format("4:05") } func (s *Song) MarshalJSON() ([]byte, error) { return json.Marshal(&struct { Artist string `json:"artist"` Title string `json:"title"` DurationMill int64 `json:"duration_msec"` MaxListeners int `json:"listeners"` StartAt string `json:"start_at"` }{ Artist: s.Artist, Title: s.Title, DurationMill: s.Duration.Milliseconds(), MaxListeners: s.MaxListeners, StartAt: s.StartAt.UTC().Format(time.RFC3339)}) } type SongList struct { sync.RWMutex current Song lastSongs []Song maxLen int } // NewSongList returns a new SongList with a maximal length set with maxLen. func NewSongList(maxLen int) *SongList { return &SongList{maxLen: maxLen, lastSongs: make([]Song, 0, maxLen)} } // Add a new song that is currently playing and update a list. func (sl *SongList) Add(newSong Song) { sl.Lock() defer sl.Unlock() if sl.current.StartAt.Year() == 1 { sl.current = newSong return } if len(sl.lastSongs) == sl.maxLen { sl.lastSongs = append(sl.lastSongs[1:], sl.current) } else { sl.lastSongs = append(sl.lastSongs, sl.current) } sl.current = newSong } // Current returns a currently playing song. func (sl *SongList) Current() *Song { sl.RLock() defer sl.RUnlock() if sl.current.StartAt.Year() == 1 { return nil } return &Song{ Artist: sl.current.Artist, Title: sl.current.Title, Duration: sl.current.Duration, MaxListeners: sl.current.MaxListeners, StartAt: sl.current.StartAt} } // UpdateCurrentMaxListeners checks and updates a maximal number of listeners // for a current song. func (sl *SongList) UpdateCurrentMaxListeners(listeners int) { sl.Lock() defer sl.Unlock() if listeners > sl.current.MaxListeners { sl.current.MaxListeners = listeners } } // List returns a list of lastly played songs. func (sl *SongList) List() []Song { sl.RLock() defer sl.RUnlock() return sl.lastSongs } // MaxLen returns a maximal length of a list func (sl *SongList) MaxLen() int { return sl.maxLen }