From 155bdfdffbae68f85cc971eb96ea432a6f4a736d Mon Sep 17 00:00:00 2001
From: Matt Kohls <mattkohls13@gmail.com>
Date: Sun, 14 Oct 2018 20:21:26 -0400
Subject: Adding ability for sounds to be added/removed on the fly

This adds a watcher to the directory named in localAudio (currently
doesn't check anything that may be in a child directory). Whenever a
file is created/deleted/renamed, it has the LocalAudioManager update its
sounds so they can be played.
---
 .../java/soundchan/BotListener/BotListener.java    | 13 +++++
 .../soundchan/BotListener/DirectoryWatcher.java    | 62 ++++++++++++++++++++++
 src/main/java/soundchan/LocalAudioManager.java     | 20 ++++---
 3 files changed, 89 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/soundchan/BotListener/DirectoryWatcher.java

(limited to 'src')

diff --git a/src/main/java/soundchan/BotListener/BotListener.java b/src/main/java/soundchan/BotListener/BotListener.java
index 9bcccfe..9177385 100644
--- a/src/main/java/soundchan/BotListener/BotListener.java
+++ b/src/main/java/soundchan/BotListener/BotListener.java
@@ -23,6 +23,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 public class BotListener extends ListenerAdapter{
 
@@ -32,6 +36,8 @@ public class BotListener extends ListenerAdapter{
     private final AudioPlayerManager playerManager;
     private final Map<Long, GuildMusicManager> musicManagers;
     private BotListenerHelpers helper = new BotListenerHelpers();
+    private ExecutorService executorService;
+    private Future<?> future;
 
     // From configuration file
     private static String followingUser;
@@ -45,6 +51,8 @@ public class BotListener extends ListenerAdapter{
         AudioSourceManagers.registerRemoteSources(playerManager);
         AudioSourceManagers.registerLocalSource(playerManager);
 
+        executorService = Executors.newSingleThreadExecutor();
+
         loadProperties(properties);
     }
 
@@ -67,6 +75,11 @@ public class BotListener extends ListenerAdapter{
         }
         else
             localManager = new LocalAudioManager(localFilePath);
+
+        DirectoryWatcher directoryWatcher = new DirectoryWatcher(localManager, localFilePath);
+        future = executorService.submit(directoryWatcher);
+        executorService.shutdown();
+
     }
 
     private synchronized GuildMusicManager getGuildAudioPlayer() {
diff --git a/src/main/java/soundchan/BotListener/DirectoryWatcher.java b/src/main/java/soundchan/BotListener/DirectoryWatcher.java
new file mode 100644
index 0000000..7d63bd1
--- /dev/null
+++ b/src/main/java/soundchan/BotListener/DirectoryWatcher.java
@@ -0,0 +1,62 @@
+package soundchan.BotListener;
+
+import soundchan.LocalAudioManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.*;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+public class DirectoryWatcher implements Runnable {
+
+    private LocalAudioManager localAudioManager;
+    private Path soundDir;
+    private WatchService watchService;
+    private WatchKey watchKey;
+
+    @SuppressWarnings("unchecked")
+    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
+        return (WatchEvent<T>) event;
+    }
+
+    public DirectoryWatcher(LocalAudioManager audioManager, String filepath) {
+        this.localAudioManager = audioManager;
+        this.soundDir = new File(filepath).toPath();
+        try {
+            this.watchService = FileSystems.getDefault().newWatchService();
+            this.watchKey = soundDir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+        } catch(IOException e) {
+            System.out.println("Error setting up watcher for " + filepath);
+        }
+    }
+
+    /**
+     * Called by an executor, checks for changes in the directory
+     */
+    public void run() {
+        try {
+            while(true) {
+                WatchKey key = watchService.take();
+                if(this.watchKey != key) {
+                    System.out.println("Error with WatchKey");
+                    continue;
+                }
+
+                for(WatchEvent<?> event : key.pollEvents()) {
+                    WatchEvent<Path> pathEvent = cast(event);
+                    //System.out.format("%s: %s\n", pathEvent.kind(), soundDir.resolve(pathEvent.context()));
+                    localAudioManager.UpdateFiles();
+                }
+
+                if(!key.reset()) {
+                    break;
+                }
+            }
+        } catch(InterruptedException e) {
+            return;
+        }
+    }
+}
diff --git a/src/main/java/soundchan/LocalAudioManager.java b/src/main/java/soundchan/LocalAudioManager.java
index 4b16850..306b8dd 100644
--- a/src/main/java/soundchan/LocalAudioManager.java
+++ b/src/main/java/soundchan/LocalAudioManager.java
@@ -20,8 +20,7 @@ public class LocalAudioManager {
 
     public LocalAudioManager(String filepath_in){
         filepath = filepath_in;
-        filenameDict = new HashMap<>();
-        PopulateFiles();
+        filenameDict = PopulateFiles();
     }
 
     /**
@@ -31,9 +30,8 @@ public class LocalAudioManager {
      */
     public LocalAudioManager(String filepath_in, String userSoundFile) {
         filepath = filepath_in;
-        filenameDict = new HashMap<>();
+        filenameDict = PopulateFiles();
         usernameDict = new HashMap<>();
-        PopulateFiles();
         MapUserAudio(userSoundFile);
     }
 
@@ -87,16 +85,26 @@ public class LocalAudioManager {
         channel.sendMessage(toPrint).queue();
     }
 
-    private void PopulateFiles(){
+    /**
+     * Updates the map of sound files
+     */
+    public void UpdateFiles() {
+        filenameDict = PopulateFiles();
+    }
+
+    private Map<String, String> PopulateFiles(){
         File folder = new File(filepath);
         File[] listOfFiles = folder.listFiles();
 
+        Map<String, String> fileDict = new HashMap<>();
+
         for (File file : listOfFiles) {
             if (file.isFile()) {
                 String filename = file.getName();
-                filenameDict.put(filename.substring(0, filename.indexOf('.')), filename);
+                fileDict.put(filename.substring(0, filename.indexOf('.')), filename);
             }
         }
+        return fileDict;
     }
 
     /**
-- 
cgit v1.2.3