From 03a51ed3b6d8afcf5c346f63557aba82866d9938 Mon Sep 17 00:00:00 2001 From: Gabriel Plassard Date: Tue, 6 Oct 2015 20:26:09 +0200 Subject: [PATCH 1/6] added support for !shuffle command --- commands.go | 19 +++++++++++++++++++ config.gcfg | 9 ++++++++- parseconfig.go | 2 ++ songqueue.go | 13 +++++++++++++ strings.go | 7 +++++++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/commands.go b/commands.go index 5d3d0de..ac5b332 100644 --- a/commands.go +++ b/commands.go @@ -152,6 +152,15 @@ func parseCommand(user *gumble.User, username, command string) { } else { dj.SendPrivateMessage(user, NO_PERMISSION_MSG) } + + // Shuffle command + case dj.conf.Aliases.ShuffleAlias: + if dj.HasPermission(username, dj.conf.Permissions.AdminShuffle) { + shuffleSongs(user, username) + } else { + dj.SendPrivateMessage(user, NO_PERMISSION_MSG) + } + default: dj.SendPrivateMessage(user, COMMAND_DOESNT_EXIST_MSG) } @@ -391,3 +400,13 @@ func deleteSongs() error { } return nil } + +// shuffles the song list +func shuffleSongs(user *gumble.User, username string) { + if dj.queue.Len() > 1 { + dj.queue.ShuffleSongs() + dj.client.Self.Channel.Send(fmt.Sprintf(SHUFFLE_SUCCESS_MSG, username), false) + } else { + dj.SendPrivateMessage(user, CANT_SHUFFLE_MSG) + } +} diff --git a/config.gcfg b/config.gcfg index db67c05..1b6a6a2 100644 --- a/config.gcfg +++ b/config.gcfg @@ -55,7 +55,7 @@ LowestVolume = 0.01 # DEFAULT VALUE: 0.8 HighestVolume = 0.8 - + [Aliases] # Alias used for add command @@ -126,6 +126,9 @@ CacheSizeAlias = "cachesize" # DEFAULT VALUE: "kill" KillAlias = "kill" +# Alias used for shuffle command +# DEFAULT VALUE: "shuffle" +ShuffleAlias = "shuffle" [Permissions] @@ -201,3 +204,7 @@ AdminCacheSize = true # Make kill an admin command? # DEFAULT VALUE: true (I recommend never changing this to false) AdminKill = true + +# Make shuffle an admin command? +# DEFAULT VALUE: true +AdminShuffle = true diff --git a/parseconfig.go b/parseconfig.go index 9da7ec2..f0ff824 100644 --- a/parseconfig.go +++ b/parseconfig.go @@ -51,6 +51,7 @@ type DjConfig struct { NumCachedAlias string CacheSizeAlias string KillAlias string + ShuffleAlias string } Permissions struct { AdminsEnabled bool @@ -70,6 +71,7 @@ type DjConfig struct { AdminNumCached bool AdminCacheSize bool AdminKill bool + AdminShuffle bool } } diff --git a/songqueue.go b/songqueue.go index f1bdc1c..c596fb1 100644 --- a/songqueue.go +++ b/songqueue.go @@ -11,8 +11,13 @@ import ( "errors" "fmt" "time" + "math/rand" ) +func init() { + rand.Seed(time.Now().UTC().UnixNano()) +} + // SongQueue type declaration. type SongQueue struct { queue []Song @@ -104,3 +109,11 @@ func (q *SongQueue) PrepareAndPlayNextSong() { q.OnSongFinished() } } + +// Shuffles the songqueue using inside-out algorithm +func (q *SongQueue) ShuffleSongs() { + for i := range q.queue[1:] { //Don't touch currently playing song + j := rand.Intn(i + 1) + q.queue[i + 1], q.queue[j + 1] = q.queue[j + 1], q.queue[i + 1] + } +} diff --git a/strings.go b/strings.go index 76b7541..6a59fad 100644 --- a/strings.go +++ b/strings.go @@ -71,6 +71,12 @@ const CACHE_SIZE_MSG = "The cache is currently %g MB in size." // Message shown to user when they attempt to issue a cache-related command when caching is not enabled. const CACHE_NOT_ENABLED_MSG = "The cache is not currently enabled." +// Message shown to user when they attempt to shuffle the a playlist with less than 2 elements. +const CANT_SHUFFLE_MSG = "Can't shuffle the playlist if there is less than 2 songs." + +// Message shown to user when the playlist has been successfully shuffled. +const SHUFFLE_SUCCESS_MSG = "The playlist has been successfully shuffled by %s (starting from next song)." + // Message shown to channel when a song is added to the queue by a user. const SONG_ADDED_HTML = ` %s has added "%s" to the queue. @@ -107,6 +113,7 @@ const HELP_HTML = `

