Version 1: Basic functionality #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -1,10 +1,6 @@
 | 
			
		|||
package handiebot;
 | 
			
		||||
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
 | 
			
		||||
import handiebot.command.CommandHandler;
 | 
			
		||||
import handiebot.lavaplayer.GuildMusicManager;
 | 
			
		||||
import handiebot.lavaplayer.MusicPlayer;
 | 
			
		||||
import sx.blah.discord.api.ClientBuilder;
 | 
			
		||||
import sx.blah.discord.api.IDiscordClient;
 | 
			
		||||
| 
						 | 
				
			
			@ -13,8 +9,7 @@ import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedE
 | 
			
		|||
import sx.blah.discord.util.DiscordException;
 | 
			
		||||
import sx.blah.discord.util.RateLimitException;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Andrew Lalis
 | 
			
		||||
| 
						 | 
				
			
			@ -22,29 +17,16 @@ import java.util.Map;
 | 
			
		|||
 */
 | 
			
		||||
public class HandieBot {
 | 
			
		||||
 | 
			
		||||
    public static Logger log = Logger.getLogger("HandieBotLog");
 | 
			
		||||
 | 
			
		||||
    private static final String TOKEN = "MjgzNjUyOTg5MjEyNjg4Mzg0.C45A_Q.506b0G6my1FEFa7_YY39lxLBHUY";
 | 
			
		||||
 | 
			
		||||
    private static IDiscordClient client;
 | 
			
		||||
 | 
			
