diff --git a/Goopfile b/Goopfile index 27a6c5e..d53564c 100644 --- a/Goopfile +++ b/Goopfile @@ -3,3 +3,4 @@ github.com/layeh/gumble/gumble #8b9989d9c4090874546c45ceaa6ff21e95705bc4 github.com/layeh/gumble/gumble_ffmpeg #c9fcce8fc4b71c7c53a5d3d9d48a1e001ad19a19 github.com/scalingdata/gcfg #37aabad69cfd3d20b8390d902a8b10e245c615ff github.com/jmoiron/jsonq #7c27c8eb9f6831555a4209f6a7d579159e766a3c +github.com/mildred/go-xdg #96b70c9133fdb4c32f9c551d50455152dea68d73 diff --git a/Makefile b/Makefile index 00566a5..ec8d022 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,6 @@ clean: install: mkdir -p ~/.mumbledj/config - mkdir -p ~/.mumbledj/songs if [ -f ~/.mumbledj/config/mumbledj.gcfg ]; then mv ~/.mumbledj/config/mumbledj.gcfg ~/.mumbledj/config/mumbledj_backup.gcfg; fi; cp -u config.gcfg ~/.mumbledj/config/mumbledj.gcfg sed -i 's/YouTube = \"/YouTube = \"'$(YOUTUBE_API_KEY)'/' ~/.mumbledj/config/mumbledj.gcfg diff --git a/README.md b/README.md index 225030e..d0bb2cd 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Command | Description | Arguments | Admin | Example **setcomment** | Sets the comment for the bot. If no argument is given, the current comment will be removed. | None OR new_comment | Yes | `!setcomment Hello! I am a bot. Type !help for the available commands.` **numcached** | Outputs the number of songs currently cached on disk. | None | Yes | `!numcached` **cachesize** | Outputs the total file size of the cache in MB. | None | Yes | `!cachesize` -**kill** | Safely cleans the bot environment and disconnects from the server. Please use this command to stop the bot instead of force closing, as the kill command deletes any remaining songs in the `~/.mumbledj/songs` directory. | None | Yes | `!kill` +**kill** | Safely cleans the bot environment and disconnects from the server. Please use this command to stop the bot instead of force closing, as the kill command deletes any remaining songs in the song cache directory. | None | Yes | `!kill` diff --git a/cache.go b/cache.go index 0adda0e..97c0cc4 100644 --- a/cache.go +++ b/cache.go @@ -47,7 +47,7 @@ func NewSongCache() *SongCache { // GetNumSongs returns the number of songs currently cached. func (c *SongCache) GetNumSongs() int { - songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) + songs, _ := ioutil.ReadDir(dj.songCacheDir) return len(songs) } @@ -55,7 +55,7 @@ func (c *SongCache) GetNumSongs() int { // the cache and returns it. func (c *SongCache) GetCurrentTotalFileSize() int64 { var totalSize int64 - songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) + songs, _ := ioutil.ReadDir(dj.songCacheDir) for _, song := range songs { totalSize += song.Size() } @@ -83,16 +83,16 @@ func (c *SongCache) Update() { // the user configuration. func (c *SongCache) ClearExpired() { for range time.Tick(5 * time.Minute) { - songs, _ := ioutil.ReadDir(fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)) + songs, _ := ioutil.ReadDir(dj.songCacheDir) for _, song := range songs { hours := time.Since(song.ModTime()).Hours() if hours >= dj.conf.Cache.ExpireTime { if dj.queue.Len() > 0 { if (dj.queue.CurrentSong().Filename()) != song.Name() { - os.Remove(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, song.Name())) + os.Remove(fmt.Sprintf("%s/%s", dj.songCacheDir, song.Name())) } } else { - os.Remove(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, song.Name())) + os.Remove(fmt.Sprintf("%s/%s", dj.songCacheDir, song.Name())) } } } @@ -101,13 +101,13 @@ 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)) + songs, _ := ioutil.ReadDir(dj.songCacheDir) 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())) + return os.Remove(fmt.Sprintf("%s/%s", dj.songCacheDir, songs[0].Name())) } return errors.New("Song is currently playing.") } - return os.Remove(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, songs[0].Name())) + return os.Remove(fmt.Sprintf("%s/%s", dj.songCacheDir, songs[0].Name())) } diff --git a/commands.go b/commands.go index 544569d..0d51966 100644 --- a/commands.go +++ b/commands.go @@ -11,6 +11,7 @@ import ( "bytes" "errors" "fmt" + "io/ioutil" "os" "strconv" "strings" @@ -355,7 +356,7 @@ func reload(user *gumble.User) { } // reset performs !reset functionality. Clears the song queue, stops playing audio, and deletes all -// remaining songs in the ~/.mumbledj/songs directory. +// remaining songs in the song cache directory. func reset(username string) { dj.queue.queue = dj.queue.queue[:0] if dj.audioStream.IsPlaying() { @@ -413,7 +414,7 @@ func setComment(user *gumble.User, comment string) { dj.SendPrivateMessage(user, COMMENT_UPDATED_MSG) } -// numCached 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. func numCached(user *gumble.User) { if dj.conf.Cache.Enabled { dj.cache.Update() @@ -433,7 +434,7 @@ func cacheSize(user *gumble.User) { } } -// kill performs !kill functionality. First cleans the ~/.mumbledj/songs directory to get rid of any +// kill performs !kill functionality. First cleans the song cache directory to get rid of any // excess m4a files. The bot then safely disconnects from the server. func kill() { if err := deleteSongs(); err != nil { @@ -447,14 +448,16 @@ func kill() { } } -// deleteSongs deletes songs from ~/.mumbledj/songs. +// deleteSongs deletes songs from the song cache. 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.") + songs, err := ioutil.ReadDir(dj.songCacheDir) + if err != nil { + return errors.New(fmt.Sprintf("An error occured while clearing %q: %v", dj.songCacheDir, err)) } - if err := os.Mkdir(songsDir, 0777); err != nil { - return errors.New("An error occurred while recreating the songs directory.") + for _, file := range songs { + if err2 := os.Remove(fmt.Sprintf("%s/%s", dj.songCacheDir, file.Name())); err2 != nil { + return errors.New(fmt.Sprintf("An error occurred while removing %q: %v", file.Name(), err2)) + } } return nil } diff --git a/main.go b/main.go index 53f843b..1235602 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( "github.com/layeh/gumble/gumble" "github.com/layeh/gumble/gumble_ffmpeg" "github.com/layeh/gumble/gumbleutil" + "github.com/mildred/go-xdg" ) // mumbledj is a struct that keeps track of all aspects of the bot's current @@ -34,6 +35,7 @@ type mumbledj struct { queue *SongQueue audioStream *gumble_ffmpeg.Stream homeDir string + songCacheDir string playlistSkips map[string][]string cache *SongCache } @@ -190,6 +192,9 @@ func main() { if currentUser, err := user.Current(); err == nil { dj.homeDir = currentUser.HomeDir } + if songCacheDir, err := xdg.Cache.EnsureDir("mumbledj/songs"); err == nil { + dj.songCacheDir = songCacheDir + } if err := loadConfiguration(); err == nil { fmt.Println("Configuration successfully loaded!") diff --git a/youtube_dl.go b/youtube_dl.go index ff39510..b19acc3 100644 --- a/youtube_dl.go +++ b/youtube_dl.go @@ -51,12 +51,12 @@ type AudioPlaylist struct { // ------------ // Download downloads the song via youtube-dl if it does not already exist on disk. -// All downloaded songs are stored in ~/.mumbledj/songs and should be automatically cleaned. +// All downloaded songs are stored in the song cache and should be automatically cleaned. func (dl *AudioTrack) Download() error { // Checks to see if song is already downloaded - if _, err := os.Stat(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename())); os.IsNotExist(err) { - cmd := exec.Command("youtube-dl", "--verbose", "--no-mtime", "--output", fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename()), "--format", dl.format, "--prefer-ffmpeg", dl.url) + if _, err := os.Stat(fmt.Sprintf("%s/%s", dj.songCacheDir, dl.Filename())); os.IsNotExist(err) { + cmd := exec.Command("youtube-dl", "--verbose", "--no-mtime", "--output", fmt.Sprintf("%s/%s", dj.songCacheDir, dl.Filename()), "--format", dl.format, "--prefer-ffmpeg", dl.url) output, err := cmd.CombinedOutput() if err == nil { if dj.conf.Cache.Enabled { @@ -82,7 +82,7 @@ func (dl *AudioTrack) Play() { offsetDuration, _ := time.ParseDuration(fmt.Sprintf("%ds", dl.offset)) dj.audioStream.Offset = offsetDuration } - dj.audioStream.Source = gumble_ffmpeg.SourceFile(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename())) + dj.audioStream.Source = gumble_ffmpeg.SourceFile(fmt.Sprintf("%s/%s", dj.songCacheDir, dl.Filename())) if err := dj.audioStream.Play(); err != nil { panic(err) } else { @@ -101,10 +101,10 @@ func (dl *AudioTrack) Play() { } } -// Delete deletes the song from ~/.mumbledj/songs if the cache is disabled. +// Delete deletes the song from the song cache if the cache is disabled. func (dl *AudioTrack) Delete() error { if dj.conf.Cache.Enabled == false { - filePath := fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename()) + filePath := fmt.Sprintf("%s/%s", dj.songCacheDir, dl.Filename()) if _, err := os.Stat(filePath); err == nil { if err := os.Remove(filePath); err == nil { return nil