diff options
Diffstat (limited to 'src/main/java')
4 files changed, 242 insertions, 20 deletions
| diff --git a/src/main/java/soundchan/BotListener/BotListener.java b/src/main/java/soundchan/BotListener/BotListener.java index 415e350..b8b4bad 100644 --- a/src/main/java/soundchan/BotListener/BotListener.java +++ b/src/main/java/soundchan/BotListener/BotListener.java @@ -19,10 +19,12 @@ import net.dv8tion.jda.core.hooks.ListenerAdapter;  import net.dv8tion.jda.core.managers.AudioManager;  import soundchan.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.nio.file.WatchEvent; +import java.sql.SQLOutput; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future;  public class BotListener extends ListenerAdapter{ @@ -32,6 +34,7 @@ public class BotListener extends ListenerAdapter{      private final AudioPlayerManager playerManager;      private final Map<Long, GuildMusicManager> musicManagers;      private BotListenerHelpers helper = new BotListenerHelpers(); +    private Map<String, Future<?> > otherTasks;      // From configuration file      private static String followingUser; @@ -56,17 +59,35 @@ public class BotListener extends ListenerAdapter{          localFilePath = properties.getProperty("localFilePath");          followingUser = properties.getProperty("followingUser");          audioOnUserJoin = settingEnableCheck(properties.getProperty("audioOnUserJoin")); +        otherTasks = new HashMap<>();          if(audioOnUserJoin) {              String userAudioPath = properties.getProperty("userAudioFilePath");              if(userAudioPath == null || userAudioPath.contentEquals("")) { -                localManager = new LocalAudioManager(localFilePath, "usersound.properties"); +                userAudioPath = "usersound.properties";              } -            else { -                localManager = new LocalAudioManager(localFilePath, userAudioPath); +            localManager = new LocalAudioManager(localFilePath, userAudioPath); + +            if(settingEnableCheck(properties.getProperty("watchUserSoundFile"))) { +                addWatcherTask(new MediaWatcherListener() { +                    @Override +                    public void onWatchEvent(WatchEvent event) { +                        localManager.UpdateUserAudio(); +                    } +                }, userAudioPath, "watchUserSoundFile", false);              }          }          else              localManager = new LocalAudioManager(localFilePath); + +        if(settingEnableCheck(properties.getProperty("watchLocalFilePath"))) { +            addWatcherTask(new MediaWatcherListener() { +                @Override +                public void onWatchEvent(WatchEvent event) { +                    localManager.UpdateFiles(); +                } +            }, localFilePath, "watchLocalFilePath", true); +        } +      }      private synchronized GuildMusicManager getGuildAudioPlayer() { @@ -425,6 +446,8 @@ public class BotListener extends ListenerAdapter{       * @return True if it matches a value to enable, False otherwise       */      private static boolean settingEnableCheck(String value) { +        if(value == null) +            return false;          value = value.toLowerCase();          if(value.contentEquals("true") || value.contentEquals("1") ||                  value.contentEquals("yes") || value.contentEquals("on") || @@ -434,4 +457,18 @@ public class BotListener extends ListenerAdapter{              return false;      } +    /** +     * Adds a new MediaWatcher to the list of running tasks +     * @param listener Listener that will get callback during watching of media +     * @param filepath Path to either directory or file +     * @param taskName Thing to name task as +     * @param watchSubDirs Also watch any subdirectories in the given directory (doesn't do anything if watching a file) +     */ +    private void addWatcherTask(@NotNull MediaWatcherListener listener, String filepath, String taskName, boolean watchSubDirs) { +        ExecutorService executorService = Executors.newSingleThreadExecutor(); +        MediaWatcher watcher = new MediaWatcher(listener, filepath, watchSubDirs); +        otherTasks.put(taskName, executorService.submit(watcher)); +        executorService.shutdown(); +    } +  } diff --git a/src/main/java/soundchan/BotListener/MediaWatcher.java b/src/main/java/soundchan/BotListener/MediaWatcher.java new file mode 100644 index 0000000..2784eec --- /dev/null +++ b/src/main/java/soundchan/BotListener/MediaWatcher.java @@ -0,0 +1,147 @@ +package soundchan.BotListener; + +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; + +import static java.lang.Thread.sleep; +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 MediaWatcher implements Runnable { + +    private MediaWatcherListener listener; +    private String mediaFilename; +    private Path mediaDir; +    private WatchService watchService; +    private WatchKey watchKey; +    private ArrayList<WatchKey> subDirKeys; +    private boolean isDirectory; +    private int sleepTime = 5000; + +    @SuppressWarnings("unchecked") +    static <T> WatchEvent<T> cast(WatchEvent<?> event) { +        return (WatchEvent<T>) event; +    } + +    /** +     * Creates a MediaWatcher, which monitors changes to files either within a directory or for a specific file. +     * Defaults to scanning every 5 seconds. +     * @param listener Object that will get a callback when there is a watch event +     * @param filepath Path to either directory or specific file +     * @param watchSubDirs Also watch any subdirectories in the given directory (doesn't do anything if watching a file) +     */ +    public MediaWatcher(MediaWatcherListener listener, String filepath, boolean watchSubDirs) { +        this.listener = listener; +        startWatchService(filepath, watchSubDirs); +    } + +    /** +     * Creates a MediaWatcher, which monitors changes to files either within a directory or for a specific file. +     * @param listener Object that will get a callback when there is a watch event +     * @param filepath Path to either directory or specific file +     * @param watchSubDirs Also watch any subdirectories in the given directory (doesn't do anything if watching a file) +     * @param sleepTime How long to put the scanner thread to sleep between rescans (time in milliseconds) +     */ +    public MediaWatcher(MediaWatcherListener listener, String filepath, boolean watchSubDirs, int sleepTime) { +        this.listener = listener; +        this.sleepTime = sleepTime; +        startWatchService(filepath, watchSubDirs); +    } + +    /** +     * Sets up watch service for the file/directory +     * @param filepath Path to file or directory to be scanned +     * @param watchSubDirs Also watch any subdirectories in the given directory (doesn't do anything if watching a file) +     */ +    private void startWatchService(String filepath, boolean watchSubDirs) { +        File mediaFile = new File(filepath); +        this.mediaFilename = mediaFile.getName(); +        if(mediaFile.isFile()) { +            try { +                this.mediaDir = mediaFile.getCanonicalFile().getParentFile().toPath(); +            } catch (IOException e) { +                System.out.println("Error getting parent path of " + mediaFilename); +            } +            isDirectory = false; +        } else if(mediaFile.isDirectory()) { +            this.mediaDir = mediaFile.toPath(); +            isDirectory = true; +            subDirKeys = new ArrayList<>(); +        } +        try { +            this.watchService = FileSystems.getDefault().newWatchService(); +            this.watchKey = mediaDir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); +            if(isDirectory && watchSubDirs) { +                Files.walkFileTree(mediaDir, new SimpleFileVisitor<Path>() { +                    @Override +                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { +                        try { +                            WatchKey temp = dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); +                            subDirKeys.add(temp); +                            return FileVisitResult.CONTINUE; +                        } catch (IOException e) { +                            System.out.println("Error setting up watch service with sub dirs in " + filepath); +                            return FileVisitResult.SKIP_SUBTREE; +                        } +                    } +                }); +            } +        } catch (IOException e) { +            System.out.println("Error setting up watcher for " + filepath); +        } +    } + +    /** +     * Called by an executor, checks for changes to file(s) +     */ +    public void run() { +        try { +            while(true) { +                WatchKey key = watchService.take(); // Wait for an event to happen + +                // Check this event happened in a place we are monitoring, otherwise ignore it +                if(!isDirectory && this.watchKey != key) { +                    System.out.println("Error with WatchKey"); +                    continue; +                } else if(isDirectory) { +                    if(this.watchKey != key) { // Our event doesn't happen in the root of the sounds directory +                        boolean noKeyMatch = true; +                        for(WatchKey subKey : subDirKeys) { // Check if it happened in on of the sub directories +                            if(subKey == key) { +                                noKeyMatch = false; +                                break; +                            } +                        } +                        if(noKeyMatch) { +                            System.out.println("Error with WatchKey"); +                            continue; +                        } +                    } +                } + +                for(WatchEvent<?> event : key.pollEvents()) { +                    WatchEvent<Path> pathEvent = cast(event); +                    if(isDirectory) { +                        listener.onWatchEvent(event); +                    } else { +                        if(pathEvent.context().endsWith(mediaFilename)) { +                            listener.onWatchEvent(event); +                        } +                    } +                } + +                if(!key.reset()) { +                    break; +                } + +                sleep(sleepTime); +            } +        } catch(InterruptedException e) { +            return; +        } +    } +} diff --git a/src/main/java/soundchan/BotListener/MediaWatcherListener.java b/src/main/java/soundchan/BotListener/MediaWatcherListener.java new file mode 100644 index 0000000..8c146f6 --- /dev/null +++ b/src/main/java/soundchan/BotListener/MediaWatcherListener.java @@ -0,0 +1,12 @@ +package soundchan.BotListener; + +import java.nio.file.WatchEvent; + +public interface MediaWatcherListener { + +    /** +     * Called by MediaWatcher when there is a file event. Any created, deleted, or modified events will be passed for use. +     * @param event The type of event that triggered the update. +     */ +    void onWatchEvent(WatchEvent event); +} diff --git a/src/main/java/soundchan/LocalAudioManager.java b/src/main/java/soundchan/LocalAudioManager.java index 28d25b9..ea5b317 100644 --- a/src/main/java/soundchan/LocalAudioManager.java +++ b/src/main/java/soundchan/LocalAudioManager.java @@ -17,11 +17,12 @@ public class LocalAudioManager {      public Map<String, String> filenameDict;      public Map<String, String> usernameDict;      private String filepath; +    private String userSoundFilepath;      public LocalAudioManager(String filepath_in){          filepath = filepath_in; -        filenameDict = new HashMap<>(); -        PopulateFiles(); +        userSoundFilepath = null; +        filenameDict = PopulateFiles();      }      /** @@ -31,10 +32,9 @@ public class LocalAudioManager {       */      public LocalAudioManager(String filepath_in, String userSoundFile) {          filepath = filepath_in; -        filenameDict = new HashMap<>(); -        usernameDict = new HashMap<>(); -        PopulateFiles(); -        MapUserAudio(userSoundFile); +        userSoundFilepath = userSoundFile; +        filenameDict = PopulateFiles(); +        usernameDict = MapUserAudio();      }      /** @@ -90,31 +90,57 @@ public class LocalAudioManager {          channel.sendMessage(toPrint).queue();      } -    private void PopulateFiles(){ +    /** +     * Updates the map of sound files +     */ +    public void UpdateFiles() { +        filenameDict = PopulateFiles(); +    } + +    /** +     * Updates the map of usernames to sound files +     */ +    public void UpdateUserAudio() { +        if(userSoundFilepath != null | userSoundFilepath.contentEquals("")) { +            usernameDict = MapUserAudio(); +        } +    } + +    /** +     * Creates a map of the sounds in the sound directory +     * @return A map with the filename (without extension) is the key for the filename (with extension) +     */ +    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;      }      /**       * Reads in users and their respective sounds from file, then builds a map of users to the filenames. This assumes       * filenames for the sounds are valid, but doesn't check for them. -     * @param userSoundFile The file (with path if required) with listing of users and the sounds to play when they join +     * @return A map with the usernames as the keys for the filename of the sound       */ -    private void MapUserAudio(String userSoundFile) { -        Properties userSoundProp = LoadProperties(userSoundFile); +    private Map<String, String> MapUserAudio() { +        Properties userSoundProp = LoadProperties(userSoundFilepath);          Set<String> users = userSoundProp.stringPropertyNames(); + +        Map<String, String> userDict = new HashMap<>(); +          for(String user : users) {              String soundFile = userSoundProp.getProperty(user); -            usernameDict.put(user, soundFile); +            userDict.put(user, soundFile);          } - +        return userDict;      }      /** | 
