Skip to content

Commit

Permalink
Added a queue command (#46)
Browse files Browse the repository at this point in the history
* moved the queue and added a couple of util functions + tests

* added the queue command

* gofmt
  • Loading branch information
svenwiltink authored Jun 4, 2018
1 parent e510ea1 commit 1bf16f8
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 87 deletions.
20 changes: 19 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@
[[constraint]]
branch = "master"
name = "github.com/ChannelMeter/iso8601duration"

[[constraint]]
name = "github.com/stretchr/testify"
version = "1.2.1"
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ GIT_VERSION_TAG=`git describe --tags --long`

BUILD_PLATFORMS ?= -os '!netbsd' -os '!openbsd' -os '!freebsd'

all: deps verify build
all: deps verify build test

help:

Expand All @@ -35,3 +35,5 @@ build:
@mkdir -p out/binaries
gox $(BUILD_PLATFORMS) \
-output="out/binaries/$(NAME)-{{.OS}}-{{.Arch}}"
test:
go test -v './...'
7 changes: 6 additions & 1 deletion bot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (bot *MusicBot) Start() {

bot.musicPlayer.AddListener(music.EventSongStarted, func(arguments ...interface{}) {
song := arguments[0].(*music.Song)
bot.BroadcastMessage(fmt.Sprintf("Started playing %v", song.Name))
bot.BroadcastMessage(fmt.Sprintf("Started playing %s: %s", song.Artist, song.Name))
})

bot.musicPlayer.AddListener(music.EventSongStartError, func(arguments ...interface{}) {
Expand Down Expand Up @@ -103,6 +103,7 @@ func (bot *MusicBot) registerCommands() {
bot.registerCommand(pausedCommand)
bot.registerCommand(playCommand)
bot.registerCommand(currentCommand)
bot.registerCommand(queueCommand)
bot.registerCommand(whiteListCommand)
bot.registerCommand(volCommand)
bot.registerCommand(aboutCommand)
Expand Down Expand Up @@ -156,3 +157,7 @@ func (bot *MusicBot) handleMessage(message Message) {
}
}
}

func (bot *MusicBot) GetMusicPlayer() music.Player {
return bot.musicPlayer
}
30 changes: 26 additions & 4 deletions bot/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ var addCommand = &Command{
bot.ReplyToMessage(message, err.Error())
} else {
if message.IsPrivate {
bot.BroadcastMessage(fmt.Sprintf("%s - %s added by %s", song.Artist, song.Name, message.Sender.NickName))
bot.BroadcastMessage(fmt.Sprintf("%s: %s added by %s", song.Artist, song.Name, message.Sender.NickName))
}
bot.ReplyToMessage(message, fmt.Sprintf("%s - %s added", song.Artist, song.Name))
bot.ReplyToMessage(message, fmt.Sprintf("%s: %s added", song.Artist, song.Name))
}
},
}
Expand Down Expand Up @@ -81,10 +81,10 @@ var searchAddCommand = &Command{
}

if message.IsPrivate {
bot.BroadcastMessage(fmt.Sprintf("%s - %s added by %s", song.Artist, song.Name, message.Sender.NickName))
bot.BroadcastMessage(fmt.Sprintf("%s: %s added by %s", song.Artist, song.Name, message.Sender.NickName))
}

bot.ReplyToMessage(message, fmt.Sprintf("%s - %s added", song.Artist, song.Name))
bot.ReplyToMessage(message, fmt.Sprintf("%s: %s added", song.Artist, song.Name))
},
}

Expand Down Expand Up @@ -160,6 +160,28 @@ var currentCommand = &Command{
},
}

var queueCommand = &Command{
Name: "queue",
Function: func(bot *MusicBot, message Message) {
queue := bot.GetMusicPlayer().GetQueue()

queueLength := queue.GetLength()
nextSongs, _ := queue.GetNextN(5)
duration := queue.GetTotalDuration()

bot.ReplyToMessage(message, fmt.Sprintf("%d songs in the queue. Total duration %s", queueLength, duration.String()))

for index, song := range nextSongs {
bot.ReplyToMessage(message, fmt.Sprintf("#%d, %s: %s (%s)\n", index+1, song.Artist, song.Name, song.Duration.String()))
}

if queueLength > 5 {
bot.ReplyToMessage(message, fmt.Sprintf("and %d more", queueLength-5))
}

},
}

