diff --git a/.classpath b/.classpath index e5e8a9b..6cf8f5a 100644 --- a/.classpath +++ b/.classpath @@ -24,7 +24,8 @@ + - + diff --git a/assets/config.csv b/assets/config.csv index 2564dd9..88103ad 100644 --- a/assets/config.csv +++ b/assets/config.csv @@ -19,6 +19,7 @@ "Localized Commands","e621","" "Localized Commands","eightball, 8ball","" "Localized Commands","fetch","" +"Localized Commands","getsauce","" "Localized Commands","givebeans","" "Localized Commands","help","" "Localized Commands","indicator","" @@ -60,6 +61,7 @@ "Localized Strings","BetBeansInfo","Allows you to bet your beans, set your amount after the command! Warning! House always wins!nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x" "Localized Strings","BetBeansLose","Sorry, you didn't win, try again!" "Localized Strings","BetBeansLowBet","Please bet with at least 20 beans!" +"Localized Strings","BetBeansMinThreshold","" "Localized Strings","BetBeansNotEnough","You don't have enough beans!" "Localized Strings","BetBeansNotValid","That's not a valid bet!" "Localized Strings","BetBeansWin","You won %s beans!" @@ -139,6 +141,7 @@ "Localized Strings","FetchInfo","Throw a custom emote and I'll try to bring it back.... maybe" "Localized Strings","FetchRunAway","*Runs away and doesn't return for a long time*" "Localized Strings","FetchStare","*Stares at %s*" +"Localized Strings","GetSauceInfo","" "Localized Strings","GiveBeansInfo","Gives beans to the mentioned users!" "Localized Strings","GiveBeansInvalid","That's not a valid number!" "Localized Strings","GiveBeansNoneMentioned","You didn't mention anyone!" @@ -270,6 +273,7 @@ "Command Enabler","e621","1" "Command Enabler","eightball, 8ball","1" "Command Enabler","fetch","1" +"Command Enabler","getsauce","1" "Command Enabler","givebeans","1" "Command Enabler","guildroleadd","1" "Command Enabler","guildroleallowed","1" diff --git a/lib/LavaPlayerJar-0.0.1-jar-with-dependencies.jar b/lib/LavaPlayerJar-0.0.1-jar-with-dependencies.jar new file mode 100644 index 0000000..3a4e0ea Binary files /dev/null and b/lib/LavaPlayerJar-0.0.1-jar-with-dependencies.jar differ diff --git a/lib/google-http-client-1.32.0.jar b/lib/google-http-client-1.32.0.jar new file mode 100644 index 0000000..b97d4d4 Binary files /dev/null and b/lib/google-http-client-1.32.0.jar differ diff --git a/lib/lavaplayer-1.3.19.jar b/lib/lavaplayer-1.3.19.jar deleted file mode 100644 index 472c468..0000000 Binary files a/lib/lavaplayer-1.3.19.jar and /dev/null differ diff --git a/src/commands/general/CommandGetSauce.java b/src/commands/general/CommandGetSauce.java new file mode 100644 index 0000000..be59ec8 --- /dev/null +++ b/src/commands/general/CommandGetSauce.java @@ -0,0 +1,29 @@ +package commands.general; + +import core.Command; +import core.LocStrings; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; +import network.NetworkSauceNAO; + +public class CommandGetSauce extends Command +{ + NetworkSauceNAO sauce = new NetworkSauceNAO(); + + public CommandGetSauce(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String getHelpText() { return LocStrings.stub("GetSauceInfo"); }; + + @Override + public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + res.send(sauce.getSauce(input.args)); + + } +} \ No newline at end of file diff --git a/src/commands/music/CommandMusicMain.java b/src/commands/music/CommandMusicMain.java index 181fb21..6581271 100644 --- a/src/commands/music/CommandMusicMain.java +++ b/src/commands/music/CommandMusicMain.java @@ -2,6 +2,7 @@ package commands.music; import core.Command; import core.LocStrings; +import core.SubCommandFormattable; import core.SubCommandFramework; import dataStructures.*; @@ -9,18 +10,24 @@ public class CommandMusicMain extends Command { SubCommandFramework framework = new SubCommandFramework(); public CommandMusicMain(KittyRole level, KittyRating rating) - { + { super(level, rating); framework.addCommand("join", new SubCommandJoin(KittyRole.General, KittyRating.Safe)); framework.addCommand("leave", new SubCommandLeave(KittyRole.General, KittyRating.Safe)); + framework.addCommand("add", new SubCommandAddTrack(KittyRole.General, KittyRating.Safe)); + framework.addCommand("skip", new SubCommandSkip(KittyRole.General, KittyRating.Safe)); + framework.addCommand("stop", new SubCommandStop(KittyRole.General, KittyRating.Safe)); + framework.addCommand("playlist", new SubCommandPlaylist(KittyRole.General, KittyRating.Safe)); } @Override - public String getHelpText() { return LocStrings.stub("MusicInfo"); } + public String getHelpText() {return LocStrings.stub("MusicInfo"); } @Override public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - framework.run(guild, channel, user, input).Call(res); + SubCommandFormattable scf = framework.run(guild, channel, user, input); + System.out.println("SCF: " + scf.resString); + scf.Call(res); } } \ No newline at end of file diff --git a/src/commands/music/SubCommandAddTrack.java b/src/commands/music/SubCommandAddTrack.java index 1c19498..39febae 100644 --- a/src/commands/music/SubCommandAddTrack.java +++ b/src/commands/music/SubCommandAddTrack.java @@ -1,7 +1,5 @@ package commands.music; -import com.google.api.services.youtube.YouTube; - import core.SubCommand; import core.SubCommandFormattable; import dataStructures.KittyChannel; @@ -10,16 +8,25 @@ import dataStructures.KittyRating; import dataStructures.KittyRole; import dataStructures.KittyUser; import dataStructures.UserInput; +import network.NetworkYoutube; public class SubCommandAddTrack extends SubCommand { public SubCommandAddTrack(KittyRole level, KittyRating rating) { super(level, rating); } + NetworkYoutube YT = new NetworkYoutube(); + @Override public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) { - - return null; + //Get track from Youtube + String video = input.args; + if(!(video.startsWith("https://www.youtube") || video.startsWith("https://www.youtu.be"))) + { + video = YT.getYT(video); + } + guild.audio.playVideo(video); + return new SubCommandFormattable(video); } } \ No newline at end of file diff --git a/src/commands/music/SubCommandPlaylist.java b/src/commands/music/SubCommandPlaylist.java new file mode 100644 index 0000000..ec81859 --- /dev/null +++ b/src/commands/music/SubCommandPlaylist.java @@ -0,0 +1,38 @@ +package commands.music; + +import java.util.ArrayList; + +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; + +import core.SubCommand; +import core.SubCommandFormattable; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.UserInput; + +public class SubCommandPlaylist extends SubCommand +{ + + public SubCommandPlaylist(KittyRole roleLevel, KittyRating contentRating) {super(roleLevel, contentRating); } + + @Override + public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) + { + ArrayList playlist = guild.audio.getPlaylist(); + String stringPlaylist = ""; + + for(AudioTrack track : playlist) + { + stringPlaylist += (playlist.indexOf(track) + 1) + ": " + track.getInfo().title + "\n"; + } + if(stringPlaylist.equals("")) + { + return new SubCommandFormattable("Nothing Queued!"); + } + return new SubCommandFormattable(stringPlaylist); + } + +} diff --git a/src/commands/music/SubCommandSkip.java b/src/commands/music/SubCommandSkip.java new file mode 100644 index 0000000..b57ee52 --- /dev/null +++ b/src/commands/music/SubCommandSkip.java @@ -0,0 +1,23 @@ +package commands.music; + +import core.SubCommand; +import core.SubCommandFormattable; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.UserInput; + +public class SubCommandSkip extends SubCommand +{ + public SubCommandSkip(KittyRole level, KittyRating rating) { super(level, rating); } + { + + } + @Override + public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) + { + return new SubCommandFormattable(guild.audio.skipVideo(guild.audio.player)); + } +} diff --git a/src/commands/music/SubCommandStop.java b/src/commands/music/SubCommandStop.java new file mode 100644 index 0000000..2aacffd --- /dev/null +++ b/src/commands/music/SubCommandStop.java @@ -0,0 +1,24 @@ +package commands.music; + +import core.SubCommand; +import core.SubCommandFormattable; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.UserInput; + +public class SubCommandStop extends SubCommand +{ + + public SubCommandStop(KittyRole roleLevel, KittyRating contentRating) {super(roleLevel, contentRating);} + + @Override + public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) + { + + return new SubCommandFormattable(guild.audio.stopPlayer(guild.audio.player)); + } + +} diff --git a/src/core/CommandManager.java b/src/core/CommandManager.java index ec831ee..e4714f8 100644 --- a/src/core/CommandManager.java +++ b/src/core/CommandManager.java @@ -106,7 +106,6 @@ public class CommandManager this.register(LocCommands.stub("raffle"), new CommandRaffleMain(KittyRole.General, KittyRating.Safe)); this.register(LocCommands.stub("poll"), new CommandPollMain(KittyRole.General, KittyRating.Safe)); this.register(LocCommands.stub("music"), new CommandMusicMain(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("defaultdance"), new CommandDefaultDance(KittyRole.General, KittyRating.Safe)); } // Allows the command manager to keep track of a command. Takes a pair (the un-localized and localzied commands) diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index fb93eff..fd5d592 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -7,22 +7,36 @@ import java.util.concurrent.Semaphore; import javax.security.auth.login.LoginException; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; + //import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; //import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import core.lua.PluginManager; -import dataStructures.*; +import dataStructures.KittyChannel; +import dataStructures.KittyCore; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; import main.Main; import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; -import net.dv8tion.jda.core.entities.*; +import net.dv8tion.jda.core.entities.Emote; +import net.dv8tion.jda.core.entities.Game; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.User; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import offline.Ref; import utils.AdminControl; //import utils.AudioUtils; import utils.GlobalLog; import utils.LogFilter; +import utils.audio.AudioUtils; // NOTE(wisp): Isolated factory to assist with storage and caching if needed. // This also minimizes the number of places JDA interacts with our codebase. @@ -55,7 +69,7 @@ public class ObjectBuilderFactory private static CommandManager commandManager; //Audio track manager -// private static AudioPlayerManager audioPlayer = new DefaultAudioPlayerManager(); + private static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); // Localization classes - these are singletons, but should be initialized before almost all other // things so their inclusion in the factory is to ensure they're started at the correct time. @@ -90,6 +104,9 @@ public class ObjectBuilderFactory database = null; stats = null; + AudioSourceManagers.registerRemoteSources(playerManager); + AudioSourceManagers.registerLocalSource(playerManager); + // Start by reading from things that are external. Because // we require these things to be resolved before the rest of the application, // we place them here. @@ -147,7 +164,7 @@ public class ObjectBuilderFactory else { // Construct a new guild with defaults - guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString); + guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString, new AudioUtils(event.getGuild(), playerManager)); DatabaseManager.instance.globalRegister(guild); guildCache.put(uid, guild); } @@ -365,7 +382,8 @@ public class ObjectBuilderFactory { lazyInit(); - kitty = new JDABuilder(AccountType.BOT).setToken(Ref.TestToken).buildBlocking(); + kitty = new JDABuilder(AccountType.BOT) + .setToken(Ref.TestToken).buildBlocking(); kitty.getPresence().setGame(Game.playing("with digital yarn")); kitty.addEventListener(new Main()); diff --git a/src/dataStructures/KittyGuild.java b/src/dataStructures/KittyGuild.java index 7801f79..ceb056d 100644 --- a/src/dataStructures/KittyGuild.java +++ b/src/dataStructures/KittyGuild.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import core.DatabaseManager; import core.DatabaseTrackedObject; import utils.AdminControl; -import utils.AudioUtils; +import utils.audio.AudioUtils; // Context for a given guild for kittybot. Primarily designed to hold guild-specific settings. public class KittyGuild extends DatabaseTrackedObject @@ -22,7 +22,7 @@ public class KittyGuild extends DatabaseTrackedObject public ArrayList emoji = new ArrayList(); public ArrayList choices = new ArrayList(); public AdminControl control; - public AudioUtils audio; + public AudioUtils audio; public ArrayList raffleUsersUnchosen = new ArrayList(); public ArrayList raffleUsersChosen = new ArrayList(); @@ -42,8 +42,9 @@ public class KittyGuild extends DatabaseTrackedObject } // Default content for a guild - public KittyGuild(String uniqueID, AdminControl adminControl, ArrayList emoji) + public KittyGuild(String uniqueID, AdminControl adminControl, ArrayList emoji, AudioUtils audio) { + super(uniqueID); this.uniqueID = uniqueID; roleList = new KittyTrackedVector(roleListName, uniqueID); @@ -54,11 +55,12 @@ public class KittyGuild extends DatabaseTrackedObject this.contentRating = KittyRating.Safe; this.polling = false; this.emoji = emoji; + this.audio = audio; setCommandIndicator("!"); } // Explicit constructor - public KittyGuild(String commandIndicator, KittyRating contentRating, KittyUser guildOwner, String uniqueID) + public KittyGuild(String commandIndicator, KittyRating contentRating, KittyUser guildOwner, String uniqueID, AudioUtils audio) { super(uniqueID); this.uniqueID = uniqueID; @@ -70,6 +72,7 @@ public class KittyGuild extends DatabaseTrackedObject this.contentRating = contentRating; this.polling = false; this.guildOwner = guildOwner; + this.audio = audio; } public String startPoll(String poll) diff --git a/src/main/Main.java b/src/main/Main.java index 06b562b..23e3b7d 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -1,9 +1,21 @@ package main; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.security.auth.login.LoginException; +import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; + import core.CharacterManager; import core.CommandEnabler; import core.CommandManager; @@ -21,9 +33,13 @@ import dataStructures.UserInput; import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; -import net.dv8tion.jda.core.entities.Game; +import net.dv8tion.jda.core.audio.AudioSendHandler; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.entities.VoiceChannel; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.core.hooks.ListenerAdapter; +import net.dv8tion.jda.core.managers.AudioManager; import offline.Ref; import utils.GlobalLog; @@ -42,6 +58,7 @@ public class Main extends ListenerAdapter private static PluginManager pluginManager; private static CharacterManager charManager; + // Initialization and setup public static void main(String[] args) throws InterruptedException, LoginException, Exception { diff --git a/src/network/NetworkSauceNAO.java b/src/network/NetworkSauceNAO.java new file mode 100644 index 0000000..93c030f --- /dev/null +++ b/src/network/NetworkSauceNAO.java @@ -0,0 +1,48 @@ +package network; + +import java.util.List; + +import com.google.gson.Gson; + +import offline.Ref; +import utils.HTTPUtils; + +public class NetworkSauceNAO +{ + private static final Gson jsonParser_ = new Gson(); + private static final String API_ROOT = "https://saucenao.com/search.php?db=999&output_type=2&numres=10&api_key=" + Ref.SauceNAOKey +"&url="; + NetworkE621 e621Sauce = new NetworkE621(); + private class SauceNAOResponseObject + { + List results; + } + + private class SauceNAOResult + { + SauceNAOData data; + } + + private class SauceNAOData + { + String [] ext_urls; + } + + public String getSauce(String input) + { + input = input.trim(); + input = input.replace("+", "%2B"); + input = input.replace(" ", "%20"); + + String res = HTTPUtils.sendGETRequest(API_ROOT + input); + + SauceNAOResponseObject sauce = jsonParser_.fromJson(res, SauceNAOResponseObject.class); + String sauceUrl = sauce.results.get(0).data.ext_urls[0]; + if(sauceUrl.startsWith("https://e621.net/post/show/")) + { + System.out.println("id:" + sauceUrl.substring(26)); + return e621Sauce.getE621("id:" + sauceUrl.substring(27)).toString(); + } + return sauce.results.get(0).data.ext_urls[0]; + } + +} diff --git a/src/network/NetworkYoutube.java b/src/network/NetworkYoutube.java index d2ee0b6..8bb0f76 100644 --- a/src/network/NetworkYoutube.java +++ b/src/network/NetworkYoutube.java @@ -1,14 +1,55 @@ package network; -import com.google.api.services.youtube.YouTube; +import java.util.List; + +import com.google.gson.Gson; import offline.Ref; +import utils.HTTPUtils; public class NetworkYoutube { - private static YouTube youtube; + /////////////////////////////////////// + // Internal JSON class and variables // + //////////////////////////////////.//// - public NetworkYoutube() + //https://www.youtube.com/watch?v= + + private static final Gson jsonParser_ = new Gson(); + private static final String API_ROOT = "https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=10&q="; + + + // Use this as the base + public class YTOuter { + List items; } -} \ No newline at end of file + + public class YTInner + { + TYID id; + YTSnippet snippet; + } + + public class TYID + { + String videoId; + } + + public class YTSnippet + { + String title; + String description; + } + + public String getYT(String input) + { + input = input.trim(); + input = input.replace("+", "%2B"); + input = input.replace(" ", "%20"); + + String res = HTTPUtils.sendGETRequest(API_ROOT + input + "&order=viewCount&type=video&topicId=%2Fm%2F04rlf&videoDefinition=high&key=" + Ref.youtube); + YTOuter videoObj = jsonParser_.fromJson(res, YTOuter.class); + return "https://www.youtube.com/watch?v=" + videoObj.items.get(0).id.videoId; + } +} diff --git a/src/utils/AudioUtils.java b/src/utils/AudioUtils.java deleted file mode 100644 index 79c1529..0000000 --- a/src/utils/AudioUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -package utils; -/*** - * https://developers.google.com/youtube/v3/code_samples/code_snippets?apix_params=%7B%22part%22%3A%22snippet%22%2C%22maxResults%22%3A25%2C%22q%22%3A%22surfing%22%7D - * https://github.com/sedmelluq/LavaPlayer#jda-integration - * https://ci.dv8tion.net/job/JDA/javadoc/net/dv8tion/jda/core/entities/VoiceChannel.html - * https://developers.google.com/youtube/registering_an_application#Create_API_Keys - */ -import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; - -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.managers.AudioManager; - -public class AudioUtils -{ - private Guild guild; - AudioManager audio; - AudioPlayer player; - - - public AudioUtils(Guild guild) - { - this.guild = guild; - audio = guild.getAudioManager(); - } - - public boolean joinChannel(String channelName) - { - VoiceChannel channel = null; - channel = guild.getVoiceChannelsByName(channelName, true).get(0); - if(channel != null) - { - audio.openAudioConnection(channel); - return true; - } - return false; - } - - public boolean leaveChannel() - { - if(audio.isConnected()) - { - audio.closeAudioConnection(); - return true; - } - return false; - } -} diff --git a/src/utils/audio/AudioUtils.java b/src/utils/audio/AudioUtils.java new file mode 100644 index 0000000..fa99919 --- /dev/null +++ b/src/utils/audio/AudioUtils.java @@ -0,0 +1,164 @@ +package utils.audio; +import java.util.ArrayList; + +import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; + +import net.dv8tion.jda.core.audio.AudioSendHandler; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.VoiceChannel; +import net.dv8tion.jda.core.managers.AudioManager; + +public class AudioUtils +{ + private Guild guild; + public AudioManager am; + public final AudioPlayer player; + public final AudioPlayerManager playerManager; + private boolean isPlaying = false; + private ArrayList playlist = new ArrayList(); + + + public AudioUtils(Guild guild, AudioPlayerManager playerManager) + { + player = playerManager.createPlayer(); + this.playerManager = playerManager; + this.guild = guild; + am = guild.getAudioManager(); + + } + + public boolean joinChannel(String channelName) + { + VoiceChannel channel = null; + channel = guild.getVoiceChannelsByName(channelName, true).get(0); + if(channel != null) + { + am.openAudioConnection(channel); + return true; + } + return false; + } + + public boolean leaveChannel() + { + if(am.isConnected()) + { + am.closeAudioConnection(); + return true; + } + return false; + } + + + public class AudioPlayerSendHandler implements AudioSendHandler + { + private final AudioPlayer audioPlayer; + private AudioFrame lastFrame; + + public AudioPlayerSendHandler(AudioPlayer audioPlayer) + { + this.audioPlayer = audioPlayer; + } + + @Override + public boolean canProvide() + { + lastFrame = audioPlayer.provide(); + return lastFrame != null; + } + + @Override public byte[] provide20MsAudio() + { + return lastFrame.getData(); + } + + @Override public boolean isOpus() + { + return true; + } + } + + public class SmallAudio implements AudioLoadResultHandler + { + private AudioPlayer player; + + private SmallAudio(AudioPlayer player) + { + this.player = player; + } + + @Override public void loadFailed(FriendlyException arg0) { } + @Override public void noMatches() { } + @Override public void playlistLoaded(AudioPlaylist arg0) { } + + @Override + public void trackLoaded(AudioTrack track) + { + synchronized(playlist) + { + playlist.add(track); + } + if(!isPlaying) + { + isPlaying = true; + startPlay(player); + } + } + } + + + public String playVideo(String videoURL) + { + guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); + playerManager.loadItemOrdered(player, videoURL, new SmallAudio(player)); + + return null; + } + + private void startPlay(AudioPlayer player) + { + do + { + if(player.getPlayingTrack() == null) + { + player.startTrack(playlist.get(0), false); + if(!playlist.isEmpty()) + playlist.remove(0); + } + } + while(!playlist.isEmpty()); + isPlaying = false; + } + + public String skipVideo(AudioPlayer player) + { + player.stopTrack(); + try + { + playlist.remove(0); + } + catch(Exception e) + { + return "Stopped"; + } + return "Skipped"; + } + + public String stopPlayer(AudioPlayer player) + { + playlist.clear(); + player.stopTrack(); + return "Stopped"; + } + + public ArrayList getPlaylist() + { + return playlist; + } +}