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..437a63e 100644 --- a/assets/config.csv +++ b/assets/config.csv @@ -1,4 +1,5 @@ "Type","Key","Value" +"Globals","mode (dev or release)","dev" "Localized Commands","beans","" "Localized Commands","benchmark, bench","" "Localized Commands","bet","" @@ -19,6 +20,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 +62,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 +142,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 +274,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..4ab8c88 --- /dev/null +++ b/src/commands/music/SubCommandPlaylist.java @@ -0,0 +1,24 @@ +package commands.music; + +import java.util.ArrayList; + +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; + +import core.SubCommand; +import core.SubCommandFormattable; +import dataStructures.*; + +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 = guild.audio.getPlaylist(guild.audio.player); + 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..0dcc14d 100644 --- a/src/core/CommandManager.java +++ b/src/core/CommandManager.java @@ -106,7 +106,7 @@ 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)); + this.register(LocCommands.stub("getsauce"), new CommandGetSauce(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/Config.java b/src/core/Config.java index c76c9c2..96b29bc 100644 --- a/src/core/Config.java +++ b/src/core/Config.java @@ -28,6 +28,7 @@ public class Config sections = new Vector(); // Add all sections + sections.add(new ConfigGlobals()); sections.add(new LocCommands()); sections.add(new LocStrings()); sections.add(new CommandEnabler()); diff --git a/src/core/ConfigGlobals.java b/src/core/ConfigGlobals.java new file mode 100644 index 0000000..d6b5db9 --- /dev/null +++ b/src/core/ConfigGlobals.java @@ -0,0 +1,68 @@ +package core; + +import java.util.ArrayList; +import java.util.List; + +import dataStructures.KittyStartupMode; +import utils.GlobalLog; + +// Want to add a single item to the config file? This is where that lives. +public class ConfigGlobals implements IConfigSection +{ + // Defined const variables + public static final String header = "Globals"; + public static ConfigGlobals instance; + + + // A pile of variables being manually tracked/serialized to the config file + private static final String startupStyleKey = "mode (dev or release)"; + private KittyStartupMode startupStyleValue = KittyStartupMode.Dev; + + // Constructor + public ConfigGlobals() + { + if(instance == null) + instance = this; + else + GlobalLog.error("Attempted to initialize a second config globals! Probably don't do this!"); + } + + @Override + public String getSectionTitle() + { + return header; + } + + public static KittyStartupMode getStartupMode() + { + return instance.startupStyleValue; + } + + @Override + public void consume(List pairs) + { + for(int i = 0; i < pairs.size(); ++i) + { + String key = pairs.get(i).key; + String value = pairs.get(i).value; + + // Parse startup style + if(key.equalsIgnoreCase(startupStyleKey)) + { + startupStyleValue = KittyStartupMode.Dev; + + if(value.equalsIgnoreCase(KittyStartupMode.Release.name())) + startupStyleValue = KittyStartupMode.Release; + } + } + } + + @Override + public List produce() + { + List items = new ArrayList(); + items.add(new ConfigItem(getSectionTitle(), startupStyleKey, startupStyleValue.name().toLowerCase())); + + return items; + } +} diff --git a/src/core/ConfigItem.java b/src/core/ConfigItem.java index 7f556d2..75e8bad 100644 --- a/src/core/ConfigItem.java +++ b/src/core/ConfigItem.java @@ -6,9 +6,9 @@ import utils.StringUtils; // perform any parsing past naming columns, and just holds the raw data. public class ConfigItem { - public String type; - public String key; - public String value; + public String type; // The section this specific key/value pair belongs to. This almost certainly will appear in multiple places. + public String key; // A unique key for a given lookup value for the specified section. Keys, within sections, are unique. + public String value; // The value assocaited with the key. public static final int items = 3; public static final String[] header = {"Type","Key","Value"}; diff --git a/src/core/LocCommands.java b/src/core/LocCommands.java index 30d071e..2d446e7 100644 --- a/src/core/LocCommands.java +++ b/src/core/LocCommands.java @@ -11,7 +11,7 @@ import dataStructures.Pair; public class LocCommands extends BaseLocFile implements IConfigSection { // Defined const variables - public static final String HeaderName = "Localized Commands"; + public static final String header = "Localized Commands"; public static final String function = "LocCommands.stub"; // Instance @@ -20,7 +20,7 @@ public class LocCommands extends BaseLocFile implements IConfigSection // Constructor public LocCommands() { - super(HeaderName, function); + super(header, function); GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName()); diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index fb93eff..a17d2ed 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -7,22 +7,37 @@ 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.KittyStartupMode; +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 +70,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 +105,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 +165,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,8 +383,15 @@ public class ObjectBuilderFactory { lazyInit(); - kitty = new JDABuilder(AccountType.BOT).setToken(Ref.TestToken).buildBlocking(); - kitty.getPresence().setGame(Game.playing("with digital yarn")); + // Determine token based on config. Default to test token. + String tokenToUse = Ref.TestToken; + if(ConfigGlobals.getStartupMode() == KittyStartupMode.Release) + tokenToUse = Ref.Token; + + // Construct bot based on token + kitty = new JDABuilder(AccountType.BOT) + .setToken(tokenToUse).buildBlocking(); + kitty.getPresence().setGame(Game.playing("with a laser pointer")); kitty.addEventListener(new Main()); return new KittyCore(kitty); 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/dataStructures/KittyStartupMode.java b/src/dataStructures/KittyStartupMode.java new file mode 100644 index 0000000..3f9f8a7 --- /dev/null +++ b/src/dataStructures/KittyStartupMode.java @@ -0,0 +1,18 @@ +package dataStructures; + +public enum KittyStartupMode +{ + Dev(1), Release(2); + + private final int value; + private KittyStartupMode(int value) + { + this.value = value; + } + + public int getValue() + { + return value; + } +} + 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..c320651 --- /dev/null +++ b/src/utils/audio/AudioUtils.java @@ -0,0 +1,144 @@ +package utils.audio; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +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 Queue playlist = new LinkedList<>(); + + + 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); + } + do + { + if(player.getPlayingTrack() == null) + { + player.startTrack(playlist.poll(), false); + } + } + while(!playlist.isEmpty()); + } + } + + + public String playVideo(String videoURL) + { + guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); + playerManager.loadItemOrdered(player, videoURL, new SmallAudio(player)); + + return null; + } + + public String skipVideo(AudioPlayer player) + { + return null; + } + + public String stopPlayer(AudioPlayer player) + { + playlist.clear(); + player.stopTrack(); + return "Stopped"; + } + + public String getPlaylist(AudioPlayer player) + { + return player.getPlayingTrack().getInfo().title; + } +}