diff --git a/src/main/java/a9lim/jdautilities/command/CommandClient.java b/src/main/java/a9lim/jdautilities/command/CommandClient.java index 9255c8b2a..90ef95e7a 100644 --- a/src/main/java/a9lim/jdautilities/command/CommandClient.java +++ b/src/main/java/a9lim/jdautilities/command/CommandClient.java @@ -57,13 +57,9 @@ public interface CommandClient { int getCommandUses(String name); - String getOwnerId(); + long getOwnerId(); - long getOwnerIdLong(); - - String[] getCoOwnerIds(); - - long[] getCoOwnerIdsLong(); + long[] getCoOwnerIds(); String getSuccess(); diff --git a/src/main/java/a9lim/jdautilities/command/CommandClientBuilder.java b/src/main/java/a9lim/jdautilities/command/CommandClientBuilder.java index d97351962..8654d4d99 100644 --- a/src/main/java/a9lim/jdautilities/command/CommandClientBuilder.java +++ b/src/main/java/a9lim/jdautilities/command/CommandClientBuilder.java @@ -31,8 +31,9 @@ public class CommandClientBuilder { private Activity activity = Activity.playing("default"); private OnlineStatus status = OnlineStatus.ONLINE; - private String ownerId, serverInvite, success, warning, error, carbonKey, botsKey; - private String[] coOwnerIds; + private String serverInvite, success, warning, error, carbonKey, botsKey; + private long ownerId; + private long[] coOwnerIds; private List prefixes; private final List commands = new LinkedList<>(); private CommandListener listener; @@ -52,12 +53,12 @@ public CommandClient build() { return client; } - public CommandClientBuilder setOwnerId(String o) { + public CommandClientBuilder setOwnerId(long o) { ownerId = o; return this; } - public CommandClientBuilder setCoOwnerIds(String... co) { + public CommandClientBuilder setCoOwnerIds(long... co) { coOwnerIds = co; return this; } @@ -89,11 +90,6 @@ public CommandClientBuilder setActivity(Activity a) { return this; } - public CommandClientBuilder useDefaultGame() { - activity = Activity.playing("default"); - return this; - } - public CommandClientBuilder setStatus(OnlineStatus stat) { status = stat; return this; diff --git a/src/main/java/a9lim/jdautilities/command/CommandEvent.java b/src/main/java/a9lim/jdautilities/command/CommandEvent.java index d7de4e697..9521df904 100644 --- a/src/main/java/a9lim/jdautilities/command/CommandEvent.java +++ b/src/main/java/a9lim/jdautilities/command/CommandEvent.java @@ -365,17 +365,16 @@ public Member getSelfMember() { } public boolean isOwner() { - if (event.getAuthor().getId().equals(client.getOwnerId())) + if (event.getAuthor().getIdLong() == client.getOwnerId()) return true; if (client.getCoOwnerIds() == null) return false; - for (String id : client.getCoOwnerIds()) - if (id.equals(event.getAuthor().getId())) + for (long id : client.getCoOwnerIds()) + if (id == event.getAuthor().getIdLong()) return true; return false; } - // shortcuts public User getAuthor() { diff --git a/src/main/java/a9lim/jdautilities/command/impl/CommandClientImpl.java b/src/main/java/a9lim/jdautilities/command/impl/CommandClientImpl.java index c87d3b318..defe901db 100644 --- a/src/main/java/a9lim/jdautilities/command/impl/CommandClientImpl.java +++ b/src/main/java/a9lim/jdautilities/command/impl/CommandClientImpl.java @@ -20,7 +20,6 @@ import a9lim.jdautilities.command.*; import a9lim.jdautilities.commons.utils.FixedSizeCache; -import a9lim.jdautilities.commons.utils.SafeIdUtil; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.Permission; @@ -58,8 +57,9 @@ public class CommandClientImpl implements CommandClient, EventListener { private final OffsetDateTime start; private final Activity activity; private final OnlineStatus status; - private final String[] coOwnerIds; - private final String ownerId, serverInvite, success, warning, error, botsKey, carbonKey, defaultprefix; + private final long[] coOwnerIds; + private final long ownerId; + private final String serverInvite, success, warning, error, botsKey, carbonKey, defaultprefix; private final List prefixes; private final HashMap uses; private final HashMap commandIndex; @@ -76,18 +76,17 @@ public class CommandClientImpl implements CommandClient, EventListener { private int totalGuilds; private String helpword; - public CommandClientImpl(String inownerId, String[] incoOwnerIds, List inprefix, Activity inactivity, OnlineStatus instatus, String inserverInvite, + public CommandClientImpl(long inownerId, long[] incoOwnerIds, List inprefix, Activity inactivity, OnlineStatus instatus, String inserverInvite, String insuccess, String inwarning, String inerror, String incarbonKey, String inbotsKey, List incommands, boolean inshutdownAutomatically, ScheduledExecutorService inexecutor, int linkedCacheSize, AnnotatedModuleCompiler incompiler, GuildSettingsManager inmanager) { - Checks.check(inownerId != null, "Owner ID was set null or not set! Please provide an User ID to register as the owner!"); - if (SafeIdUtil.badId(inownerId)) + if (inownerId < 0) LOG.warn(String.format("The provided Owner ID (%s) was found unsafe! Make sure ID is a non-negative long!", inownerId)); if (incoOwnerIds != null) { - for (String coOwnerId : incoOwnerIds) { - if (SafeIdUtil.badId(coOwnerId)) + for (long coOwnerId : incoOwnerIds) { + if (coOwnerId < 0) LOG.warn(String.format("The provided CoOwner ID (%s) was found unsafe! Make sure ID is a non-negative long!", coOwnerId)); } } @@ -231,31 +230,16 @@ public void addAnnotatedModule(Object module) { } @Override - public String getOwnerId() { + public long getOwnerId() { return ownerId; } @Override - public long getOwnerIdLong() { - return Long.parseLong(ownerId); - } - - @Override - public String[] getCoOwnerIds() { - return coOwnerIds; - } - - @Override - public long[] getCoOwnerIdsLong() { + public long[] getCoOwnerIds() { // Thought about using java.util.Arrays#setAll(T[], IntFunction) // here, but as it turns out it's actually the same thing as this but // it throws an error if null. Go figure. - if (coOwnerIds == null) - return null; - long[] ids = new long[coOwnerIds.length]; - for (int i = 0; i < ids.length; i++) - ids[i] = Long.parseLong(coOwnerIds[i]); - return ids; + return coOwnerIds; } @Override @@ -347,7 +331,8 @@ private void onReady(ReadyEvent event) { event.getJDA().shutdown(); return; } - event.getJDA().getPresence().setPresence(status == null ? OnlineStatus.ONLINE : status, + // todo: look at this + event.getJDA().getPresence().setPresence(status, activity == null ? null : "default".equals(activity.getName()) ? Activity.playing("Type " + defaultprefix + helpword) : activity); // Start SettingsManager if necessary diff --git a/src/main/java/a9lim/jdautilities/commons/utils/SafeIdUtil.java b/src/main/java/a9lim/jdautilities/commons/utils/SafeIdUtil.java deleted file mode 100644 index be0f17a22..000000000 --- a/src/main/java/a9lim/jdautilities/commons/utils/SafeIdUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2023 Aidan Lim (a9lim) -// Copyright 2016-2018 John Grosh (jagrosh) & Kaidan Gustave (TheMonitorLizard). -// -// This file is part of Raiko. -// -// Raiko is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// Raiko is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with Raiko. If not, see . - -package a9lim.jdautilities.commons.utils; - -public class SafeIdUtil { - - public static long safeConvert(String id) { - try { - return Math.max(Long.parseLong(id.trim()),0); - } catch (NumberFormatException e) { - return 0; - } - } - - public static boolean badId(String id) { - try { - return Long.parseLong(id.trim()) < 0; - } catch (NumberFormatException e) { - return true; - } - } - -} diff --git a/src/main/java/a9lim/raiko/Bot.java b/src/main/java/a9lim/raiko/Bot.java index a17a949b1..b1baeb19a 100644 --- a/src/main/java/a9lim/raiko/Bot.java +++ b/src/main/java/a9lim/raiko/Bot.java @@ -44,8 +44,6 @@ public class Bot { private final PlaylistLoader playlists; private final NowplayingHandler nowplaying; private final AloneInVoiceHandler aloneInVoiceHandler; - private final ChatBot chatBot; - private boolean shuttingDown; private JDA jda; private GUI gui; @@ -57,12 +55,11 @@ public Bot(EventWaiter inwaiter, BotConfig inconfig, SettingsManager insettings) playlists = new PlaylistLoader(inconfig); threadpool = Executors.newSingleThreadScheduledExecutor(); players = new PlayerManager(this); - players.init(); + players.init(inconfig); nowplaying = new NowplayingHandler(this); nowplaying.init(); aloneInVoiceHandler = new AloneInVoiceHandler(this); aloneInVoiceHandler.init(); - chatBot = new ChatBot(inconfig); } public BotConfig getConfig() { @@ -96,9 +93,6 @@ public NowplayingHandler getNowplayingHandler() { public AloneInVoiceHandler getAloneInVoiceHandler() { return aloneInVoiceHandler; } - public ChatBot getChatBot() { - return chatBot; - } public JDA getJDA() { return jda; @@ -111,7 +105,7 @@ public void closeAudioConnection(long guildId) { } public void resetGame() { - Activity game = config.getGame() == null || "none".equalsIgnoreCase(config.getGame().getName()) ? null : config.getGame(); + Activity game = config.getGame(); if (!Objects.equals(jda.getPresence().getActivity(), game)) jda.getPresence().setActivity(game); } diff --git a/src/main/java/a9lim/raiko/BotConfig.java b/src/main/java/a9lim/raiko/BotConfig.java index 401521865..09fe8c95f 100644 --- a/src/main/java/a9lim/raiko/BotConfig.java +++ b/src/main/java/a9lim/raiko/BotConfig.java @@ -43,7 +43,7 @@ public class BotConfig implements AliasSource { private Path path; private String token, playlistsFolder, successEmoji, warningEmoji, errorEmoji, loadingEmoji, searchingEmoji, - cgpttoken, preprompt; + cgpttoken, preprompt, ytemail, ytpw, nndemail, nndpw; private List prefixes; private boolean stayInChannel, songInGame, npImages, model, valid; @@ -86,10 +86,16 @@ public void load() { aloneTimeUntilStop = config.getLong("alonetimeuntilstop"); playlistsFolder = config.getString("playlistsfolder"); aliases = config.getConfig("aliases"); - cgpttoken = config.getString("gpttoken"); + + cgpttoken = noneblank(config.getString("gpttoken")); model = config.getBoolean("cheapmodel"); preprompt = config.getString("preprompt"); + ytemail = noneblank(config.getString("ytemail")); + ytpw = noneblank(config.getString("ytpw")); + nndemail = noneblank(config.getString("nndemail")); + nndpw = noneblank(config.getString("nndpw")); + // we may need to write a new config file boolean write = false; @@ -108,19 +114,6 @@ public void load() { } } - // validate chatgpt token - if (cgpttoken == null || cgpttoken.isEmpty() || "CGPTTOKEN".equalsIgnoreCase(cgpttoken)) { - cgpttoken = prompt.prompt(""" - Please provide an OpenAI token. - OpenAI Token:\s"""); - if (cgpttoken == null) { - prompt.alert(Prompt.Level.WARNING, CONTEXT, "No token provided! Exiting.\n\nConfig Location: " + path.toAbsolutePath()); - return; - } else { - write = true; - } - } - // validate bot owner if (owner <= 0) { try { @@ -151,6 +144,8 @@ public void load() { } } + //todo: fix this + private void writeToFile() { byte[] bytes = loadDefaultConfig().replace("BOT_TOKEN_HERE", token) .replace("0 // OWNER ID", Long.toString(owner)) @@ -194,6 +189,9 @@ public static void writeDefaultConfig() { } } + public static String noneblank(String s){ + return "none".equalsIgnoreCase(s) || s.isBlank() ? null : s; + } public boolean isValid() { return valid; } @@ -293,4 +291,20 @@ public boolean getModel(){ public String getPreprompt() { return preprompt; } + + public String getYTEmail() { + return ytemail; + } + + public String getYTPW() { + return ytpw; + } + + public String getNNDEmail() { + return nndemail; + } + + public String getNNDPW() { + return nndpw; + } } diff --git a/src/main/java/a9lim/raiko/Listener.java b/src/main/java/a9lim/raiko/Listener.java index 19b530bef..2a6dba170 100644 --- a/src/main/java/a9lim/raiko/Listener.java +++ b/src/main/java/a9lim/raiko/Listener.java @@ -42,7 +42,7 @@ public void onReady(ReadyEvent event) { log.warn("This bot is not on any guilds! Use the following link to add the bot to your guilds!"); log.warn(event.getJDA().getInviteUrl(Raiko.RECOMMENDED_PERMS)); } - event.getJDA().getGuilds().forEach((guild) -> { + event.getJDA().getGuilds().forEach(guild -> { try { VoiceChannel vc = bot.getSettingsManager().getSettings(guild).getVoiceChannel(guild); if (bot.getSettingsManager().getSettings(guild).getDefaultPlaylist() != null diff --git a/src/main/java/a9lim/raiko/Raiko.java b/src/main/java/a9lim/raiko/Raiko.java index 892d01d05..922a4388a 100644 --- a/src/main/java/a9lim/raiko/Raiko.java +++ b/src/main/java/a9lim/raiko/Raiko.java @@ -18,8 +18,10 @@ package a9lim.raiko; +import a9lim.jdautilities.command.Command; import a9lim.jdautilities.command.CommandClientBuilder; import a9lim.jdautilities.commons.waiter.EventWaiter; +import a9lim.raiko.chat.ChatBot; import a9lim.raiko.commands.BotCommand; import a9lim.raiko.commands.ChatCommand; import a9lim.raiko.commands.admin.PrefixCmd; @@ -87,12 +89,11 @@ private static void startBot() { aboutCmd.setReplacementCharacter("\uD83C\uDFB6"); // 🎶 BotCommand.setBot(bot); - ChatCommand.setChatBot(bot.getChatBot()); // set up the command client CommandClientBuilder cb = new CommandClientBuilder() .setPrefixes(config.getPrefixes()) - .setOwnerId(Long.toString(config.getOwnerId())) + .setOwnerId(config.getOwnerId()) .setEmojis(config.getSuccess(), config.getWarning(), config.getError()) .setLinkedCacheSize(200) .setGuildSettingsManager(settings) @@ -129,25 +130,21 @@ private static void startBot() { new SetgameCmd(), new SetnameCmd(), new SetstatusCmd(), - new ShutdownCmd(), - - new ChatCmd(), - new ClearChatCmd(), - new ToggleModelCmd(), - new RemoveChatCmd(), - new RewindChatCmd(), - new SetPrepromptCmd() - ); - boolean nogame = false; - if (config.getStatus() != OnlineStatus.UNKNOWN) - cb.setStatus(config.getStatus()); - if (config.getGame() == null) - cb.useDefaultGame(); - else if ("none".equalsIgnoreCase(config.getGame().getName())) { - cb.setActivity(null); - nogame = true; - } else - cb.setActivity(config.getGame()); + new ShutdownCmd()); + + if(config.getCgpttoken() != null) { + ChatCommand.setChatBot(new ChatBot(config)); + cb.addCommands( + new ChatCmd(), + new ClearChatCmd(), + new ToggleModelCmd(), + new RemoveChatCmd(), + new RewindChatCmd(), + new SetPrepromptCmd()); + } + + cb.setStatus(config.getStatus()); + cb.setActivity(config.getGame()); if (!prompt.isNoGUI()) { try { @@ -166,9 +163,8 @@ else if ("none".equalsIgnoreCase(config.getGame().getName())) { bot.setJDA( JDABuilder.create(config.getToken(), Arrays.asList(INTENTS)) .enableCache(CacheFlag.MEMBER_OVERRIDES, CacheFlag.VOICE_STATE) .disableCache(CacheFlag.ACTIVITY, CacheFlag.CLIENT_STATUS, CacheFlag.EMOJI, CacheFlag.ONLINE_STATUS, CacheFlag.SCHEDULED_EVENTS) - .setActivity(nogame ? null : Activity.playing("loading...")) - .setStatus(config.getStatus() == OnlineStatus.INVISIBLE || config.getStatus() == OnlineStatus.OFFLINE - ? OnlineStatus.INVISIBLE : OnlineStatus.DO_NOT_DISTURB) +// .setActivity(config.getGame()) +// .setStatus(config.getStatus()) .addEventListeners(cb.build(), waiter, new Listener(bot)) .setBulkDeleteSplittingEnabled(true).build() ); } catch (IllegalArgumentException ex) { diff --git a/src/main/java/a9lim/raiko/audio/PlayerManager.java b/src/main/java/a9lim/raiko/audio/PlayerManager.java index 5a7bb601a..5ce82a4c8 100644 --- a/src/main/java/a9lim/raiko/audio/PlayerManager.java +++ b/src/main/java/a9lim/raiko/audio/PlayerManager.java @@ -18,13 +18,25 @@ package a9lim.raiko.audio; +import a9lim.raiko.BotConfig; +import com.sedmelluq.discord.lavaplayer.container.MediaContainerRegistry; 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.source.bandcamp.BandcampAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.beam.BeamAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.getyarn.GetyarnAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.nico.NicoAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.yamusic.YandexMusicAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; import a9lim.raiko.Bot; import net.dv8tion.jda.api.entities.Guild; - public class PlayerManager extends DefaultAudioPlayerManager { private final Bot bot; @@ -32,10 +44,21 @@ public PlayerManager(Bot b) { bot = b; } - public void init() { - AudioSourceManagers.registerRemoteSources(this); - AudioSourceManagers.registerLocalSource(this); - source(YoutubeAudioSourceManager.class).setPlaylistPageCount(10); + public void init(BotConfig config) { + // custom sources + YoutubeAudioSourceManager yt = new YoutubeAudioSourceManager(true,config.getYTEmail(),config.getYTPW()); + yt.setPlaylistPageCount(10); + registerSourceManager(yt); + registerSourceManager(new NicoAudioSourceManager(config.getNNDEmail(),config.getNNDPW())); + registerSourceManager(new YandexMusicAudioSourceManager(true)); + registerSourceManager(SoundCloudAudioSourceManager.createDefault()); + registerSourceManager(new BandcampAudioSourceManager()); + registerSourceManager(new VimeoAudioSourceManager()); + registerSourceManager(new TwitchStreamAudioSourceManager()); + registerSourceManager(new BeamAudioSourceManager()); + registerSourceManager(new GetyarnAudioSourceManager()); + registerSourceManager(new HttpAudioSourceManager(MediaContainerRegistry.DEFAULT_REGISTRY)); + registerSourceManager(new LocalAudioSourceManager(MediaContainerRegistry.DEFAULT_REGISTRY)); } public Bot getBot() { diff --git a/src/main/java/a9lim/raiko/chat/ChatBot.java b/src/main/java/a9lim/raiko/chat/ChatBot.java index a37bff7c2..cf0bf4210 100644 --- a/src/main/java/a9lim/raiko/chat/ChatBot.java +++ b/src/main/java/a9lim/raiko/chat/ChatBot.java @@ -28,6 +28,8 @@ import java.util.concurrent.TimeUnit; public class ChatBot { + + // HttpClient with long wait times because gpt often takes a while private final OkHttpClient client = new OkHttpClient.Builder() .callTimeout(10, TimeUnit.MINUTES) .readTimeout(10, TimeUnit.MINUTES) @@ -41,6 +43,8 @@ public class ChatBot { private boolean cheap; private final String apiKey; private final MediaType mediaType = MediaType.parse("application/json"); + + // Set up details with config public ChatBot(BotConfig c) { apiKey = c.getCgpttoken(); cheap = c.getModel(); @@ -48,23 +52,24 @@ public ChatBot(BotConfig c) { clearHead(); } + // Get model in use public String getModel(){ return (cheap ? "gpt-3.5-turbo-1106" : "gpt-4-1106-preview"); } - // chat function + // Function to chat public String chat(String s, long l) { - // append and json-ize new prompt to previous reply, escaping forbidden characters (\n and ") + // Append and json-ize new prompt to previous reply, escaping forbidden characters (\n and ") temp += "{\"role\": \"user\", \"content\": \"" + s.replace("\n","\\n").replace("\"", "\\\"") + "\"}"; - // if chat history is full, clear out space + // If chat history is full, clear out space if(chathist.size() == capacity) chathist.pop(); - // add new prompt to chat history + // Add new prompt to chat history chathist.add(new QueuedChat(temp,l)); try { - // send full request to openai, and process and save result as reply + // Send full request to openai, and process and save result as reply String reply = (new JSONObject(client.newCall(new Request.Builder() .url("https://api.openai.com/v1/chat/completions") .post(RequestBody.create(head + chathist + "]}",mediaType)) @@ -75,13 +80,13 @@ public String chat(String s, long l) { .getJSONArray("choices").getJSONObject(0) .getJSONObject("message").getString("content")); - // save and json-ize new reply, escaping forbidden characters (\n and ") + // Save and json-ize new reply, escaping forbidden characters (\n and ") temp = ", {\"role\": \"assistant\", \"content\": \"" + reply.replace("\n","\\n").replace("\"", "\\\"") + "\"}, "; - // return reply + // Return reply return reply; } catch (Exception e){ - // if something goes wrong, clear chat history and return error + // If something goes wrong, clear chat history in case some message was causing the issue and return error System.out.println(e); clear(); return "Huh?"; diff --git a/src/main/java/a9lim/raiko/commands/AdminCommand.java b/src/main/java/a9lim/raiko/commands/AdminCommand.java index 07384ed61..22fb0ccd6 100644 --- a/src/main/java/a9lim/raiko/commands/AdminCommand.java +++ b/src/main/java/a9lim/raiko/commands/AdminCommand.java @@ -23,7 +23,7 @@ public abstract class AdminCommand extends Command { public AdminCommand() { - category = new Category("Admin", event -> event.getAuthor().getId().equals(event.getClient().getOwnerId()) || event.getGuild() == null || event.getMember().hasPermission(Permission.MANAGE_SERVER)); + category = new Category("Admin", event -> event.getAuthor().getIdLong() == event.getClient().getOwnerId() || event.getGuild() == null || event.getMember().hasPermission(Permission.MANAGE_SERVER)); guildOnly = true; } } diff --git a/src/main/java/a9lim/raiko/commands/BotCommand.java b/src/main/java/a9lim/raiko/commands/BotCommand.java index 3c0c2392c..114f56daf 100644 --- a/src/main/java/a9lim/raiko/commands/BotCommand.java +++ b/src/main/java/a9lim/raiko/commands/BotCommand.java @@ -4,6 +4,7 @@ import a9lim.raiko.Bot; public abstract class BotCommand extends Command { + // Store the bot used by all bot commands protected static Bot bot; public static void setBot(Bot b){ diff --git a/src/main/java/a9lim/raiko/commands/ChatCommand.java b/src/main/java/a9lim/raiko/commands/ChatCommand.java index 50c25cf6d..a857de9b1 100644 --- a/src/main/java/a9lim/raiko/commands/ChatCommand.java +++ b/src/main/java/a9lim/raiko/commands/ChatCommand.java @@ -15,19 +15,20 @@ // You should have received a copy of the GNU Affero General Public License // along with Raiko. If not, see . - package a9lim.raiko.commands; import a9lim.jdautilities.command.Command; import a9lim.raiko.chat.ChatBot; public abstract class ChatCommand extends Command { + // Store the chatbot used by all chat commands protected static ChatBot chatBot; public ChatCommand(){ guildOnly = true; category = new Category("Chat"); } + // Setter public static void setChatBot(ChatBot c){ chatBot = c; } diff --git a/src/main/java/a9lim/raiko/commands/music/PlayCmd.java b/src/main/java/a9lim/raiko/commands/music/PlayCmd.java index 6303c81dc..a0a6589f7 100644 --- a/src/main/java/a9lim/raiko/commands/music/PlayCmd.java +++ b/src/main/java/a9lim/raiko/commands/music/PlayCmd.java @@ -94,7 +94,7 @@ private ResultHandler(Message message, CommandEvent e, boolean b) { private void loadSingle(AudioTrack track, AudioPlaylist playlist) { if (bot.getConfig().isTooLong(track)) { m.editMessage(FormatUtil.filter(event.getClient().getWarning() + " This track (**" + track.getInfo().title + "**) is longer than the allowed maximum: `" - + FormatUtil.formatTime(track.getDuration()) + "` > `" + FormatUtil.formatTime(bot.getConfig().getMaxSeconds() * 1000) + "`")).queue(); + + FormatUtil.formatTime(track.getDuration()) + "` > `" + bot.getConfig().getMaxTime() + "`")).queue(); return; } AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler(); diff --git a/src/main/java/a9lim/raiko/commands/music/PlaynextCmd.java b/src/main/java/a9lim/raiko/commands/music/PlaynextCmd.java index d5263cac5..04163bf3e 100644 --- a/src/main/java/a9lim/raiko/commands/music/PlaynextCmd.java +++ b/src/main/java/a9lim/raiko/commands/music/PlaynextCmd.java @@ -67,7 +67,7 @@ private ResultHandler(Message message, CommandEvent e, boolean b) { private void loadSingle(AudioTrack track) { if (bot.getConfig().isTooLong(track)) { m.editMessage(FormatUtil.filter(event.getClient().getWarning() + " This track (**" + track.getInfo().title + "**) is longer than the allowed maximum: `" - + FormatUtil.formatTime(track.getDuration()) + "` > `" + FormatUtil.formatTime(bot.getConfig().getMaxSeconds() * 1000) + "`")).queue(); + + FormatUtil.formatTime(track.getDuration()) + "` > `" + bot.getConfig().getMaxTime() + "`")).queue(); return; } AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler(); diff --git a/src/main/java/a9lim/raiko/commands/music/QueueCmd.java b/src/main/java/a9lim/raiko/commands/music/QueueCmd.java index aae3b5263..7840dd837 100644 --- a/src/main/java/a9lim/raiko/commands/music/QueueCmd.java +++ b/src/main/java/a9lim/raiko/commands/music/QueueCmd.java @@ -27,6 +27,7 @@ import a9lim.raiko.audio.AudioHandler; import a9lim.raiko.audio.QueuedTrack; import a9lim.raiko.commands.MusicCommand; +import a9lim.raiko.queue.DoubleDealingQueue; import a9lim.raiko.settings.Settings; import a9lim.raiko.utils.GuildUtil; import net.dv8tion.jda.api.Permission; @@ -65,8 +66,8 @@ public void doCommand(CommandEvent event) { pagenum = Integer.parseInt(event.getArgs()); } catch (NumberFormatException ignore) {} AudioHandler ah = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler(); - Deque deque = ah.getQueue().getDeque(); - if (deque.isEmpty()) { + DoubleDealingQueue queue = ah.getQueue(); + if (queue.isEmpty()) { MessageCreateData nowp = ah.getNowPlaying(event.getJDA()); event.reply(new MessageCreateBuilder() .setContent(event.getClient().getWarning() + " There is no music in the queue!") @@ -77,9 +78,9 @@ public void doCommand(CommandEvent event) { }); return; } - String[] songs = new String[deque.size()]; + String[] songs = new String[queue.size()]; long total = 0; - Iterator iterator = deque.iterator(); + Iterator iterator = queue.getDeque().iterator(); for (int i = 0; i < songs.length; i++) { QueuedTrack track = iterator.next(); total += track.getTrack().getDuration(); diff --git a/src/main/java/a9lim/raiko/commands/music/RemoveCmd.java b/src/main/java/a9lim/raiko/commands/music/RemoveCmd.java index 13fce8e4b..f285a25a5 100644 --- a/src/main/java/a9lim/raiko/commands/music/RemoveCmd.java +++ b/src/main/java/a9lim/raiko/commands/music/RemoveCmd.java @@ -22,6 +22,7 @@ import a9lim.raiko.audio.AudioHandler; import a9lim.raiko.audio.QueuedTrack; import a9lim.raiko.commands.MusicCommand; +import a9lim.raiko.queue.DoubleDealingQueue; import net.dv8tion.jda.api.entities.User; public class RemoveCmd extends MusicCommand { @@ -35,57 +36,57 @@ public RemoveCmd() { @Override public void doCommand(CommandEvent event) { - AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler(); - if (handler.getQueue().isEmpty()) { + DoubleDealingQueue queue = ((AudioHandler) event.getGuild().getAudioManager().getSendingHandler()).getQueue(); + if (queue.isEmpty()) { event.replyError("There is nothing in the queue!"); return; } - int pos; - if ("all".equalsIgnoreCase(event.getArgs())) { - pos = handler.getQueue().size(); - handler.getQueue().clear(); - if (pos == 0) - event.replyWarning("There are no songs in the queue!"); - else - event.replySuccess("Successfully removed " + pos + " entries."); - return; - } - if ("mine".equalsIgnoreCase(event.getArgs())) { - if ((pos = handler.getQueue().removeAll(event.getAuthor().getIdLong())) == 0) - event.replyWarning("You don't have any songs in the queue!"); - else - event.replySuccess("Successfully removed your " + pos + " entries."); - return; - } - try { - pos = Integer.parseInt(event.getArgs()); - } catch (NumberFormatException e) { - QueuedTrack qt = handler.getQueue().getDeque().peek(); - handler.getQueue().getDeque().pop(); - User u; - try { - u = event.getJDA().getUserById(qt.getIdentifier()); - } catch (Exception f) { - u = null; + switch(event.getArgs().toLowerCase()) { + case "all" -> { + pos = queue.size(); + if (pos == 0) + event.replyWarning("There are no songs in the queue!"); + else { + queue.clear(); + event.replySuccess("Successfully removed " + pos + " entries."); + } + } + case "mine" -> { + if ((pos = queue.removeAll(event.getAuthor().getIdLong())) == 0) + event.replyWarning("You don't have any songs in the queue!"); + else + event.replySuccess("Successfully removed your " + pos + " entries."); + } + default -> { + try { + pos = Integer.parseInt(event.getArgs()); + } catch (NumberFormatException e) { + QueuedTrack qt = queue.pop(); + User u; + try { + u = event.getJDA().getUserById(qt.getIdentifier()); + } catch (Exception f) { + u = null; + } + event.replySuccess("Removed **" + qt.getTrack().getInfo().title + + "** from the queue (requested by " + (u == null ? "someone" : "**" + u.getName() + "**") + ")"); + return; + } + if (pos < 1 || pos > queue.size()) { + event.replyError("Position must be a valid integer between 1 and " + queue.size() + "!"); + return; + } + QueuedTrack qt = queue.remove(pos); + User u; + try { + u = event.getJDA().getUserById(qt.getIdentifier()); + } catch (Exception e) { + u = null; + } + event.replySuccess("Removed **" + qt.getTrack().getInfo().title + + "** from the queue (requested by " + (u == null ? "someone" : "**" + u.getName() + "**") + ")"); } - event.replySuccess("Removed **" + qt.getTrack().getInfo().title - + "** from the queue (requested by " + (u == null ? "someone" : "**" + u.getName() + "**") + ")"); - return; - } - if (pos < 1 || pos > handler.getQueue().size()) { - event.replyError("Position must be a valid integer between 1 and " + handler.getQueue().size() + "!"); - return; - } - QueuedTrack qt = handler.getQueue().remove(pos); - User u; - try { - u = event.getJDA().getUserById(qt.getIdentifier()); - } catch (Exception e) { - u = null; } - event.replySuccess("Removed **" + qt.getTrack().getInfo().title - + "** from the queue (requested by " + (u == null ? "someone" : "**" + u.getName() + "**") + ")"); - } } diff --git a/src/main/java/a9lim/raiko/queue/DoubleDealingQueue.java b/src/main/java/a9lim/raiko/queue/DoubleDealingQueue.java index 61b2ecf82..54c3058ee 100644 --- a/src/main/java/a9lim/raiko/queue/DoubleDealingQueue.java +++ b/src/main/java/a9lim/raiko/queue/DoubleDealingQueue.java @@ -15,22 +15,26 @@ // You should have received a copy of the GNU Affero General Public License // along with Raiko. If not, see . - package a9lim.raiko.queue; import java.util.*; + +// Deque with a few extra features public class DoubleDealingQueue { private Deque deque; + // Standard constructor public DoubleDealingQueue(){ deque = new ArrayDeque<>(); } + // Known size constructor public DoubleDealingQueue(int i){ deque = new ArrayDeque<>(i); } + // Normal Deque adders public void add(T item) { deque.add(item); } @@ -39,6 +43,7 @@ public void push(T item) { deque.push(item); } + // Arbitrary index add public void add(int index, T item) { ArrayDeque helper; if(index < deque.size()/2) { @@ -48,35 +53,16 @@ public void add(int index, T item) { deque.push(item); helper.forEach(deque::push); } else { - int size = deque.size(); - helper = new ArrayDeque<>(size - index); - while(index++ < size) + index = deque.size() - index; + helper = new ArrayDeque<>(index); + while(index-- > 0) helper.push(deque.removeLast()); deque.add(item); deque.addAll(helper); } } - public int size() { - return deque.size(); - } - - public T pop() { - return deque.pop(); - } - - public T popLast() { - return deque.removeLast(); - } - - public boolean isEmpty() { - return deque.isEmpty(); - } - - public Deque getDeque() { - return deque; - } - + // Normal Deque getters public T peek() { return deque.peek(); } @@ -85,6 +71,7 @@ public T peekLast() { return deque.peekLast(); } + // Arbitrary index get public T get(int index) { Iterator iterator; if(index < deque.size()/2) { @@ -99,6 +86,16 @@ public T get(int index) { return iterator.next(); } + // Normal Deque removers + public T pop() { + return deque.pop(); + } + + public T popLast() { + return deque.removeLast(); + } + + // Arbitrary index remove public T remove(int index) { Iterator iterator; if(index < deque.size()/2) { @@ -115,6 +112,7 @@ public T remove(int index) { return out; } + // Removal by identity public int removeAll(long identifier) { int count = 0; Iterator iterator = deque.iterator(); @@ -126,10 +124,28 @@ public int removeAll(long identifier) { return count; } + // Normal Deque methods + public int size() { + return deque.size(); + } + + public boolean isEmpty() { + return deque.isEmpty(); + } + public void clear() { deque.clear(); } + public Deque getDeque() { + return deque; + } + + public void reverse(){ + deque = deque.reversed(); + } + + // Shuffle by identity public int shuffle(long identifier) { ArrayDeque iset = new ArrayDeque<>(); ArrayList out = new ArrayList<>(); @@ -155,6 +171,7 @@ public int shuffle(long identifier) { return out.size(); } + // Shuffle deque public void shuffle() { ArrayList out = new ArrayList<>(deque); Collections.shuffle(out); @@ -162,16 +179,19 @@ public void shuffle() { deque.addAll(out); } + // Remove first n elements public void skip(int number) { while (--number > 0) deque.pop(); } + // Remove last n elements public void backskip(int number) { while (--number > 0) deque.removeLast(); } + // Move within deque public T moveItem(int from, int to) { int i = 0; ArrayDeque helper = new ArrayDeque<>(to); @@ -189,6 +209,7 @@ public T moveItem(int from, int to) { return B; } + // Swap two elements public List swap(int a, int b) { int i; if (b > a) { @@ -217,10 +238,6 @@ public List swap(int a, int b) { return out; } - public void reverse(){ - deque = deque.reversed(); - } - public String toString(){ StringBuilder out = new StringBuilder(); deque.forEach(out::append); diff --git a/src/main/java/a9lim/raiko/utils/OtherUtil.java b/src/main/java/a9lim/raiko/utils/OtherUtil.java index fdd1b8d72..a1b6295d8 100644 --- a/src/main/java/a9lim/raiko/utils/OtherUtil.java +++ b/src/main/java/a9lim/raiko/utils/OtherUtil.java @@ -67,8 +67,10 @@ public static InputStream imageFromUrl(String url) { } public static Activity parseGame(String game) { - if (game == null || game.trim().isEmpty() || "default".equalsIgnoreCase(game.trim())) + if (game == null || game.isBlank()) return null; + if("default".equalsIgnoreCase(game.trim())) + return Activity.playing("default"); String lower = game.toLowerCase(); if (lower.startsWith("playing")) return Activity.playing(makeNonEmpty(game.substring(7).trim())); @@ -92,7 +94,7 @@ public static String makeNonEmpty(String str) { } public static OnlineStatus parseStatus(String status) { - if (status == null || status.trim().isEmpty()) + if (status == null || status.isBlank()) return OnlineStatus.ONLINE; OnlineStatus st = OnlineStatus.fromKey(status); return st == null ? OnlineStatus.ONLINE : st; diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index de2c8d570..8367d638c 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -23,9 +23,10 @@ owner = 0 // OWNER ID // This sets the bot's OpenAI token +// If set to NONE, chatbot features will be unavailable! // https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key -gpttoken = CGPTTOKEN +gpttoken = NONE // If set to true, the bot will use GPT-3.5 Turbo @@ -40,6 +41,20 @@ cheapmodel = false preprompt = "You are Raiko Horikawa, fun-loving, free spirited drum tsukumogami. You're having a chat with several humans!" +// This is the email and password used by the bot to sign in to youtube +// If set to NONE, you won't be able to access age-restricted videos + +ytemail = "NONE" +ytpw = "NONE" + + +// This is the email and password used by the bot to sign in to niconico +// If set to NONE, you won't be able to play niconico videos + +nndemail = "NONE" +nndpw = "NONE" + + // This is the bot's prefix used to signify commands // If you use !!, !!play will make it play // If left empty, the prefix will be a mention of the bot (@Botname play) @@ -48,7 +63,7 @@ prefixes = [ "!", "?", ";" ] // This modifies the bot's default game -// Set this to NONE to have no game +// Leave this blank to have no game // Set this to DEFAULT to use the default game // You can make the game "Playing X", "Listening to X", or "Watching X" // where X is the title. If you don't include an action, it will default to "Playing" diff --git a/src/test/java/a9lim/raiko/Test.java b/src/test/java/a9lim/raiko/Test.java index 66ef16a4e..6284cc03a 100644 --- a/src/test/java/a9lim/raiko/Test.java +++ b/src/test/java/a9lim/raiko/Test.java @@ -25,15 +25,8 @@ public class Test { public static void main(String[] args){ - testSwap(20, 0, 20); - System.out.println(); - testSwap(20, 1, 20); - System.out.println(); - testSwap(20, 0, 20); - System.out.println(); - testSwap(20, 0, 19); - System.out.println(); - testSwap(20, 1, 19); + for(int i = 0; i < 21; i++) + testAdd(20,i); } public static void testAdd(int len, int target){