var whiteListCommand = &Command{
Name: "whitelist",
MasterOnly: true,
Expand Down
1 change: 1 addition & 0 deletions music/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Player interface {
Stop()
GetStatus() PlayerStatus
GetCurrentSong() (*Song, time.Duration)
GetQueue() *Queue
}

type PlayerStatus string
Expand Down
10 changes: 7 additions & 3 deletions music/player/musicplayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// MusicPlayer is responsible for playing music
type MusicPlayer struct {
*eventemitter.Emitter
Queue *Queue
Queue *music.Queue
Status music.PlayerStatus
dataProviders []music.DataProvider
musicProviders []music.Provider
Expand All @@ -23,6 +23,10 @@ type MusicPlayer struct {
currentSongEnds time.Time
}

func (player *MusicPlayer) GetQueue() *music.Queue {
return player.Queue
}

func (player *MusicPlayer) Pause() error {
if player.Status != music.PlayerStatusPlaying {
return errors.New("cannot pause, nothing is playing")
Expand Down Expand Up @@ -158,7 +162,7 @@ func (player *MusicPlayer) AddSong(song *music.Song) error {
return fmt.Errorf("no suitable player found for %+v", song)
}

player.Queue.append(song)
player.Queue.Append(song)
return nil
}

Expand Down Expand Up @@ -247,7 +251,7 @@ func (player *MusicPlayer) Stop() {
func NewMusicPlayer(providers []music.Provider, dataProviders []music.DataProvider) *MusicPlayer {
instance := &MusicPlayer{
Emitter: eventemitter.NewEmitter(false),
Queue: NewQueue(),
Queue: music.NewQueue(),
musicProviders: providers,
dataProviders: dataProviders,
shouldStop: false,
Expand Down
77 changes: 0 additions & 77 deletions music/player/queue.go

This file was deleted.

115 changes: 115 additions & 0 deletions music/queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package music

import (
"log"
"sync"

"errors"
"github.com/vansante/go-event-emitter"
"time"
)

const (
songAdded eventemitter.EventType = "song-added"
)

// Queue holds an array of songs
type Queue struct {
*eventemitter.Emitter
songs []*Song
lock sync.Mutex
}

func (queue *Queue) Append(songs ...*Song) {
queue.lock.Lock()
defer queue.lock.Unlock()

queue.songs = append(queue.songs, songs...)
log.Println("Song added to the queue")
queue.EmitEvent(songAdded)
}

// GetNext returns the next item in the queue if it exists
func (queue *Queue) GetNext() *Song {
queue.lock.Lock()
defer queue.lock.Unlock()

return queue.getNext()
}

func (queue *Queue) getNext() *Song {
if len(queue.songs) == 0 {
return nil
}
song, remaining := queue.songs[0], queue.songs[1:]

queue.songs = remaining

return song
}

func (queue *Queue) GetLength() int {
queue.lock.Lock()
defer queue.lock.Unlock()

return len(queue.songs)
}

func (queue *Queue) GetTotalDuration() time.Duration {
queue.lock.Lock()
defer queue.lock.Unlock()

var duration time.Duration

for _, song := range queue.songs {
duration = duration + song.Duration
}

return duration.Round(time.Second)
}

func (queue *Queue) GetNextN(limit int) ([]Song, error) {
if limit <= 0 {
return nil, errors.New("limit must be greater than 0")
}

queue.lock.Lock()
defer queue.lock.Unlock()

if len(queue.songs) < limit {
limit = len(queue.songs)
}

result := make([]Song, limit)
for i := 0; i < limit; i++ {
result[i] = *queue.songs[i]
}

return result, nil
}

// WaitForNext is a blocking call that returns the next song in the queue and wait for one to be added
// if there is no song available.
func (queue *Queue) WaitForNext() *Song {
next := queue.GetNext()

if next != nil {
return next
}

done := make(chan struct{})
queue.ListenOnce(songAdded, func(args ...interface{}) {
done <- struct{}{}
})

<-done
return queue.GetNext()
}

// NewQueue creates a new instance of Queue
func NewQueue() *Queue {
return &Queue{
songs: make([]*Song, 0),
Emitter: eventemitter.NewEmitter(true),
}
}
Loading

0 comments on commit 1bf16f8

Please sign in to comment.