!reset - An admin command that resets the song queue.

!forceskip - An admin command that forces a song skip.

!forceskipplaylist - An admin command that forces a playlist skip.

+

!shuffle - An admin command that shuffles the playlist.

!move - Moves MumbleDJ into channel if it exists.

!reload - Reloads mumbledj.gcfg configuration settings.

!setcomment - Sets the comment for the bot.

From 22466952208f9cd8c62ffd8fe079e18ef6821568 Mon Sep 17 00:00:00 2001 From: Gabriel Plassard Date: Wed, 7 Oct 2015 23:58:54 +0200 Subject: [PATCH 2/6] [WIP] Added support for !shuffleon and !shuffleoff commands #39 --- commands.go | 32 +++++++++++++++++++++++++++++++ config.gcfg | 12 ++++++++++++ parseconfig.go | 52 +++++++++++++++++++++++++++----------------------- songqueue.go | 4 ++++ strings.go | 20 ++++++++++++++++--- 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/commands.go b/commands.go index ac5b332..c2d832d 100644 --- a/commands.go +++ b/commands.go @@ -161,6 +161,22 @@ func parseCommand(user *gumble.User, username, command string) { dj.SendPrivateMessage(user, NO_PERMISSION_MSG) } + // Shuffleon command + case dj.conf.Aliases.ShuffleOnAlias: + if dj.HasPermission(username, dj.conf.Permissions.AdminShuffleToggle) { + toggleAutomaticShuffle(true, user, username) + } else { + dj.SendPrivateMessage(user, NO_PERMISSION_MSG) + } + + // Shuffleoff command + case dj.conf.Aliases.ShuffleOffAlias: + if dj.HasPermission(username, dj.conf.Permissions.AdminShuffleToggle) { + toggleAutomaticShuffle(false, user, username) + } else { + dj.SendPrivateMessage(user, NO_PERMISSION_MSG) + } + default: dj.SendPrivateMessage(user, COMMAND_DOESNT_EXIST_MSG) } @@ -410,3 +426,19 @@ func shuffleSongs(user *gumble.User, username string) { dj.SendPrivateMessage(user, CANT_SHUFFLE_MSG) } } + +// handles toggling of automatic shuffle playing +func toggleAutomaticShuffle(activate bool, user *gumble.User, username string){ + if (dj.conf.General.AutomaticShuffleOn != activate){ + dj.conf.General.AutomaticShuffleOn = activate + if (activate){ + dj.client.Self.Channel.Send(fmt.Sprintf(SHUFFLE_ON_MESSAGE, username), false) + } else{ + dj.client.Self.Channel.Send(fmt.Sprintf(SHUFFLE_OFF_MESSAGE, username), false) + } + } else if (activate){ + dj.SendPrivateMessage(user, SHUFFLE_ACTIVATED_ERROR_MESSAGE) + } else{ + dj.SendPrivateMessage(user, SHUFFLE_DEACTIVATED_ERROR_MESSAGE) + } +} diff --git a/config.gcfg b/config.gcfg index 1b6a6a2..0b24d99 100644 --- a/config.gcfg +++ b/config.gcfg @@ -26,6 +26,10 @@ DefaultComment = "Hello! I am a bot. Type !help for a list of commands." # Default Value: 0 MaxSongDuration = 0 +# Is playlist shuffling enabled when the bot starts? +# Default Value: false +AutomaticShuffleOn = false + [Cache] # Cache songs as they are downloaded? @@ -130,6 +134,14 @@ KillAlias = "kill" # DEFAULT VALUE: "shuffle" ShuffleAlias = "shuffle" +# Alias used for shuffleon command +# DEFAULT VALUE: "shuffleon" +ShuffleOnAlias = "shuffleon" + +# Alias used for shuffleoff command +# DEFAULT VALUE: "shuffleoff" +ShuffleOffAlias = "shuffleoff" + [Permissions] # Enable admins diff --git a/parseconfig.go b/parseconfig.go index f0ff824..e3dc403 100644 --- a/parseconfig.go +++ b/parseconfig.go @@ -17,11 +17,12 @@ import ( // DjConfig is a Golang struct representation of mumbledj.gcfg file structure for parsing. type DjConfig struct { General struct { - CommandPrefix string - SkipRatio float32 - PlaylistSkipRatio float32 - DefaultComment string - MaxSongDuration int + CommandPrefix string + SkipRatio float32 + PlaylistSkipRatio float32 + DefaultComment string + MaxSongDuration int + AutomaticShuffleOn bool } Cache struct { Enabled bool @@ -51,27 +52,30 @@ type DjConfig struct { NumCachedAlias string CacheSizeAlias string KillAlias string - ShuffleAlias string + ShuffleAlias string + ShuffleOnAlias string + ShuffleOffAlias string } Permissions struct { - AdminsEnabled bool - Admins []string - AdminAdd bool - AdminAddPlaylists bool - AdminSkip bool - AdminHelp bool - AdminVolume bool - AdminMove bool - AdminReload bool - AdminReset bool - AdminNumSongs bool - AdminNextSong bool - AdminCurrentSong bool - AdminSetComment bool - AdminNumCached bool - AdminCacheSize bool - AdminKill bool - AdminShuffle bool + AdminsEnabled bool + Admins []string + AdminAdd bool + AdminAddPlaylists bool + AdminSkip bool + AdminHelp bool + AdminVolume bool + AdminMove bool + AdminReload bool + AdminReset bool + AdminNumSongs bool + AdminNextSong bool + AdminCurrentSong bool + AdminSetComment bool + AdminNumCached bool + AdminCacheSize bool + AdminKill bool + AdminShuffle bool + AdminShuffleToggle bool } } diff --git a/songqueue.go b/songqueue.go index c596fb1..4000477 100644 --- a/songqueue.go +++ b/songqueue.go @@ -64,6 +64,10 @@ func (q *SongQueue) NextSong() { // PeekNext peeks at the next Song and returns it. func (q *SongQueue) PeekNext() (Song, error) { if q.Len() > 1 { + if (dj.conf.General.AutomaticShuffleOn){ //Shuffle mode is active + swapIndex := 1 + rand.Intn(q.Len()) + q.queue[offset], q.queue[swapIndex] = q.queue[swapIndex], q.queue[offset] + } return q.queue[1], nil } return nil, errors.New("There isn't a Song coming up next.") diff --git a/strings.go b/strings.go index 6a59fad..5d17e25 100644 --- a/strings.go +++ b/strings.go @@ -74,8 +74,20 @@ const CACHE_NOT_ENABLED_MSG = "The cache is not currently enabled." // Message shown to user when they attempt to shuffle the a playlist with less than 2 elements. const CANT_SHUFFLE_MSG = "Can't shuffle the playlist if there is less than 2 songs." -// Message shown to user when the playlist has been successfully shuffled. -const SHUFFLE_SUCCESS_MSG = "The playlist has been successfully shuffled by %s (starting from next song)." +// Message shown to users when the playlist has been successfully shuffled. +const SHUFFLE_SUCCESS_MSG = "The current playlist has been successfully shuffled by %s (starting from next song)." + +// Message shown to users when automatic shuffle is activated +const SHUFFLE_ON_MESSAGE = "%s has turned automatic shuffle on." + +// Message shown to users when automatic shuffle is deactivated +const SHUFFLE_OFF_MESSAGE = "%s has turned automatic shuffle off." + +// Message shown to user when they attempt to enable automatic shuffle while it's already activated +const SHUFFLE_ACTIVATED_ERROR_MESSAGE = "Automatic shuffle is already activated." + +// Message shown to user when they attempt to disable automatic shuffle while it's already deactivated +const SHUFFLE_DEACTIVATED_ERROR_MESSAGE = "Automatic shuffle is already deactivated." // Message shown to channel when a song is added to the queue by a user. const SONG_ADDED_HTML = ` @@ -113,7 +125,9 @@ const HELP_HTML = `

