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 {
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:
dj.SendPrivateMessage(user, COMMAND_DOESNT_EXIST_MSG)
}
@ -391,3 +416,29 @@ 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)
}
}
// 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
MaxSongDuration = 0
# Is playlist shuffling enabled when the bot starts?
# Default Value: false
AutomaticShuffleOn = false
[Cache]
# Cache songs as they are downloaded?
@ -55,7 +59,7 @@ LowestVolume = 0.01
# DEFAULT VALUE: 0.8
HighestVolume = 0.8
[Aliases]
# Alias used for add command
@ -126,6 +130,17 @@ CacheSizeAlias = "cachesize"
# DEFAULT VALUE: "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]
@ -201,3 +216,12 @@ 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
# Make shuffleon and shuffleoff admin commands?
# DEFAULT VALUE: true
AdminShuffleToggle = true

View file

@ -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,25 +52,30 @@ type DjConfig struct {
NumCachedAlias string
CacheSizeAlias string
KillAlias 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
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
}
}

View file

@ -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 {

View file

@ -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
@ -59,6 +64,9 @@ 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
q.RandomNextSong(false)
}
return q.queue[1], nil
}
return nil, errors.New("There isn't a Song coming up next.")
@ -104,3 +112,22 @@ 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]
}
}
// 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.
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.
const SONG_ADDED_HTML = `
<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>!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>!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>!reload</b> - Reloads mumbledj.gcfg configuration settings.</p>
<p><b>!setcomment</b> - Sets the comment for the bot.</p>