Merge pull request #90 from GabrielPlassard/master
Add support for !shuffle, !shuffleon and !shuffleoff commands #39
This commit is contained in:
commit
ae61d8cdf2
51
commands.go
51
commands.go
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
24
config.gcfg
24
config.gcfg
|
@ -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
|
||||||
|
|
|
@ -17,11 +17,12 @@ import (
|
||||||
// DjConfig is a Golang struct representation of mumbledj.gcfg file structure for parsing.
|
// DjConfig is a Golang struct representation of mumbledj.gcfg file structure for parsing.
|
||||||
type DjConfig struct {
|
type DjConfig struct {
|
||||||
General struct {
|
General struct {
|
||||||
CommandPrefix string
|
CommandPrefix string
|
||||||
SkipRatio float32
|
SkipRatio float32
|
||||||
PlaylistSkipRatio float32
|
PlaylistSkipRatio float32
|
||||||
DefaultComment string
|
DefaultComment string
|
||||||
MaxSongDuration int
|
MaxSongDuration int
|
||||||
|
AutomaticShuffleOn bool
|
||||||
}
|
}
|
||||||
Cache struct {
|
Cache struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
@ -51,25 +52,30 @@ 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
|
||||||
Admins []string
|
Admins []string
|
||||||
AdminAdd bool
|
AdminAdd bool
|
||||||
AdminAddPlaylists bool
|
AdminAddPlaylists bool
|
||||||
AdminSkip bool
|
AdminSkip bool
|
||||||
AdminHelp bool
|
AdminHelp bool
|
||||||
AdminVolume bool
|
AdminVolume bool
|
||||||
AdminMove bool
|
AdminMove bool
|
||||||
AdminReload bool
|
AdminReload bool
|
||||||
AdminReset bool
|
AdminReset bool
|
||||||
AdminNumSongs bool
|
AdminNumSongs bool
|
||||||
AdminNextSong bool
|
AdminNextSong bool
|
||||||
AdminCurrentSong bool
|
AdminCurrentSong bool
|
||||||
AdminSetComment bool
|
AdminSetComment bool
|
||||||
AdminNumCached bool
|
AdminNumCached bool
|
||||||
AdminCacheSize bool
|
AdminCacheSize bool
|
||||||
AdminKill bool
|
AdminKill bool
|
||||||
|
AdminShuffle bool
|
||||||
|
AdminShuffleToggle bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
27
songqueue.go
27
songqueue.go
|
@ -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]
|
||||||
|
}
|
||||||
|
|
21
strings.go
21
strings.go
|
@ -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>
|
||||||
|
|
Reference in a new issue