diff options
| -rw-r--r-- | backend.go | 8 | ||||
| -rw-r--r-- | localBackend.go | 4 | ||||
| -rw-r--r-- | player.go | 6 | ||||
| -rw-r--r-- | playlist.go | 3 | ||||
| -rw-r--r-- | playlist_test.go | 38 | ||||
| -rw-r--r-- | spotify.go | 6 | ||||
| -rw-r--r-- | upload.go | 2 | ||||
| -rw-r--r-- | wrms.go | 59 | ||||
| -rw-r--r-- | wrms_test.go | 42 | ||||
| -rw-r--r-- | youtube.go | 4 |
10 files changed, 96 insertions, 76 deletions
@@ -7,7 +7,7 @@ import ( type Backend interface { Play(song *Song, player Player) - Search(map[string]string) []Song + Search(map[string]string) []*Song OnSongFinished(song *Song) } @@ -15,12 +15,12 @@ type DummyBackend struct{} func (dummy *DummyBackend) Play(song *Song, player Player) {} func (dummy *DummyBackend) OnSongFinished(song *Song) {} -func (dummy *DummyBackend) Search(map[string]string) []Song { +func (dummy *DummyBackend) Search(map[string]string) []*Song { s := NewDummySong("Dummy Mc Crashtest", "foo") - return []Song{s} + return []*Song{s} } -func NewDummySong(title, artist string) Song { +func NewDummySong(title, artist string) *Song { h := sha1.New() h.Write([]byte(title)) h.Write([]byte(artist)) diff --git a/localBackend.go b/localBackend.go index cb07ab1..e59bf03 100644 --- a/localBackend.go +++ b/localBackend.go @@ -114,7 +114,7 @@ func (b *LocalBackend) findSongs() { s := NewSong(m.Title(), m.Artist(), "local", p) s.Album = m.Album() s.Year = m.Year() - songs = append(songs, &s) + songs = append(songs, s) return nil }) @@ -129,7 +129,7 @@ func (b *LocalBackend) Play(song *Song, player Player) { player.PlayUri("file://" + song.Uri) } -func (b *LocalBackend) Search(patterns map[string]string) (results []Song) { +func (b *LocalBackend) Search(patterns map[string]string) (results []*Song) { pattern := strings.ToLower(patterns["pattern"]) query := fmt.Sprintf("SELECT * FROM songs WHERE Title LIKE '%%%s%%' OR Artist LIKE '%%%s%%'", @@ -14,7 +14,7 @@ import ( type Player interface { Play(*Song) Playing() bool - Search(map[string]string) chan []Song + Search(map[string]string) chan []*Song PlayUri(string) PlayData(io.Reader) Pause() @@ -232,11 +232,11 @@ func (player *MpvPlayer) _stop() { player.mpv.Store(nil) } -func (player *MpvPlayer) Search(pattern map[string]string) chan []Song { +func (player *MpvPlayer) Search(pattern map[string]string) chan []*Song { var wg sync.WaitGroup wg.Add(len(player.Backends)) - ch := make(chan []Song) + ch := make(chan []*Song) for _, backend := range player.Backends { backend := backend diff --git a/playlist.go b/playlist.go index aeb1297..cb9c90c 100644 --- a/playlist.go +++ b/playlist.go @@ -78,7 +78,8 @@ func (pl *Playlist) OrderedList() []*Song { func (pl *Playlist) applyTimeBonus(timeBonus float64) { for _, s := range *pl { s.Weight += timeBonus + llog.DDebug("%p %v", s, s.Weight) } heap.Init(pl) - llog.DDebug("applying time bonus to the playlist") + llog.DDebug("applying time bonus to the playlist %v", *pl) } diff --git a/playlist_test.go b/playlist_test.go index 2ccad7c..8730737 100644 --- a/playlist_test.go +++ b/playlist_test.go @@ -5,7 +5,7 @@ import "testing" func TestPlAdd(t *testing.T) { var pl Playlist s := NewDummySong("Foo", "Bar") - pl.Add(&s) + pl.Add(s) if len(pl) != 1 { t.Log("len should be 1") t.Fail() @@ -15,7 +15,7 @@ func TestPlAdd(t *testing.T) { func TestPlAddPop(t *testing.T) { var pl Playlist s := NewDummySong("Foo", "Bar") - pl.Add(&s) + pl.Add(s) if len(pl) != 1 { t.Log("len should be 1") t.Fail() @@ -27,7 +27,7 @@ func TestPlAddPop(t *testing.T) { t.Fail() } - if ps != &s { + if ps != s { t.Log("the popped ptr should match the one added") t.Fail() } @@ -37,8 +37,8 @@ func TestPlAddPopTwice(t *testing.T) { var pl Playlist s1 := NewDummySong("Foo", "Bar") s2 := NewDummySong("Nasen", "Baer") - pl.Add(&s1) - pl.Add(&s2) + pl.Add(s1) + pl.Add(s2) if len(pl) != 2 { t.Log("len should be 2") t.Fail() @@ -51,12 +51,12 @@ func TestPlAddPopTwice(t *testing.T) { t.Fail() } - if ps1 != &s1 { + if ps1 != s1 { t.Log("the popped ptr should match the one added") t.Fail() } - if ps2 != &s2 { + if ps2 != s2 { t.Log("the popped ptr should match the one added") t.Fail() } @@ -66,15 +66,15 @@ func TestPlAdd2AdjustPop(t *testing.T) { var pl Playlist s1 := NewDummySong("Foo", "Bar") s2 := NewDummySong("Nasen", "Baer") - pl.Add(&s1) - pl.Add(&s2) + pl.Add(s1) + pl.Add(s2) if len(pl) != 2 { t.Log("len should be 2") t.Fail() } s2.Weight += 1 - pl.Adjust(&s2) + pl.Adjust(s2) ps := pl.PopSong() if len(pl) != 1 { @@ -82,7 +82,7 @@ func TestPlAdd2AdjustPop(t *testing.T) { t.Fail() } - if ps != &s2 { + if ps != s2 { t.Log("the popped ptr should match the one adjusted") t.Fail() } @@ -93,9 +93,9 @@ func TestPlAdd3AdjustAdjustPop(t *testing.T) { s1 := NewDummySong("Foo", "Bar") s2 := NewDummySong("Nasen", "Baer") s3 := NewDummySong("Hut", "Traeger") - pl.Add(&s1) - pl.Add(&s2) - pl.Add(&s3) + pl.Add(s1) + pl.Add(s2) + pl.Add(s3) if len(pl) != 3 { t.Log("len should be 3") @@ -103,13 +103,13 @@ func TestPlAdd3AdjustAdjustPop(t *testing.T) { } s1.Weight += 1 - pl.Adjust(&s1) + pl.Adjust(s1) s2.Weight -= 1 - pl.Adjust(&s2) + pl.Adjust(s2) s3.Weight += 1 - pl.Adjust(&s3) + pl.Adjust(s3) ps := pl.PopSong() if len(pl) != 2 { @@ -117,7 +117,7 @@ func TestPlAdd3AdjustAdjustPop(t *testing.T) { t.Fail() } - if ps == &s2 { + if ps == s2 { t.Log("the popped ptr is the downvoted one") t.Fail() } @@ -128,7 +128,7 @@ func TestPlAdd3AdjustAdjustPop(t *testing.T) { t.Fail() } - if ps == &s2 { + if ps == s2 { t.Log("the popped ptr is the downvoted one") t.Fail() } @@ -96,7 +96,7 @@ func (spotify *SpotifyBackend) Play(song *Song, player Player) { player.PlayData(audioFile) } -func (spotify *SpotifyBackend) Search(patterns map[string]string) []Song { +func (spotify *SpotifyBackend) Search(patterns map[string]string) []*Song { session := spotify.session keyword := "" for _, p := range []string{"pattern", "title", "artist", "album"} { @@ -110,7 +110,7 @@ func (spotify *SpotifyBackend) Search(patterns map[string]string) []Song { if err != nil { llog.Error("Failed to search: %s", err) - return []Song{} + return nil } res := resp.Results @@ -124,7 +124,7 @@ func (spotify *SpotifyBackend) Search(patterns map[string]string) []Song { llog.Debug("\nTracks: %d (total %d)\n", len(res.Tracks.Hits), res.Tracks.Total) - results := []Song{} + results := []*Song{} for _, track := range res.Tracks.Hits { uriParts := strings.Split(track.Uri, ":") s := NewSong(track.Name, track.Artists[0].Name, "spotify", uriParts[len(uriParts)-1]) @@ -95,6 +95,6 @@ func (b *UploadBackend) Play(song *Song, player Player) { player.PlayUri("file://" + path.Join(b.uploadDir, song.Uri)) } -func (b *UploadBackend) Search(map[string]string) []Song { +func (b *UploadBackend) Search(map[string]string) []*Song { return nil } @@ -26,8 +26,8 @@ type Song struct { Downvotes map[uuid.UUID]struct{} `json:"-"` } -func NewSong(title, artist, source, uri string) Song { - return Song{ +func NewSong(title, artist, source, uri string) *Song { + return &Song{ Title: title, Artist: artist, Source: source, @@ -37,33 +37,33 @@ func NewSong(title, artist, source, uri string) Song { } } -func NewDetailedSong(title, artist, source, uri, album string, year int) Song { +func NewDetailedSong(title, artist, source, uri, album string, year int) *Song { s := NewSong(title, artist, source, uri) s.Album = album s.Year = year return s } -func NewSongFromJson(data []byte) (Song, error) { +func NewSongFromJson(data []byte) (*Song, error) { var s Song err := json.Unmarshal(data, &s) if err != nil { llog.Error("Failed to parse song data %s with %s", string(data), err) - return s, err + return nil, err } s.Upvotes = map[uuid.UUID]struct{}{} s.Downvotes = map[uuid.UUID]struct{}{} - return s, nil + return &s, nil } type Event struct { - Event string `json:"cmd"` - Id uint64 `json:"id"` - Songs []Song `json:"songs"` + Event string `json:"cmd"` + Id uint64 `json:"id"` + Songs []*Song `json:"songs"` } -func (wrms *Wrms) newEvent(event string, songs []Song) Event { +func (wrms *Wrms) newEvent(event string, songs []*Song) Event { return Event{Id: wrms.eventId.Add(1), Event: event, Songs: songs} } @@ -188,7 +188,7 @@ type Wrms struct { nextConnNr atomic.Uint64 // The rwlock must be held when using most internal state rwlock sync.RWMutex - Songs []Song + Songs []*Song queue Playlist CurrentSong atomic.Pointer[Song] Player Player @@ -234,23 +234,23 @@ func (wrms *Wrms) initConn(conn *Connection) error { } if wrms.playing { - var songs []Song + var songs []*Song if currentSong := wrms.CurrentSong.Load(); currentSong != nil { - songs = []Song{*currentSong} + songs = []*Song{currentSong} } initialCmds = append(initialCmds, wrms.newEvent("play", songs)) } - upvoted := []Song{} - downvoted := []Song{} + upvoted := []*Song{} + downvoted := []*Song{} if len(wrms.Songs) > 0 { initialCmds = append(initialCmds, wrms.newEvent("add", wrms.Songs)) for _, song := range wrms.queue.OrderedList() { if _, ok := song.Upvotes[conn.Id]; ok { - upvoted = append(upvoted, *song) + upvoted = append(upvoted, song) } else if _, ok := song.Downvotes[conn.Id]; ok { - downvoted = append(downvoted, *song) + downvoted = append(downvoted, song) } } } @@ -291,20 +291,21 @@ func (wrms *Wrms) Broadcast(ev Event) { }) } -func (wrms *Wrms) AddSong(song Song) { +func (wrms *Wrms) AddSong(song *Song) { wrms.rwlock.Lock() startPlayingAgain := wrms.playing && wrms.CurrentSong.Load() == nil - wrms.Songs = append(wrms.Songs, song) - s := &wrms.Songs[len(wrms.Songs)-1] - wrms.queue.Add(s) if wrms.Config.timeBonus != 0 { llog.Info("Apply time bonus %v", wrms.Config.timeBonus) wrms.queue.applyTimeBonus(wrms.Config.timeBonus) } - ev := wrms.newEvent("add", []Song{song}) + wrms.Songs = append(wrms.Songs, song) + s := wrms.Songs[len(wrms.Songs)-1] + wrms.queue.Add(s) + + ev := wrms.newEvent("add", []*Song{song}) wrms.rwlock.Unlock() llog.Info("Added song %s (ptr=%p) to Songs", s.Uri, s) @@ -319,7 +320,7 @@ func (wrms *Wrms) DeleteSong(songUri string) { wrms.rwlock.Lock() for i := 0; i < len(wrms.Songs); i++ { - s := &wrms.Songs[i] + s := wrms.Songs[i] if s.Uri != songUri { continue } @@ -329,7 +330,7 @@ func (wrms *Wrms) DeleteSong(songUri string) { wrms.queue.RemoveSong(s) - ev := wrms.newEvent("delete", []Song{*s}) + ev := wrms.newEvent("delete", []*Song{s}) wrms.rwlock.Unlock() wrms.Broadcast(ev) @@ -383,7 +384,7 @@ func (wrms *Wrms) _next() { cmd = "play" } - ev := wrms.newEvent(cmd, []Song{*next}) + ev := wrms.newEvent(cmd, []*Song{next}) wrms.rwlock.Unlock() wrms.Broadcast(ev) @@ -421,7 +422,7 @@ func (wrms *Wrms) PlayPause() { wrms.Player.Play(currentSong) } - ev := wrms.newEvent("play", []Song{*currentSong}) + ev := wrms.newEvent("play", []*Song{currentSong}) wrms.rwlock.Unlock() wrms.Broadcast(ev) @@ -431,7 +432,7 @@ func (wrms *Wrms) AdjustSongWeight(connId uuid.UUID, songUri string, vote string wrms.rwlock.Lock() for i := 0; i < len(wrms.Songs); i++ { - s := &wrms.Songs[i] + s := wrms.Songs[i] if s.Uri != songUri { continue } @@ -488,7 +489,7 @@ func (wrms *Wrms) AdjustSongWeight(connId uuid.UUID, songUri string, vote string } wrms.queue.Adjust(s) - ev := wrms.newEvent("update", []Song{*s}) + ev := wrms.newEvent("update", []*Song{s}) wrms.rwlock.Unlock() wrms.Broadcast(ev) @@ -496,6 +497,6 @@ func (wrms *Wrms) AdjustSongWeight(connId uuid.UUID, songUri string, vote string } } -func (wrms *Wrms) Search(pattern map[string]string) chan []Song { +func (wrms *Wrms) Search(pattern map[string]string) chan []*Song { return wrms.Player.Search(pattern) } diff --git a/wrms_test.go b/wrms_test.go index 7d0c4d1..29ee2b2 100644 --- a/wrms_test.go +++ b/wrms_test.go @@ -1,22 +1,22 @@ package main import ( + "fmt" "github.com/google/uuid" "io" - "muhq.space/go/wrms/llog" "testing" ) type mockPlayer struct{} -func (p *mockPlayer) Play(*Song) {} -func (p *mockPlayer) PlayUri(string) {} -func (p *mockPlayer) PlayData(io.Reader) {} -func (p *mockPlayer) Search(pattern map[string]string) (res chan []Song) { return } -func (p *mockPlayer) Playing() bool { return false } -func (p *mockPlayer) Pause() {} -func (p *mockPlayer) Continue() {} -func (p *mockPlayer) Stop() {} +func (p *mockPlayer) Play(*Song) {} +func (p *mockPlayer) PlayUri(string) {} +func (p *mockPlayer) PlayData(io.Reader) {} +func (p *mockPlayer) Search(pattern map[string]string) (res chan []*Song) { return } +func (p *mockPlayer) Playing() bool { return false } +func (p *mockPlayer) Pause() {} +func (p *mockPlayer) Continue() {} +func (p *mockPlayer) Stop() {} var alice, _ = uuid.NewRandom() @@ -33,7 +33,7 @@ func TestWrmsAdd(t *testing.T) { func TestWrmsAdd3Next3(t *testing.T) { wrms := Wrms{Player: &mockPlayer{}} - songs := []Song{ + songs := []*Song{ NewDummySong("song1", "snfmt"), NewDummySong("song2", "snfmt"), NewDummySong("song3", "snfmt"), @@ -94,7 +94,6 @@ func TestWrmsUpUpDownNextNext(t *testing.T) { wrms.AddSong(s2) wrms.AddSong(s3) - llog.Info("UpUpDown test") wrms.AdjustSongWeight(alice, s1.Uri, "up") wrms.AdjustSongWeight(alice, s2.Uri, "down") wrms.AdjustSongWeight(alice, s3.Uri, "up") @@ -114,7 +113,6 @@ func TestWrmsDoubleAdd(t *testing.T) { wrms := Wrms{Player: &mockPlayer{}} s1 := NewDummySong("song1", "snfmt") - llog.Info("Double Add test") wrms.AddSong(s1) wrms.AdjustSongWeight(alice, s1.Uri, "up") wrms.Next() @@ -141,3 +139,23 @@ func TestFlipVote(t *testing.T) { t.Fail() } } + +func TestTimeBonus(t *testing.T) { + wrms := Wrms{Player: &mockPlayer{}} + wrms.Config.timeBonus = 0.1 + songs := []*Song{ + NewDummySong("song1", "snfmt"), + NewDummySong("song2", "snfmt"), + NewDummySong("song3", "snfmt"), + } + + for _, s := range songs { + wrms.AddSong(s) + } + + exp := 0.1 * float64(len(songs)-1) + if wrms.Songs[0].Weight != exp { + t.Log(fmt.Sprintf("TimeBonus not correctly applied song %p %v expected: %v", &wrms.Songs[0], wrms.Songs[0], exp)) + t.Fail() + } +} @@ -27,7 +27,7 @@ type YoutubeDlSearchResult struct { Title string } -func (b *YoutubeBackend) Search(patterns map[string]string) []Song { +func (b *YoutubeBackend) Search(patterns map[string]string) []*Song { pattern := "" for _, v := range patterns { pattern += v + " " @@ -41,7 +41,7 @@ func (b *YoutubeBackend) Search(patterns map[string]string) []Song { llog.Error("youtube-dl failed with: %s", err) } - songs := []Song{} + songs := []*Song{} for _, l := range strings.Split(string(results), "\n") { if l == "" { continue |
