1
0
dwelling-radio/internal/radio/song.go

100 lines
2.3 KiB
Go
Raw Normal View History

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
}
// ArtistTitle returns a string formatted as "<artist> - <title>".
func (s *Song) ArtistTitle() string {
return s.Artist + " - " + s.Title
}
// 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"`
Duration string `json:"duration"`
MaxListeners int `json:"listeners"`
StartAt string `json:"start_at"`
}{
Artist: s.Artist,
Title: s.Title,
DurationMill: s.Duration.Milliseconds(),
Duration: s.DurationString(),
MaxListeners: s.MaxListeners,
StartAt: s.StartAt.UTC().Format(time.RFC3339)})
}
type SongList struct {
sync.Mutex
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.Lock()
defer sl.Unlock()
if sl.current.StartAt.Year() == 1 {
return nil
}
return &sl.current
}
// List returns a list of lastly played songs.
func (sl *SongList) List() []Song {
sl.Lock()
defer sl.Unlock()
return sl.lastSongs
}
// MaxLen returns a maximal length of a list
func (sl *SongList) MaxLen() int {
return sl.maxLen
}