From 8f16b5d96f0dc7860a048e600bf7b4e1f9c72178 Mon Sep 17 00:00:00 2001 From: "Alexander \"Arav\" Andreev" Date: Mon, 13 Mar 2023 00:03:59 +0400 Subject: [PATCH] Implemented a functionality for storing and showing most listened song. --- internal/radio/mostlistened.go | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 internal/radio/mostlistened.go diff --git a/internal/radio/mostlistened.go b/internal/radio/mostlistened.go new file mode 100644 index 0000000..c3cf249 --- /dev/null +++ b/internal/radio/mostlistened.go @@ -0,0 +1,76 @@ +package radio + +import ( + "bytes" + "errors" + "strconv" + "time" +) + +type MostListenedSong struct { + Listeners int + Date time.Time + Song string +} + +func (mls *MostListenedSong) DateString() string { + return mls.Date.Format("02 January 2006") +} + +var mostListened MostListenedSong + +// CheckAndUpdateMostListenedSong compares current most played song with +// provided `cur`rent song's listeners, and if it is larger, then it takes +// `prev`ious song's name. +// +// Why we take a previous song's name? Experimentally I noticed that Icecast +// writes amount of listeners that was by the very start of a next song. So +// it means that it was actually amount of listeners by the end of +// the previous song. +// +// So it would be fairer to give these listeners back to a song they was +// listening to. +func CheckAndUpdateMostListenedSong(cur, prev Song) { + l, _ := strconv.Atoi(cur.Listeners) + if l > mostListened.Listeners { + mostListened = MostListenedSong{ + Listeners: l, + Date: time.Now().UTC(), + Song: prev.Song} + } +} + +// MostListened returns song that currently is the song with most simultaneous +// listeners. +func MostListened() *MostListenedSong { + return &mostListened +} + +func LoadMostListenedSong(data []byte) (err error) { + lines := bytes.Split(data, []byte{'\n'}) + if len(lines) != 3 { + return errors.New("lines count mismatch, should be 3") + } + mostListened = MostListenedSong{} + if mostListened.Date, err = time.Parse(time.RFC3339, string(lines[0])); err != nil { + return err + } + if mostListened.Listeners, err = strconv.Atoi(string(lines[1])); err != nil { + return err + } + mostListened.Song = string(lines[2]) + return nil +} + +func StoreMostListenedSong() []byte { + buf := make([]byte, 0, 30+len(mostListened.Song)) + b := bytes.NewBuffer(buf) + + b.WriteString(mostListened.Date.Format(time.RFC3339)) + b.WriteByte('\n') + b.WriteString(strconv.Itoa(mostListened.Listeners)) + b.WriteByte('\n') + b.WriteString(mostListened.Song) + + return b.Bytes() +}