diff --git a/cache.go b/cache.go index 74368e4..0adda0e 100644 --- a/cache.go +++ b/cache.go @@ -16,6 +16,7 @@ import ( "time" ) +// ByAge is a type that holds file information for the cache items. type ByAge []os.FileInfo func (a ByAge) Len() int { @@ -28,11 +29,14 @@ func (a ByAge) Less(i, j int) bool { return time.Since(a[i].ModTime()) < time.Since(a[j].ModTime()) } +// SongCache is a struct that holds the number of songs currently cached and +// their combined file size. type SongCache struct { NumSongs int TotalFileSize int64 } +// NewSongCache creates an empty SongCache. func NewSongCache() *SongCache { newCache := &SongCache{ NumSongs: 0, @@ -41,13 +45,16 @@ func NewSongCache() *SongCache { return newCache } +// GetNumSongs returns the number of songs currently cached. func (c *SongCache) GetNumSongs() int { songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) return len(songs) } +// GetCurrentTotalFileSize calculates the total file size of the files within +// the cache and returns it. func (c *SongCache) GetCurrentTotalFileSize() int64 { - var totalSize int64 = 0 + var totalSize int64 songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) for _, song := range songs { totalSize += song.Size() @@ -55,6 +62,9 @@ func (c *SongCache) GetCurrentTotalFileSize() int64 { return totalSize } +// CheckMaximumDirectorySize checks the cache directory to determine if the filesize +// of the songs within exceed the user-specified size limit. If so, the oldest files +// get cleared until it is no longer exceeding the limit. func (c *SongCache) CheckMaximumDirectorySize() { for c.GetCurrentTotalFileSize() > (dj.conf.Cache.MaximumSize * 1048576) { if err := c.ClearOldest(); err != nil { @@ -63,11 +73,14 @@ func (c *SongCache) CheckMaximumDirectorySize() { } } +// Update updates the SongCache struct. func (c *SongCache) Update() { c.NumSongs = c.GetNumSongs() c.TotalFileSize = c.GetCurrentTotalFileSize() } +// ClearExpired clears cache items that are older than the cache period set within +// the user configuration. func (c *SongCache) ClearExpired() { for range time.Tick(5 * time.Minute) { songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) @@ -86,16 +99,15 @@ func (c *SongCache) ClearExpired() { } } +// ClearOldest deletes the oldest item in the cache. func (c *SongCache) ClearOldest() error { songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) sort.Sort(ByAge(songs)) if dj.queue.Len() > 0 { if (dj.queue.CurrentSong().Filename()) != songs[0].Name() { return os.Remove(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, songs[0].Name())) - } else { - return errors.New("Song is currently playing.") } - } else { - return os.Remove(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, songs[0].Name())) + return errors.New("Song is currently playing.") } + return os.Remove(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, songs[0].Name())) } diff --git a/commands.go b/commands.go index 6920092..644f842 100644 --- a/commands.go +++ b/commands.go @@ -18,8 +18,9 @@ import ( "github.com/layeh/gumble/gumble" ) -// Called on text message event. Checks the message for a command string, and processes it accordingly if -// it contains a command. +// parseCommand views incoming chat messages and determines if there is a valid command within them. +// If a command exists, the arguments (if any) will be parsed and sent to the appropriate helper +// function to perform the command's task. func parseCommand(user *gumble.User, username, command string) { var com, argument string split := strings.Split(command, "\n") @@ -157,7 +158,7 @@ func parseCommand(user *gumble.User, username, command string) { } } -// Performs add functionality. Checks input URL for YouTube format, and adds +// add performs !add functionality. Checks input URL for YouTube format, and adds // the URL to the queue if the format matches. func add(user *gumble.User, username, url string) { if url == "" { @@ -238,7 +239,7 @@ func add(user *gumble.User, username, url string) { } } -// Performs skip functionality. Adds a skip to the skippers slice for the current song, and then +// skip performs !skip functionality. Adds a skip to the skippers slice for the current song, and then // evaluates if a skip should be performed. Both skip and forceskip are implemented here. func skip(user *gumble.User, username string, admin, playlistSkip bool) { if dj.audioStream.IsPlaying() { @@ -306,12 +307,12 @@ func skip(user *gumble.User, username string, admin, playlistSkip bool) { } } -// Performs help functionality. Displays a list of valid commands. +// help performs !help functionality. Displays a list of valid commands. func help(user *gumble.User) { dj.SendPrivateMessage(user, HELP_HTML) } -// Performs volume functionality. Checks input value against LowestVolume and HighestVolume from +// volume performs !volume functionality. Checks input value against LowestVolume and HighestVolume from // config to determine if the volume should be applied. If in the correct range, the new volume // is applied and is immediately in effect. func volume(user *gumble.User, username, value string) { @@ -332,7 +333,7 @@ func volume(user *gumble.User, username, value string) { } } -// Performs move functionality. Determines if the supplied channel is valid and moves the bot +// move performs !move functionality. Determines if the supplied channel is valid and moves the bot // to the channel if it is. func move(user *gumble.User, channel string) { if channel == "" { @@ -346,14 +347,14 @@ func move(user *gumble.User, channel string) { } } -// Performs reload functionality. Tells command submitter if the reload completed successfully. +// reload performs !reload functionality. Tells command submitter if the reload completed successfully. func reload(user *gumble.User) { if err := loadConfiguration(); err == nil { dj.SendPrivateMessage(user, CONFIG_RELOAD_SUCCESS_MSG) } } -// Performs reset functionality. Clears the song queue, stops playing audio, and deletes all +// reset performs !reset functionality. Clears the song queue, stops playing audio, and deletes all // remaining songs in the ~/.mumbledj/songs directory. func reset(username string) { dj.queue.queue = dj.queue.queue[:0] @@ -369,7 +370,7 @@ func reset(username string) { } } -// Performs numsongs functionality. Uses the SongQueue traversal function to traverse the +// numSongs performs !numsongs functionality. Uses the SongQueue traversal function to traverse the // queue with a function call that increments a counter. Once finished, the bot outputs // the number of songs in the queue to chat. func numSongs() { @@ -380,7 +381,7 @@ func numSongs() { dj.client.Self.Channel.Send(fmt.Sprintf(NUM_SONGS_HTML, songCount), false) } -// Performs nextsong functionality. Uses the SongQueue PeekNext function to peek at the next +// nextSong performs !nextsong functionality. Uses the SongQueue PeekNext function to peek at the next // item if it exists. The user will then be sent a message containing the title and submitter // of the next item if it exists. func nextSong(user *gumble.User) { @@ -391,7 +392,7 @@ func nextSong(user *gumble.User) { } } -// Performs currentsong functionality. Sends the user who submitted the currentsong command +// currentSong performs !currentsong functionality. Sends the user who submitted the currentsong command // information about the song currently playing. func currentSong(user *gumble.User) { if dj.audioStream.IsPlaying() { @@ -406,13 +407,13 @@ func currentSong(user *gumble.User) { } } -// Performs setcomment functionality. Sets the bot's comment to whatever text is supplied in the argument. +// setComment performs !setcomment functionality. Sets the bot's comment to whatever text is supplied in the argument. func setComment(user *gumble.User, comment string) { dj.client.Self.SetComment(comment) dj.SendPrivateMessage(user, COMMENT_UPDATED_MSG) } -// Performs numcached functionality. Displays the number of songs currently cached on disk at ~/.mumbledj/songs. +// numCached performs !numcached functionality. Displays the number of songs currently cached on disk at ~/.mumbledj/songs. func numCached(user *gumble.User) { if dj.conf.Cache.Enabled { dj.cache.Update() @@ -422,7 +423,7 @@ func numCached(user *gumble.User) { } } -// Performs cachesize functionality. Displays the total file size of the cached audio files. +// cacheSize performs !cachesize functionality. Displays the total file size of the cached audio files. func cacheSize(user *gumble.User) { if dj.conf.Cache.Enabled { dj.cache.Update() @@ -432,7 +433,7 @@ func cacheSize(user *gumble.User) { } } -// Performs kill functionality. First cleans the ~/.mumbledj/songs directory to get rid of any +// kill performs !kill functionality. First cleans the ~/.mumbledj/songs directory to get rid of any // excess m4a files. The bot then safely disconnects from the server. func kill() { if err := deleteSongs(); err != nil { @@ -446,15 +447,14 @@ func kill() { } } -// Deletes songs from ~/.mumbledj/songs. +// deleteSongs deletes songs from ~/.mumbledj/songs. func deleteSongs() error { songsDir := fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir) if err := os.RemoveAll(songsDir); err != nil { return errors.New("An error occurred while deleting the audio files.") - } else { - if err := os.Mkdir(songsDir, 0777); err != nil { - return errors.New("An error occurred while recreating the songs directory.") - } - return nil } + if err := os.Mkdir(songsDir, 0777); err != nil { + return errors.New("An error occurred while recreating the songs directory.") + } + return nil } diff --git a/main.go b/main.go index e0f786a..b2fb25a 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,8 @@ import ( "github.com/layeh/gumble/gumbleutil" ) -// MumbleDJ type declaration +// mumbledj is a struct that keeps track of all aspects of the bot's current +// state. type mumbledj struct { config gumble.Config client *gumble.Client @@ -106,7 +107,7 @@ func (dj *mumbledj) OnUserChange(e *gumble.UserChangeEvent) { } } -// Checks if username has the permissions to execute a command. Permissions are specified in +// HasPermission checks if username has the permissions to execute a command. Permissions are specified in // mumbledj.gcfg. func (dj *mumbledj) HasPermission(username string, command bool) bool { if dj.conf.Permissions.AdminsEnabled && command { @@ -116,12 +117,11 @@ func (dj *mumbledj) HasPermission(username string, command bool) bool { } } return false - } else { - return true } + return true } -// Sends a private message to a user. Essentially just checks if a user is still in the server +// SendPrivateMessage sends a private message to a user. Essentially just checks if a user is still in the server // before sending them the message. func (dj *mumbledj) SendPrivateMessage(user *gumble.User, message string) { if targetUser := dj.client.Self.Channel.Users.Find(user.Name); targetUser != nil { @@ -146,7 +146,7 @@ var dj = mumbledj{ cache: NewSongCache(), } -// Main function, but only really performs startup tasks. Grabs and parses commandline +// main primarily performs startup tasks. Grabs and parses commandline // args, sets up the gumble client and its listeners, and then connects to the server. func main() { diff --git a/parseconfig.go b/parseconfig.go index e352cd5..9da7ec2 100644 --- a/parseconfig.go +++ b/parseconfig.go @@ -14,7 +14,7 @@ import ( "code.google.com/p/gcfg" ) -// 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 { General struct { CommandPrefix string @@ -77,8 +77,7 @@ type DjConfig struct { func loadConfiguration() error { if gcfg.ReadFileInto(&dj.conf, fmt.Sprintf("%s/.mumbledj/config/mumbledj.gcfg", dj.homeDir)) == nil { return nil - } else { - fmt.Printf("%s/.mumbledj/config/mumbledj.gcfg\n", dj.homeDir) - return errors.New("Configuration load failed.") } + fmt.Printf("%s/.mumbledj/config/mumbledj.gcfg\n", dj.homeDir) + return errors.New("Configuration load failed.") } diff --git a/songqueue.go b/songqueue.go index b9d20f8..3321ca2 100644 --- a/songqueue.go +++ b/songqueue.go @@ -18,30 +18,29 @@ type SongQueue struct { queue []Song } -// Initializes a new queue and returns the new SongQueue. +// NewSongQueue initializes a new queue and returns it. func NewSongQueue() *SongQueue { return &SongQueue{ queue: make([]Song, 0), } } -// Adds a Song to the SongQueue. +// AddSong adds a Song to the SongQueue. func (q *SongQueue) AddSong(s Song) error { beforeLen := q.Len() q.queue = append(q.queue, s) if len(q.queue) == beforeLen+1 { return nil - } else { - return errors.New("Could not add Song to the SongQueue.") } + return errors.New("Could not add Song to the SongQueue.") } -// Returns the current Song. +// CurrentSong returns the current Song. func (q *SongQueue) CurrentSong() Song { return q.queue[0] } -// Moves to the next Song in SongQueue. NextSong() removes the first Song in the queue. +// NextSong moves to the next Song in SongQueue. NextSong() removes the first Song in the queue. func (q *SongQueue) NextSong() { if q.CurrentSong().Playlist() != nil { if s, err := q.PeekNext(); err == nil { @@ -55,21 +54,20 @@ func (q *SongQueue) NextSong() { q.queue = q.queue[1:] } -// Peeks at the next Song and returns it. +// PeekNext peeks at the next Song and returns it. func (q *SongQueue) PeekNext() (Song, error) { if q.Len() > 1 { return q.queue[1], nil - } else { - return nil, errors.New("There isn't a Song coming up next.") } + return nil, errors.New("There isn't a Song coming up next.") } -// Returns the length of the SongQueue. +// Len returns the length of the SongQueue. func (q *SongQueue) Len() int { return len(q.queue) } -// A traversal function for SongQueue. Allows a visit function to be passed in which performs +// Traverse is a traversal function for SongQueue. Allows a visit function to be passed in which performs // the specified action on each queue item. func (q *SongQueue) Traverse(visit func(i int, s Song)) { for sQueue, queueSong := range q.queue { @@ -94,8 +92,8 @@ func (q *SongQueue) OnSongFinished() { } } -// Prepares next song and plays it if the download succeeds. Otherwise the function will print an error message -// to the channel and skip to the next song. +// PrepareAndPlayNextSong prepares next song and plays it if the download succeeds. +// Otherwise the function will print an error message to the channel and skip to the next song. func (q *SongQueue) PrepareAndPlayNextSong() { if err := q.CurrentSong().Download(); err == nil { q.CurrentSong().Play()