!reset - An admin command that resets the song queue.

!forceskip - An admin command that forces a song skip.

!forceskipplaylist - An admin command that forces a playlist skip.

-

!shuffle - An admin command that shuffles the playlist.

+

!shuffle - An admin command that shuffles the current playlist.

+

!shuffleon - An admin command that enables auto shuffling.

+

!shuffleoff - An admin command that disables auto shuffling.

!move - Moves MumbleDJ into channel if it exists.

!reload - Reloads mumbledj.gcfg configuration settings.

!setcomment - Sets the comment for the bot.

From 7dbbd77c4e91f999be9924d0c22fca50e8d6993b Mon Sep 17 00:00:00 2001 From: Gabriel Plassard Date: Thu, 8 Oct 2015 00:24:59 +0200 Subject: [PATCH 3/6] Fixup --- songqueue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/songqueue.go b/songqueue.go index 4000477..0255d00 100644 --- a/songqueue.go +++ b/songqueue.go @@ -66,7 +66,7 @@ func (q *SongQueue) PeekNext() (Song, error) { if q.Len() > 1 { if (dj.conf.General.AutomaticShuffleOn){ //Shuffle mode is active swapIndex := 1 + rand.Intn(q.Len()) - q.queue[offset], q.queue[swapIndex] = q.queue[swapIndex], q.queue[offset] + q.queue[1], q.queue[swapIndex] = q.queue[swapIndex], q.queue[1] } return q.queue[1], nil } From c5409a8d8bc7904438bbd55acf9cbf6b78e904d2 Mon Sep 17 00:00:00 2001 From: Gabriel Plassard Date: Fri, 9 Oct 2015 00:15:34 +0200 Subject: [PATCH 4/6] Fix first song not being shuffled --- service.go | 3 +++ songqueue.go | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/service.go b/service.go index 1e855b5..245947e 100644 --- a/service.go +++ b/service.go @@ -115,6 +115,9 @@ func FindServiceAndAdd(user *gumble.User, url string) error { // Starts playing the new song if nothing else is playing if oldLength == 0 && dj.queue.Len() != 0 && !dj.audioStream.IsPlaying() { + if (dj.conf.General.AutomaticShuffleOn){ + dj.queue.RandomNextSong(true) + } if err := dj.queue.CurrentSong().Download(); err == nil { dj.queue.CurrentSong().Play() } else { diff --git a/songqueue.go b/songqueue.go index 0255d00..182455d 100644 --- a/songqueue.go +++ b/songqueue.go @@ -64,9 +64,8 @@ func (q *SongQueue) NextSong() { // PeekNext peeks at the next Song and returns it. func (q *SongQueue) PeekNext() (Song, error) { if q.Len() > 1 { - if (dj.conf.General.AutomaticShuffleOn){ //Shuffle mode is active - swapIndex := 1 + rand.Intn(q.Len()) - q.queue[1], q.queue[swapIndex] = q.queue[swapIndex], q.queue[1] + if dj.conf.General.AutomaticShuffleOn{ //Shuffle mode is active + q.RandomNextSong(false) } return q.queue[1], nil } @@ -121,3 +120,14 @@ func (q *SongQueue) ShuffleSongs() { q.queue[i + 1], q.queue[j + 1] = q.queue[j + 1], q.queue[i + 1] } } + +// Sets a random song as next song to be played +// queueWasEmpty wether the queue was empty before adding the last Song +func (q *SongQueue) RandomNextSong(queueWasEmpty bool){ + nextSongIndex := 1 + if queueWasEmpty{ + nextSongIndex = 0 + } + swapIndex := nextSongIndex + rand.Intn(q.Len()) + q.queue[nextSongIndex], q.queue[swapIndex] = q.queue[swapIndex], q.queue[nextSongIndex] +} From 5deb85d8fbe8e71d4aa2b24671eae55bf2e84a14 Mon Sep 17 00:00:00 2001 From: Gabriel Plassard Date: Fri, 9 Oct 2015 21:49:56 +0200 Subject: [PATCH 5/6] cosmetic --- commands.go | 4 ++-- parseconfig.go | 6 +++--- songqueue.go | 4 ++-- strings.go | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/commands.go b/commands.go index c2d832d..8ff8846 100644 --- a/commands.go +++ b/commands.go @@ -162,14 +162,14 @@ func parseCommand(user *gumble.User, username, command string) { } // Shuffleon command - case dj.conf.Aliases.ShuffleOnAlias: + case dj.conf.Aliases.ShuffleOnAlias: if dj.HasPermission(username, dj.conf.Permissions.AdminShuffleToggle) { toggleAutomaticShuffle(true, user, username) } else { dj.SendPrivateMessage(user, NO_PERMISSION_MSG) } - // Shuffleoff command + // Shuffleoff command case dj.conf.Aliases.ShuffleOffAlias: if dj.HasPermission(username, dj.conf.Permissions.AdminShuffleToggle) { toggleAutomaticShuffle(false, user, username) diff --git a/parseconfig.go b/parseconfig.go index e3dc403..c69e8b3 100644 --- a/parseconfig.go +++ b/parseconfig.go @@ -52,7 +52,7 @@ type DjConfig struct { NumCachedAlias string CacheSizeAlias string KillAlias string - ShuffleAlias string + ShuffleAlias string ShuffleOnAlias string ShuffleOffAlias string } @@ -74,8 +74,8 @@ type DjConfig struct { AdminNumCached bool AdminCacheSize bool AdminKill bool - AdminShuffle bool - AdminShuffleToggle bool + AdminShuffle bool + AdminShuffleToggle bool } } diff --git a/songqueue.go b/songqueue.go index 182455d..f36e973 100644 --- a/songqueue.go +++ b/songqueue.go @@ -65,7 +65,7 @@ func (q *SongQueue) NextSong() { func (q *SongQueue) PeekNext() (Song, error) { if q.Len() > 1 { if dj.conf.General.AutomaticShuffleOn{ //Shuffle mode is active - q.RandomNextSong(false) + q.RandomNextSong(false) } return q.queue[1], nil } @@ -122,7 +122,7 @@ func (q *SongQueue) ShuffleSongs() { } // Sets a random song as next song to be played -// queueWasEmpty wether the queue was empty before adding the last Song +// queueWasEmpty wether the queue was empty before adding the last song func (q *SongQueue) RandomNextSong(queueWasEmpty bool){ nextSongIndex := 1 if queueWasEmpty{ diff --git a/strings.go b/strings.go index 5d17e25..8e19199 100644 --- a/strings.go +++ b/strings.go @@ -71,11 +71,11 @@ const CACHE_SIZE_MSG = "The cache is currently %g MB in size." // Message shown to user when they attempt to issue a cache-related command when caching is not enabled. const CACHE_NOT_ENABLED_MSG = "The cache is not currently enabled." -// Message shown to user when they attempt to shuffle the a playlist with less than 2 elements. -const CANT_SHUFFLE_MSG = "Can't shuffle the playlist if there is less than 2 songs." +// Message shown to user when they attempt to shuffle the queue and it has less than 2 elements. +const CANT_SHUFFLE_MSG = "Can't shuffle the queue if there is less than 2 songs." -// Message shown to users when the playlist has been successfully shuffled. -const SHUFFLE_SUCCESS_MSG = "The current playlist has been successfully shuffled by %s (starting from next song)." +// Message shown to users when the songqueue has been successfully shuffled. +const SHUFFLE_SUCCESS_MSG = "The current songqueue has been successfully shuffled by %s (starting from next song)." // Message shown to users when automatic shuffle is activated const SHUFFLE_ON_MESSAGE = "%s has turned automatic shuffle on." @@ -125,9 +125,9 @@ const HELP_HTML = `

!reset - An admin command that resets the song queue.

!forceskip - An admin command that forces a song skip.

!forceskipplaylist - An admin command that forces a playlist skip.

-

!shuffle - An admin command that shuffles the current playlist.

+

!shuffle - An admin command that shuffles the current queue.

!shuffleon - An admin command that enables auto shuffling.

-

!shuffleoff - An admin command that disables auto shuffling.

+

!shuffleoff - An admin command that disables auto shuffling.

!move - Moves MumbleDJ into channel if it exists.

!reload - Reloads mumbledj.gcfg configuration settings.

!setcomment - Sets the comment for the bot.

From 5e6b72c03e5ee026aed917cf0fc3fb8867fbf4bf Mon Sep 17 00:00:00 2001 From: Gabriel Plassard Date: Mon, 12 Oct 2015 18:05:14 +0200 Subject: [PATCH 6/6] add missing config entry --- config.gcfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config.gcfg b/config.gcfg index 0b24d99..408f51b 100644 --- a/config.gcfg +++ b/config.gcfg @@ -220,3 +220,8 @@ AdminKill = true # Make shuffle an admin command? # DEFAULT VALUE: true AdminShuffle = true + + +# Make shuffleon and shuffleoff admin commands? +# DEFAULT VALUE: true +AdminShuffleToggle = true