		||||
    private CommandHandler commandHandler;
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) throws DiscordException, RateLimitException {
 | 
			
		||||
        System.out.println("Logging bot in...");
 | 
			
		||||
        client = new ClientBuilder().withToken(TOKEN).build();
 | 
			
		||||
        client.getDispatcher().registerListener(new HandieBot());
 | 
			
		||||
        client.login();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final AudioPlayerManager playerManager;
 | 
			
		||||
    private final Map<Long, GuildMusicManager> musicManagers;
 | 
			
		||||
    private MusicPlayer musicPlayer;
 | 
			
		||||
 | 
			
		||||
    private HandieBot() {
 | 
			
		||||
        this.musicManagers = new HashMap<>();
 | 
			
		||||
        this.playerManager = new DefaultAudioPlayerManager();
 | 
			
		||||
        AudioSourceManagers.registerRemoteSources(playerManager);
 | 
			
		||||
        AudioSourceManagers.registerLocalSource(playerManager);
 | 
			
		||||
 | 
			
		||||
        this.commandHandler = new CommandHandler(this);
 | 
			
		||||
        this.musicPlayer = new MusicPlayer();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -58,5 +40,11 @@ public class HandieBot {
 | 
			
		|||
        this.commandHandler.handleCommand(event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) throws DiscordException, RateLimitException {
 | 
			
		||||
        System.out.println("Logging bot in.");
 | 
			
		||||
        client = new ClientBuilder().withToken(TOKEN).build();
 | 
			
		||||
        client.getDispatcher().registerListener(new HandieBot());
 | 
			
		||||
        client.login();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package handiebot.command;
 | 
			
		|||
 | 
			
		||||
import com.sun.istack.internal.NotNull;
 | 
			
		||||
import handiebot.HandieBot;
 | 
			
		||||
import handiebot.utils.DisappearingMessage;
 | 
			
		||||
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
 | 
			
		||||
import sx.blah.discord.handle.obj.*;
 | 
			
		||||
import sx.blah.discord.util.EmbedBuilder;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,16 +35,24 @@ public class CommandHandler {
 | 
			
		|||
        String command = extractCommand(message);
 | 
			
		||||
        String[] args = extractArgs(message);
 | 
			
		||||
        if (guild != null && command != null){
 | 
			
		||||
            DisappearingMessage.deleteMessageAfter(2000, message);
 | 
			
		||||
            if (command.equals("play") && args.length == 1){
 | 
			
		||||
                //Play or queue a song.
 | 
			
		||||
                this.bot.getMusicPlayer().loadToQueue(guild, args[0]);
 | 
			
		||||
            } else if (command.equals("skip") && args.length == 0){
 | 
			
		||||
                //Skip the current song.
 | 
			
		||||
                this.bot.getMusicPlayer().skipTrack(guild);
 | 
			
		||||
            } else if (command.equals("help")){
 | 
			
		||||
                this.sendHelpInfo(user);
 | 
			
		||||
                //Send a PM to the user with help info.
 | 
			
		||||
                this.sendHelpInfo(user);//TODO finish the help command and fill in with new descriptions each time.
 | 
			
		||||
            } else if (command.equals("queue") && args.length == 0){
 | 
			
		||||
                //Display the first few items of the queue.
 | 
			
		||||
                this.bot.getMusicPlayer().showQueueList(guild);
 | 
			
		||||
            } else if (command.equals("repeat")){
 | 
			
		||||
                this.bot.getMusicPlayer().toggleRepeat(guild);
 | 
			
		||||
                //Toggle repeat.
 | 
			
		||||
                //TODO implement repeat command.
 | 
			
		||||
            } else if (command.equals("clear")){
 | 
			
		||||
                //TODO clear command.
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,40 +0,0 @@
 | 
			
		|||
package handiebot.lavaplayer;
 | 
			
		||||
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Andrew Lalis
 | 
			
		||||
 */
 | 
			
		||||
public class AudioLoadResultHandler implements com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler {
 | 
			
		||||
 | 
			
		||||
    private TrackScheduler scheduler;
 | 
			
		||||
 | 
			
		||||
    public AudioLoadResultHandler(TrackScheduler scheduler){
 | 
			
		||||
        this.scheduler = scheduler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void trackLoaded(AudioTrack audioTrack) {
 | 
			
		||||
        System.out.println("Adding to queue "+ audioTrack.getInfo().title);
 | 
			
		||||
        scheduler.queue(audioTrack);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void playlistLoaded(AudioPlaylist audioPlaylist) {
 | 
			
		||||
        System.out.println("Adding playlist to queue.");
 | 
			
		||||
        audioPlaylist.getTracks().forEach(track -> this.scheduler.queue(track));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void noMatches() {
 | 
			
		||||
        System.out.println("No matches!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void loadFailed(FriendlyException e) {
 | 
			
		||||
        System.out.println("Load failed.");
 | 
			
		||||
        e.printStackTrace();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package handiebot.lavaplayer;
 | 
			
		|||
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
 | 
			
		||||
import sx.blah.discord.handle.obj.IGuild;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Andrew Lalis
 | 
			
		||||
| 
						 | 
				
			
			@ -13,9 +14,9 @@ public class GuildMusicManager {
 | 
			
		|||
 | 
			
		||||
    public final TrackScheduler scheduler;
 | 
			
		||||
 | 
			
		||||
    public GuildMusicManager(AudioPlayerManager manager){
 | 
			
		||||
    public GuildMusicManager(AudioPlayerManager manager, IGuild guild){
 | 
			
		||||
        this.player = manager.createPlayer();
 | 
			
		||||
        this.scheduler = new TrackScheduler(this.player);
 | 
			
		||||
        this.scheduler = new TrackScheduler(this.player, guild);
 | 
			
		||||
        this.player.addListener(this.scheduler);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,14 +8,17 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
 | 
			
		|||
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
 | 
			
		||||
import handiebot.command.CommandHandler;
 | 
			
		||||
import handiebot.utils.DisappearingMessage;
 | 
			
		||||
import sx.blah.discord.handle.obj.IChannel;
 | 
			
		||||
import sx.blah.discord.handle.obj.IGuild;
 | 
			
		||||
import sx.blah.discord.handle.obj.IMessage;
 | 
			
		||||
import sx.blah.discord.handle.obj.IVoiceChannel;
 | 
			
		||||
import sx.blah.discord.util.EmbedBuilder;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Andrew Lalis
 | 
			
		||||
| 
						 | 
				
			
			@ -24,37 +27,94 @@ import java.util.Map;
 | 
			
		|||
 */
 | 
			
		||||
public class MusicPlayer {
 | 
			
		||||
 | 
			
		||||
    private static String CHANNEL_NAME = "music";
 | 
			
		||||
    //Name for the message and voice channels dedicated to this bot.
 | 
			
		||||
    public static String CHANNEL_NAME = "HandieBotMusic";
 | 
			
		||||
 | 
			
		||||
    private final AudioPlayerManager playerManager;
 | 
			
		||||
    private final Map<Long, GuildMusicManager> musicManagers;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    Mappings of music managers, channels and voice channels for each guild.
 | 
			
		||||
     */
 | 
			
		||||
    private Map<IGuild, GuildMusicManager> musicManagers;
 | 
			
		||||
    private Map<IGuild, IChannel> chatChannels;
 | 
			
		||||
    private Map<IGuild, IVoiceChannel> voiceChannels;
 | 
			
		||||
 | 
			
		||||
    public MusicPlayer(){
 | 
			
		||||
        this.musicManagers = new HashMap<>();
 | 
			
		||||
        //Initialize player manager.
 | 
			
		||||
        this.playerManager = new DefaultAudioPlayerManager();
 | 
			
		||||
        AudioSourceManagers.registerLocalSource(playerManager);
 | 
			
		||||
        AudioSourceManagers.registerRemoteSources(playerManager);
 | 
			
		||||
 | 
			
		||||
        //Initialize all maps.
 | 
			
		||||
        this.musicManagers = new HashMap<>();
 | 
			
		||||
        this.chatChannels = new HashMap<>();
 | 
			
		||||
        this.voiceChannels = new HashMap<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggles the playlist's repeating.
 | 
			
		||||
     * @param guild The guild to perform the action on.
 | 
			
		||||
     * Gets the music manager specific to a particular guild.
 | 
			
		||||
     * @param guild The guild to get the music manager for.
 | 
			
		||||
     * @return The music manager for a guild.
 | 
			
		||||
     */
 | 
			
		||||
    public void toggleRepeat(IGuild guild){
 | 
			
		||||
        GuildMusicManager musicManager = this.getGuildMusicManager(guild);
 | 
			
		||||
        musicManager.scheduler.setRepeat(!musicManager.scheduler.isRepeating());
 | 
			
		||||
        this.getMessageChannel(guild).sendMessage("**Repeat** is now *"+(musicManager.scheduler.isRepeating() ? "On" : "Off")+"*.");
 | 
			
		||||
    private GuildMusicManager getMusicManager(IGuild guild){
 | 
			
		||||
        if (!this.musicManagers.containsKey(guild)){
 | 
			
		||||
            System.out.println("Registering guild, creating audio provider.");
 | 
			
		||||
            this.musicManagers.put(guild, new GuildMusicManager(this.playerManager, guild));
 | 
			
		||||
            guild.getAudioManager().setAudioProvider(this.musicManagers.get(guild).getAudioProvider());
 | 
			
		||||
        }
 | 
			
		||||
        return this.musicManagers.get(guild);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the chat channel specific to a particular guild. This channel is used send updates about playback and
 | 
			
		||||
     * responses to people's commands. If none exists, the bot will attempt to make a channel.
 | 
			
		||||
     * @param guild The guild to get the channel from.
 | 
			
		||||
     * @return A message channel on a particular guild that is specifically for music.
 | 
			
		||||
     */
 | 
			
		||||
    private IChannel getChatChannel(IGuild guild){
 | 
			
		||||
        if (!this.chatChannels.containsKey(guild)){
 | 
			
		||||
            List<IChannel> channels = guild.getChannelsByName(CHANNEL_NAME.toLowerCase());
 | 
			
		||||
            if (channels.isEmpty()){
 | 
			
		||||
                System.out.println("Found "+channels.size()+" matches for message channel, creating new one.");
 | 
			
		||||
                this.chatChannels.put(guild, guild.createChannel(CHANNEL_NAME.toLowerCase()));
 | 
			
		||||
            } else {
 | 
			
		||||
                this.chatChannels.put(guild, channels.get(0));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return this.chatChannels.get(guild);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the voice channel associated with a particular guild. This channel is used for audio playback. If none
 | 
			
		||||
     * exists, the bot will attempt to make a voice channel.
 | 
			
		||||
     * @param guild The guild to get the channel from.
 | 
			
		||||
     * @return The voice channel on a guild that is for this bot.
 | 
			
		||||
     */
 | 
			
		||||
    private IVoiceChannel getVoiceChannel(IGuild guild){
 | 
			
		||||
        if (!this.voiceChannels.containsKey(guild)){
 | 
			
		||||
            List<IVoiceChannel> channels = guild.getVoiceChannelsByName(CHANNEL_NAME);
 | 
			
		||||
            if (channels.isEmpty()){
 | 
			
		||||
                System.out.println("Found "+channels.size()+" matches for voice channel, creating new one.");
 | 
			
		||||
                this.voiceChannels.put(guild, guild.createVoiceChannel(CHANNEL_NAME));
 | 
			
		||||
            } else {
 | 
			
		||||
                this.voiceChannels.put(guild, channels.get(0));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        IVoiceChannel vc = this.voiceChannels.get(guild);
 | 
			
		||||
        if (!vc.isConnected()){
 | 
			
		||||
            System.out.println("Joined voice channel.");
 | 
			
		||||
            vc.join();
 | 
			
		||||
        }
 | 
			
		||||
        return vc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a formatted message to the guild about the first few items in a queue.
 | 
			
		||||
     * @param guild The guild to show the queue for.
 | 
			
		||||
     */
 | 
			
		||||
    public void showQueueList(IGuild guild){
 | 
			
		||||
        GuildMusicManager musicManager = this.getGuildMusicManager(guild);
 | 
			
		||||
        List<AudioTrack> tracks = musicManager.scheduler.queueList();
 | 
			
		||||
        List<AudioTrack> tracks = getMusicManager(guild).scheduler.queueList();
 | 
			
		||||
        if (tracks.size() == 0) {
 | 
			
		||||
            this.getMessageChannel(guild).sendMessage("The queue is empty. Use **"+ CommandHandler.PREFIX+"play** *URL* to add songs.");
 | 
			
		||||
            new DisappearingMessage(getChatChannel(guild), "The queue is empty. Use **"+ CommandHandler.PREFIX+"play** *URL* to add songs.", 3000);
 | 
			
		||||
        } else {
 | 
			
		||||
            EmbedBuilder builder = new EmbedBuilder();
 | 
			
		||||
            builder.withColor(255, 0, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -74,22 +134,22 @@ public class MusicPlayer {
 | 
			
		|||
                sb.append(seconds % 60);
 | 
			
		||||
                sb.append("]\n");
 | 
			
		||||
            }
 | 
			
		||||
            builder.appendField("Showing " + (tracks.size() <= 10 ? tracks.size() : "the first 10") + " tracks.", sb.toString(), false);
 | 
			
		||||
            this.getMessageChannel(guild).sendMessage(builder.build());
 | 
			
		||||
            builder.withTimestamp(System.currentTimeMillis());
 | 
			
		||||
            builder.appendField("Showing " + (tracks.size() <= 10 ? tracks.size() : "the first 10") + " track"+(tracks.size() > 1 ? "s" : "")+".", sb.toString(), false);
 | 
			
		||||
            getChatChannel(guild).sendMessage(builder.build());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a URL to the queue, or outputs an error message if it fails.
 | 
			
		||||
     * @param guild The guild to load the URL to.
 | 
			
		||||
     * @param trackURL A string representing a youtube/soundcloud URL.
 | 
			
		||||
     */
 | 
			
		||||
    public void loadToQueue(IGuild guild, String trackURL){
 | 
			
		||||
        GuildMusicManager musicManager = this.getGuildMusicManager(guild);
 | 
			
		||||
        this.playerManager.loadItemOrdered(musicManager, trackURL, new AudioLoadResultHandler() {
 | 
			
		||||
        this.playerManager.loadItemOrdered(getMusicManager(guild), trackURL, new AudioLoadResultHandler() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void trackLoaded(AudioTrack audioTrack) {
 | 
			
		||||
                addToQueue(guild, musicManager, audioTrack);
 | 
			
		||||
                System.out.println("Track successfully loaded: "+audioTrack.getInfo().title);
 | 
			
		||||
                addToQueue(guild, audioTrack);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -99,92 +159,59 @@ public class MusicPlayer {
 | 
			
		|||
                    if (firstTrack == null){
 | 
			
		||||
                        firstTrack = audioPlaylist.getTracks().get(0);
 | 
			
		||||
                    }
 | 
			
		||||
                    addToQueue(guild, musicManager,firstTrack);
 | 
			
		||||
                    addToQueue(guild, firstTrack);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void noMatches() {
 | 
			
		||||
                getMessageChannel(guild).sendMessage("Unable to find a result for: "+trackURL);
 | 
			
		||||
                new DisappearingMessage(getChatChannel(guild), "Unable to find a result for: "+trackURL, 3000);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void loadFailed(FriendlyException e) {
 | 
			
		||||
                getMessageChannel(guild).sendMessage("Unable to load. "+e.getMessage());
 | 
			
		||||
                new DisappearingMessage(getChatChannel(guild), "Unable to load. "+e.getMessage(), 3000);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a track to the queue and sends a message to the appropriate channel notifying users.
 | 
			
		||||
     * @param guild The guild to queue the track in.
 | 
			
		||||
     * @param musicManager The music manager to use.
 | 
			
		||||
     * @param track The track to queue.
 | 
			
		||||
     */
 | 
			
		||||
    public void addToQueue(IGuild guild, GuildMusicManager musicManager, AudioTrack track){
 | 
			
		||||
        IVoiceChannel voiceChannel = this.connectToMusicChannel(guild);
 | 
			
		||||
    public void addToQueue(IGuild guild, AudioTrack track){
 | 
			
		||||
        IVoiceChannel voiceChannel = getVoiceChannel(guild);
 | 
			
		||||
        if (voiceChannel != null){
 | 
			
		||||
            musicManager.scheduler.queue(track);
 | 
			
		||||
            IChannel channel = this.getMessageChannel(guild);
 | 
			
		||||
            channel.sendMessage("Added **"+track.getInfo().title+"** to the queue.");
 | 
			
		||||
            //Check to make sure sound can be played.
 | 
			
		||||
            if (guild.getAudioManager().getAudioProvider() == null){
 | 
			
		||||
                new DisappearingMessage(getChatChannel(guild), "Audio provider not set. Please try again.", 3000);
 | 
			
		||||
                guild.getAudioManager().setAudioProvider(getMusicManager(guild).getAudioProvider());
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            long timeUntilPlay = getMusicManager(guild).scheduler.getTimeUntilDone();
 | 
			
		||||
            getMusicManager(guild).scheduler.queue(track);
 | 
			
		||||
            //Build message.
 | 
			
		||||
            StringBuilder sb = new StringBuilder();
 | 
			
		||||
            sb.append("Added **").append(track.getInfo().title).append("** to the queue.");
 | 
			
		||||
            //If there's some tracks in the queue, get the time until this one plays.
 | 
			
		||||
            if (timeUntilPlay != 0){
 | 
			
		||||
                sb.append(String.format("\nTime until play: %d min, %d sec",
 | 
			
		||||
                        TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay),
 | 
			
		||||
                        TimeUnit.MILLISECONDS.toSeconds(timeUntilPlay) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay))
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
            IMessage message = getChatChannel(guild).sendMessage(sb.toString());
 | 
			
		||||
            DisappearingMessage.deleteMessageAfter(3000, message);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Skips the current track.
 | 
			
		||||
     * @param guild The guild to perform the skip on.
 | 
			
		||||
     */
 | 
			
		||||
    public void skipTrack(IGuild guild){
 | 
			
		||||
        this.getGuildMusicManager(guild).scheduler.nextTrack();
 | 
			
		||||
        this.getMessageChannel(guild).sendMessage("Skipping the current track.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets or creates a music manager for a specific guild.
 | 
			
		||||
     * @param guild The guild to get a manager for.
 | 
			
		||||
     * @return A Music Manager for the guild.
 | 
			
		||||
     */
 | 
			
		||||
    private synchronized GuildMusicManager getGuildMusicManager(IGuild guild){
 | 
			
		||||
        long guildId = Long.parseLong(guild.getStringID());
 | 
			
		||||
        GuildMusicManager musicManager = this.musicManagers.get(guildId);
 | 
			
		||||
        if (musicManager == null){
 | 
			
		||||
            musicManager = new GuildMusicManager(this.playerManager);
 | 
			
		||||
            musicManagers.put(guildId, musicManager);
 | 
			
		||||
        }
 | 
			
		||||
        guild.getAudioManager().setAudioProvider(musicManager.getAudioProvider());
 | 
			
		||||
        return musicManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Searches for and attempts to connect to a channel called 'music'.
 | 
			
		||||
     * @param guild the guild to get voice channels from.
 | 
			
		||||
     * @return The voice channel the bot is now connected to.
 | 
			
		||||
     */
 | 
			
		||||
    private IVoiceChannel connectToMusicChannel(IGuild guild){
 | 
			
		||||
        List<IVoiceChannel> voiceChannels = guild.getVoiceChannelsByName(CHANNEL_NAME);
 | 
			
		||||
        if (voiceChannels.size() == 1){
 | 
			
		||||
            if (!voiceChannels.get(0).isConnected())
 | 
			
		||||
                voiceChannels.get(0).join();
 | 
			
		||||
            return voiceChannels.get(0);
 | 
			
		||||
        }
 | 
			
		||||
        IVoiceChannel voiceChannel = guild.createVoiceChannel(CHANNEL_NAME);
 | 
			
		||||
        voiceChannel.join();
 | 
			
		||||
        return voiceChannel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a 'music' message channel where the bot can post info on playing songs, user requests,
 | 
			
		||||
     * etc.
 | 
			
		||||
     * @param guild The guild to get channels from.
 | 
			
		||||
     * @return The channel with that name.
 | 
			
		||||
     */
 | 
			
		||||
    private IChannel getMessageChannel(IGuild guild){
 | 
			
		||||
        List<IChannel> channels = guild.getChannelsByName(CHANNEL_NAME);
 | 
			
		||||
        if (channels.size() == 1){
 | 
			
		||||
            return channels.get(0);
 | 
			
		||||
        }
 | 
			
		||||
        return guild.createChannel(CHANNEL_NAME);
 | 
			
		||||
        getMusicManager(guild).scheduler.nextTrack();
 | 
			
		||||
        new DisappearingMessage(getChatChannel(guild), "Skipping the current track.", 3000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
 | 
			
		|||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
 | 
			
		||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
 | 
			
		||||
import sx.blah.discord.handle.obj.IChannel;
 | 
			
		||||
import sx.blah.discord.handle.obj.IGuild;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,15 +20,18 @@ public class TrackScheduler extends AudioEventAdapter {
 | 
			
		|||
 | 
			
		||||
    private final AudioPlayer player;
 | 
			
		||||
    private final BlockingQueue<AudioTrack> queue;
 | 
			
		||||
 | 
			
		||||
    private boolean repeat = false;
 | 
			
		||||
    private AudioTrack currentTrack = null;
 | 
			
		||||
 | 
			
		||||
    private IGuild guild;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new track scheduler with the given player.
 | 
			
		||||
     * @param player The audio player this scheduler uses.
 | 
			
		||||
     */
 | 
			
		||||
    public TrackScheduler(AudioPlayer player){
 | 
			
		||||
    public TrackScheduler(AudioPlayer player, IGuild guild){
 | 
			
		||||
        this.player = player;
 | 
			
		||||
        this.guild = guild;
 | 
			
		||||
        this.queue = new LinkedBlockingQueue<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -46,13 +51,38 @@ public class TrackScheduler extends AudioEventAdapter {
 | 
			
		|||
        return this.repeat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the time until the bot is done playing sound, at the current rate.
 | 
			
		||||
     * @return The milliseconds until music stops.
 | 
			
		||||
     */
 | 
			
		||||
    public long getTimeUntilDone(){
 | 
			
		||||
        long t = 0;
 | 
			
		||||
        AudioTrack currentTrack = this.player.getPlayingTrack();
 | 
			
		||||
        if (currentTrack != null){
 | 
			
		||||
            t += currentTrack.getDuration() - currentTrack.getPosition();
 | 
			
		||||
        }
 | 
			
		||||
        for (AudioTrack track : this.queueList()){
 | 
			
		||||
            t += track.getDuration();
 | 
			
		||||
        }
 | 
			
		||||
        return t;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a list of tracks in the queue.
 | 
			
		||||
     * @return A list of tracks in the queue.
 | 
			
		||||
     */
 | 
			
		||||
    public List<AudioTrack> queueList(){
 | 
			
		||||
        return new ArrayList<>(this.queue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add the next track to the queue or play right away if nothing is in the queue.
 | 
			
		||||
     * @param track The track to play or add to the queue.
 | 
			
		||||
     */
 | 
			
		||||
    public void queue(AudioTrack track){
 | 
			
		||||
        if (!player.startTrack(track, true)){
 | 
			
		||||
            System.out.println("Unable to start track immediately, adding to queue.");
 | 
			
		||||
        if (player.getPlayingTrack() == null){
 | 
			
		||||
            player.startTrack(track, false);
 | 
			
		||||
        } else {
 | 
			
		||||
            queue.offer(track);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -63,28 +93,28 @@ public class TrackScheduler extends AudioEventAdapter {
 | 
			
		|||
    public void nextTrack(){
 | 
			
		||||
        AudioTrack track = queue.poll();
 | 
			
		||||
        player.startTrack(track, false);
 | 
			
		||||
        this.currentTrack = track;
 | 
			
		||||
        if (this.repeat){
 | 
			
		||||
            this.queue.add(track);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
 | 
			
		||||
        if (endReason.mayStartNext){
 | 
			
		||||
            nextTrack();
 | 
			
		||||
        } else {
 | 
			
		||||
            this.currentTrack = null;
 | 
			
		||||
            System.out.println(endReason.toString());
 | 
			
		||||
    public void onTrackStart(AudioPlayer player, AudioTrack track) {
 | 
			
		||||
        System.out.println("Started audio track: "+track.getInfo().title);
 | 
			
		||||
        List<IChannel> channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase());
 | 
			
		||||
        if (channels.size() > 0){
 | 
			
		||||
            channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"**.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a list of tracks in the queue.
 | 
			
		||||
     * @return A list of tracks in the queue.
 | 
			
		||||
     */
 | 
			
		||||
    public List<AudioTrack> queueList(){
 | 
			
		||||
        return new ArrayList<>(this.queue);
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
 | 
			
		||||
        System.out.println("Track ended.");
 | 
			
		||||
        if (endReason.mayStartNext){
 | 
			
		||||
            nextTrack();
 | 
			
		||||
        } else {
 | 
			
		||||
            System.out.println(endReason.toString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -96,4 +126,5 @@ public class TrackScheduler extends AudioEventAdapter {
 | 
			
		|||
    public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) {
 | 
			
		||||
        super.onTrackStuck(player, track, thresholdMs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
package handiebot.utils;
 | 
			
		||||
 | 
			
		||||
import sx.blah.discord.handle.obj.IChannel;
 | 
			
		||||
import sx.blah.discord.handle.obj.IMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Andrew Lalis
 | 
			
		||||
 * Creates a message on a channel that will disappear after some time.
 | 
			
		||||
 */
 | 
			
		||||
public class DisappearingMessage extends Thread implements Runnable {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new disappearing message that times out after some time.
 | 
			
		||||
     * @param channel The channel to write the message in.
 | 
			
		||||
     * @param message The message content.
 | 
			
		||||
     * @param timeout How long until the message is deleted.
 | 
			
		||||
     */
 | 
			
		||||
    public DisappearingMessage(IChannel channel, String message, long timeout){
 | 
			
		||||
        IMessage sentMessage = channel.sendMessage(message);
 | 
			
		||||
        try {
 | 
			
		||||
            sleep(timeout);
 | 
			
		||||
        } catch (InterruptedException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        sentMessage.delete();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deletes a message after a set amount of time.
 | 
			
		||||
     * @param timeout The delay until deletion, in milliseconds.
 | 
			
		||||
     * @param message The message to delete.
 | 
			
		||||
     */
 | 
			
		||||
    public static void deleteMessageAfter(long timeout, IMessage message){
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                sleep(timeout);
 | 
			
		||||
                message.delete();
 | 
			
		||||
            } catch (InterruptedException e){
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue