Merge pull request #90 from GabrielPlassard/master

Add support for !shuffle, !shuffleon and !shuffleoff commands #39
This commit is contained in:
Matthieu Grieger 2015-10-12 14:01:06 -07:00
commit ae61d8cdf2
6 changed files with 155 additions and 23 deletions

View file

@ -152,6 +152,31 @@ func parseCommand(user *gumble.User, username, command string) {
} else { } else {
dj.SendPrivateMessage(user, NO_PERMISSION_MSG) 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)
}
// 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: default:
dj.SendPrivateMessage(user, COMMAND_DOESNT_EXIST_MSG) dj.SendPrivateMessage(user, COMMAND_DOESNT_EXIST_MSG)
} }
@ -391,3 +416,29 @@ func deleteSongs() error {
} }
return nil 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)
}
}
// 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)
}
}

View file

@ -26,6 +26,10 @@ DefaultComment = "Hello! I am a bot. Type !help for a list of commands."
# Default Value: 0 # Default Value: 0
MaxSongDuration = 0 MaxSongDuration = 0
# Is playlist shuffling enabled when the bot starts?
# Default Value: false
AutomaticShuffleOn = false
[Cache] [Cache]
# Cache songs as they are downloaded? # Cache songs as they are downloaded?
@ -126,6 +130,17 @@ CacheSizeAlias = "cachesize"
# DEFAULT VALUE: "kill" # DEFAULT VALUE: "kill"
KillAlias = "kill" KillAlias = "kill"
# Alias used for shuffle command
# 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] [Permissions]
@ -201,3 +216,12 @@ AdminCacheSize = true
# Make kill an admin command? # Make kill an admin command?
# DEFAULT VALUE: true (I recommend never changing this to false) # DEFAULT VALUE: true (I recommend never changing this to false)
AdminKill = true AdminKill = true
# Make shuffle an admin command?
# DEFAULT VALUE: true
AdminShuffle = true
# Make shuffleon and shuffleoff admin commands?
# DEFAULT VALUE: true
AdminShuffleToggle = true

View file

@ -22,6 +22,7 @@ type DjConfig struct {
PlaylistSkipRatio float32 PlaylistSkipRatio float32
DefaultComment string DefaultComment string
MaxSongDuration int MaxSongDuration int
AutomaticShuffleOn bool
} }
Cache struct { Cache struct {
Enabled bool Enabled bool
@ -51,6 +52,9 @@ type DjConfig struct {
NumCachedAlias string NumCachedAlias string
CacheSizeAlias string CacheSizeAlias string
KillAlias string KillAlias string
ShuffleAlias string
ShuffleOnAlias string
ShuffleOffAlias string
} }
Permissions struct { Permissions struct {
AdminsEnabled bool AdminsEnabled bool
@ -70,6 +74,8 @@ type DjConfig struct {
AdminNumCached bool AdminNumCached bool
AdminCacheSize bool AdminCacheSize bool
AdminKill bool AdminKill bool
AdminShuffle bool
AdminShuffleToggle bool
} }
} }

View file

@ -115,6 +115,9 @@ func FindServiceAndAdd(user *gumble.User, url string) error {
// Starts playing the new song if nothing else is playing // Starts playing the new song if nothing else is playing
if oldLength == 0 && dj.queue.Len() != 0 && !dj.audioStream.IsPlaying() { 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 { if err := dj.queue.CurrentSong().Download(); err == nil {
dj.queue.CurrentSong().Play() dj.queue.CurrentSong().Play()
} else { } else {

View file

@ -11,8 +11,13 @@ import (
"errors" "errors"
"fmt" "fmt"
"time" "time"
"math/rand"
) )
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
// SongQueue type declaration. // SongQueue type declaration.
type SongQueue struct { type SongQueue struct {
queue []Song queue []Song
@ -59,6 +64,9 @@ func (q *SongQueue) NextSong() {
// PeekNext peeks at the next Song and returns it. // PeekNext peeks at the next Song and returns it.
func (q *SongQueue) PeekNext() (Song, error) { func (q *SongQueue) PeekNext() (Song, error) {
if q.Len() > 1 { if q.Len() > 1 {
if dj.conf.General.AutomaticShuffleOn{ //Shuffle mode is active
q.RandomNextSong(false)
}
return q.queue[1], nil return q.queue[1], nil
} }
return nil, errors.New("There isn't a Song coming up next.") return nil, errors.New("There isn't a Song coming up next.")
@ -104,3 +112,22 @@ func (q *SongQueue) PrepareAndPlayNextSong() {
q.OnSongFinished() 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]
}
}
// 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]
}

View file

@ -71,6 +71,24 @@ 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. // 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." const CACHE_NOT_ENABLED_MSG = "The cache is not currently enabled."
// 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 songqueue has been successfully shuffled.
const SHUFFLE_SUCCESS_MSG = "The current songqueue has been successfully shuffled by <b>%s</b> (starting from next song)."
// Message shown to users when automatic shuffle is activated
const SHUFFLE_ON_MESSAGE = "<b>%s</b> has turned automatic shuffle on."
// Message shown to users when automatic shuffle is deactivated
const SHUFFLE_OFF_MESSAGE = "<b>%s</b> 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. // Message shown to channel when a song is added to the queue by a user.
const SONG_ADDED_HTML = ` const SONG_ADDED_HTML = `
<b>%s</b> has added "%s" to the queue. <b>%s</b> has added "%s" to the queue.
@ -107,6 +125,9 @@ const HELP_HTML = `<br/>
<p><b>!reset</b> - An admin command that resets the song queue. </p> <p><b>!reset</b> - An admin command that resets the song queue. </p>
<p><b>!forceskip</b> - An admin command that forces a song skip. </p> <p><b>!forceskip</b> - An admin command that forces a song skip. </p>
<p><b>!forceskipplaylist</b> - An admin command that forces a playlist skip. </p> <p><b>!forceskipplaylist</b> - An admin command that forces a playlist skip. </p>
<p><b>!shuffle</b> - An admin command that shuffles the current queue. </p>
<p><b>!shuffleon</b> - An admin command that enables auto shuffling.</p>
<p><b>!shuffleoff</b> - An admin command that disables auto shuffling.</p>
<p><b>!move </b>- Moves MumbleDJ into channel if it exists.</p> <p><b>!move </b>- Moves MumbleDJ into channel if it exists.</p>
<p><b>!reload</b> - Reloads mumbledj.gcfg configuration settings.</p> <p><b>!reload</b> - Reloads mumbledj.gcfg configuration settings.</p>
<p><b>!setcomment</b> - Sets the comment for the bot.</p> <p><b>!setcomment</b> - Sets the comment for the bot.</p>