From 29a9d1bc46489feeffd927296e5d2b6f21141b5c Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Tue, 25 Sep 2018 20:38:20 -0400 Subject: [PATCH 001/155] Fixed blacklist command where database command would overlap each other --- .../java/netneutrality/ThreadManager.java | 10 ++- .../command/message/BlacklistCommand.java | 60 ++++++++--------- .../db/controllers/DBBlacklist.java | 67 ++++++++++++------- 3 files changed, 73 insertions(+), 64 deletions(-) diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 09a96c4..bd2a69d 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -16,23 +16,21 @@ public class ThreadManager { public static final ExecutorService executor = Executors.newSingleThreadExecutor(); public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - public static void shutdownExecutor() { try { - System.out.println("attempt to shutdown executor"); + System.out.println("[Executor] Shutting down..."); executor.shutdown(); executor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.err.println("tasks interrupted"); + System.err.println("[Executor] Running tasks interrupted!"); } finally { if (!executor.isTerminated()) { - System.err.println("cancel non-finished tasks"); + System.err.println("[Executor] Forcing shutdown of running tasks.."); } executor.shutdownNow(); - System.out.println("shutdown finished"); + System.out.println("[Executor] Shutdown finished!"); } } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 6631496..970ad80 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -64,15 +64,12 @@ public class BlacklistCommand extends AbstractCommand { try { StringBuilder sb = new StringBuilder(); - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId(), new Consumer>() { - @Override - public void accept(ArrayList mBlacklists) { - for (MBlacklist bl : mBlacklists) { - sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); - } - - t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); + ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId(), mBlacklists -> { + for (MBlacklist bl : mBlacklists) { + sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); } + + t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); }); } catch (RuntimeException e) { @@ -86,49 +83,48 @@ public class BlacklistCommand extends AbstractCommand { case "add": - try { - ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, event.getAuthor().getId(), event.getGuild().getId())); + ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, event.getAuthor().getId(), event.getGuild().getId()), response -> { + if (response) { event.getTextChannel().sendMessage("Added the word \"" + word + "\" to the blacklist.").queue(); - } catch (RuntimeException e) { + } else { event.getTextChannel().sendMessage("Error adding \"" + word + "\" to the blacklist. It's already blacklisted!").queue(); - LogHandler.log(e); } - + }); break; case "remove": - try { - ((DBBlacklist) DBController.get("blacklist")).delete(word, event.getGuild().getId()); + ((DBBlacklist) DBController.get("blacklist")).delete(word, event.getGuild().getId(), success -> { + if (success) { event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } catch (RuntimeException e) { - LogHandler.log(e); + } else { event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); } - + }); + break; case "disable": - - try { - ((DBBlacklist) DBController.get("blacklist")).disable(word, event.getGuild().getId()); - event.getTextChannel().sendMessage("Succesfully disabled the word \"" + word + "\" from the blacklist!").queue(); - } catch (NullPointerException e) { - LogHandler.log(e); - event.getTextChannel().sendMessage("Error disabling \"" + word + "\", it's not blacklisted!").queue(); + + ((DBBlacklist) DBController.get("blacklist")).disable(word, event.getGuild().getId(), success -> { + if (success) { + event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); } + }); break; case "enable": - - try { - ((DBBlacklist) DBController.get("blacklist")).enable(word, event.getGuild().getId()); - event.getTextChannel().sendMessage("Succesfully enabled the word \"" + word + "\" from the blacklist!").queue(); - } catch (NullPointerException e) { - event.getTextChannel().sendMessage("Error enabling \"" + word + "\", it's not blacklisted!").queue(); - LogHandler.log(e); + + ((DBBlacklist) DBController.get("blacklist")).enable(word, event.getGuild().getId(), success -> { + if (success) { + event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); } + }); break; diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 255b0b6..09cfe57 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -27,39 +27,53 @@ public class DBBlacklist extends AbstractController { return database; } - public void add(MBlacklist obj) { - if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { - database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); - } else { - throw new RuntimeException("Word is already blacklisted"); - } + public void add(MBlacklist obj, Consumer success) { + ThreadManager.executor.submit(() -> { + if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { + database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); + success.accept(true); + } else { + success.accept(false); + } + + }); + } - public void delete(String word, String serverId) { - if (isAlreadyBlacklisted(word, serverId)) { - database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); - } else { - throw new RuntimeException("Is not blacklisted"); - } - } - - public void enable(String word, String serverId) { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); - } else { - throw new RuntimeException("Is not blacklisted"); - } + public void delete(String word, String serverId, Consumer success) { + ThreadManager.executor.submit(() -> { + if (isAlreadyBlacklisted(word, serverId)) { + System.out.println("true"); + database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + success.accept(true); + } else { + success.accept(false); + } + }); } - public void disable(String word, String serverId) { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); - } else { - throw new RuntimeException("Is not blacklisted"); - } + public void enable(String word, String serverId, Consumer success) { + ThreadManager.executor.submit(() -> { + if (isAlreadyBlacklisted(word, serverId)) { + database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); + success.accept(true); + } else { + success.accept(false); + } + }); + } + public void disable(String word, String serverId, Consumer success) { + ThreadManager.executor.submit(() -> { + if (isAlreadyBlacklisted(word, serverId)) { + database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); + success.accept(true); + } else { + success.accept(false); + } + }); } public void getBlacklistForWord(String word, String serverId, Consumer success) { @@ -108,6 +122,7 @@ public class DBBlacklist extends AbstractController { public boolean isAlreadyBlacklisted(String word, String serverId) { ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + try { if (rs.next()) { return rs.getInt(1) != 0; From 3f9164d3a675231ec2ffcf40e8a9649d3e739361 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Tue, 25 Sep 2018 20:49:40 -0400 Subject: [PATCH 002/155] Fixed compiler error --- src/main/java/netneutrality/MusicBot.java | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 48d2223..ab30ea3 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -38,32 +38,32 @@ public class MusicBot { jda.getPresence().setGame(Game.watching("me load...")); jda.addEventListener(new NewCommandListener(), new EditHandler()); - Settings.setCreator(jda.getUserById("194270171727265792")); - Settings.setOwnerGuild(jda.getGuildById("195386426400047105")); - - WebApi webserver = new WebApi(); + // WebApi webserver = new WebApi(); jda.getPresence().setGame(Game.watching("rape")); - Thread status = new Thread(new StatusThread(jda.getPresence())); - // status.start(); + ConsoleHandler consoleInput = new ConsoleHandler(); switch (consoleInput.init()) { case "quit": - System.out.println("Shutting down..."); - MusicManager.disconnectPlayers(); - jda.shutdown(); - DBController.shutdown(); - ThreadManager.shutdownExecutor(); - System.out.println("Shutdown complete"); + shutdown(); System.exit(0); break; } } + + public static void shutdown() { + System.out.println("Shutting down..."); + MusicManager.disconnectPlayers(); + disconnect(); + DBController.shutdown(); + ThreadManager.shutdownExecutor(); + System.out.println("Shutdown complete"); + } public static JDA getJDA() { return jda; From 04fc5b17f2e7c4940b7f1dc47c5207ba3fce9b8d Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 25 Sep 2018 20:23:17 -0500 Subject: [PATCH 003/155] Delete LICENSE --- LICENSE | 201 -------------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 646d44f..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 Anthony - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. From 889e9404ac93554ad2cc3886dcc2e30bac56c686 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 25 Sep 2018 20:24:21 -0500 Subject: [PATCH 004/155] Changed license --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b7687ab --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + netneutrality + Copyright (C) 2018 Anthony + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + netneutrality Copyright (C) 2018 Anthony + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 15497a09abfa8e9ba9451ff413d4a28548489489 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 4 Nov 2018 20:14:51 -0500 Subject: [PATCH 005/155] Added user to play command and attempted to fix topic when playing music --- .../java/netneutrality/command/music/BitconnectCommand.java | 4 ++-- src/main/java/netneutrality/command/music/PlayCommand.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 47e6647..90536e1 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -54,12 +54,12 @@ public class BitconnectCommand extends AbstractCommand { if (player.isConnected()) { if (player.isConnectedTo(vChannel)) { - player.play("https://www.youtube.com/watch?v=A8M70M7tzTI", event.getTextChannel(), true); + player.play("https://www.youtube.com/watch?v=A8M70M7tzTI", event.getTextChannel(), event.getMember(), true); } else event.getTextChannel().sendMessage("Not in your voice channel").queue(); } else { player.connect(vChannel); - player.play("https://www.youtube.com/watch?v=A8M70M7tzTI", event.getTextChannel(), true); + player.play("https://www.youtube.com/watch?v=A8M70M7tzTI", event.getTextChannel(), event.getMember(), true); } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 76d1068..6002727 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -57,9 +57,9 @@ public class PlayCommand extends AbstractCommand { event.getMessage().delete().queue(); if (args.startsWith("ytsearch:")) { - player.play(args, event.getTextChannel(), false); + player.play(args, event.getTextChannel(), event.getMember(), false); } else { - player.play(args.split(" ")[0], event.getTextChannel(), false); + player.play(args.split(" ")[0], event.getTextChannel(), event.getMember(), false); } } else @@ -67,7 +67,7 @@ public class PlayCommand extends AbstractCommand { } else { player.connect(vChannel); event.getMessage().delete().queue(); - player.play(args.split(" ")[0], event.getTextChannel(), false); + player.play(args.split(" ")[0], event.getTextChannel(), event.getMember(), false); } } else event.getTextChannel().sendMessage("You are not in a voice channel").queue(); From 66957f0eeb08463f18869e43caf8396395095a58 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 4 Nov 2018 20:16:06 -0500 Subject: [PATCH 006/155] Missing files in last commit --- .../java/netneutrality/music/MusicManager.java | 14 ++++++-------- .../java/netneutrality/music/TrackScheduler.java | 14 +++++++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index c87b528..7d5ec38 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -14,9 +14,7 @@ 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 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.entities.*; import netneutrality.MusicBot; import netneutrality.handler.LogHandler; import netneutrality.utils.MessageFunction; @@ -85,6 +83,8 @@ public class MusicManager { stopMusic(); } + scheduler.resetTopic(); + Guild guild = MusicBot.getJDA().getGuildById(guildId); if (guild != null) { guild.getAudioManager().closeAudioConnection(); @@ -93,9 +93,7 @@ public class MusicManager { } public synchronized void stopMusic() { - if (scheduler.getTextChannel() != null) - scheduler.getTextChannel().getManager().setTopic(scheduler.topic).queue(); - + scheduler.resetTopic(); player.destroy(); } @@ -105,7 +103,7 @@ public class MusicManager { } } - public synchronized void play(String url, TextChannel channel, boolean silent ) { + public synchronized void play(String url, TextChannel channel, Member user, boolean silent ) { String identifier = SourceFinder.getIdentifier(url, channel); System.out.println(identifier); @@ -116,7 +114,7 @@ public class MusicManager { @Override public void trackLoaded(AudioTrack audioTrack) { if (!silent) - channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack)).queue(); + channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); scheduler.queue(audioTrack); diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 2c0221a..0d757a0 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -41,13 +41,25 @@ public class TrackScheduler extends AudioEventAdapter { public void setTextChannel(TextChannel channel) { this.channel = channel; - topic = channel.getTopic(); + + if (this.topic == null) { + this.topic = channel.getTopic(); + } + } public TextChannel getTextChannel() { return channel; } + public void resetTopic() { + if (this.channel != null) { + this.channel.getManager().setTopic(this.topic).queue(); + } + + this.topic = ""; + } + /** * Start the next track, stopping the current one if it is playing. */ From 2750f6f71d98aebafb3d467f8f30d1c960bee36c Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 4 Nov 2018 20:17:41 -0500 Subject: [PATCH 007/155] Simplified message model and refactored some class --- .../command/specific/DatabaseCommand.java | 13 ++++--------- .../netneutrality/command/specific/EvalMethod.java | 2 +- .../netneutrality/db/controllers/DBMessage.java | 4 ++-- src/main/java/netneutrality/db/models/MMessage.java | 10 ++++++++-- src/main/java/netneutrality/handler/LogHandler.java | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 3a7164a..96ba1a4 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -59,6 +59,8 @@ public class DatabaseCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String args) { + //TODO: Clean up the mess + event.getMessage().delete().queue(); if (!event.getAuthor().getDiscriminator().equals(Settings.getCreator().getDiscriminator())) return null; @@ -69,7 +71,7 @@ public class DatabaseCommand extends AbstractCommand { case "message": if (countArgs(args) > 1) { - event.getMessage().delete().queue(); + MMessage message = ((DBMessage) DBController.get("message")).getMessage(parseArgs(args, 1)); if (message != null) { EmbedBuilder embed = new EmbedBuilder(); @@ -97,14 +99,7 @@ public class DatabaseCommand extends AbstractCommand { } embed.setFooter("Guild : " + event.getGuild().getName(), null); - event.getAuthor().openPrivateChannel().queue(new Consumer() { - - @Override - public void accept(PrivateChannel t) { - t.sendMessage(embed.build()).queue(); - - } - }); + event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); } } diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 1ec4a28..01996ab 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -67,7 +67,7 @@ public class EvalMethod extends AbstractCommand { se.put("music", MusicManager.get(event.getGuild())); try { - event.getTextChannel().sendMessage(" Evaluated Successfully:\n```\n"+se.eval("(function() {with (imports) {\nreturn " + args + "\n}})();") + " ```").queue(); + event.getTextChannel().sendMessage(" Evaluated Successfully:\n```"+se.eval("(function() {with (imports) {\nreturn " + args + "\n}})();") + " ```").queue(); } catch(Exception e) { event.getTextChannel().sendMessage(" An exception was thrown:\n```\n"+e+" ```").queue(); diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index a2db481..0ad205f 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -47,7 +47,7 @@ public class DBMessage extends AbstractController { ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE messageId = ?", messageId); MTableModel table = MysqlDatabase.convertToTableModel(rs); if (table.getNbRows() > 0) { - return new MMessage(table.getRowModel(0).getItem(0), table.getRowModel(0).getItem(1), table.getRowModel(0).getItem(2), table.getRowModel(0).getItem(3), table.getRowModel(0).getItem(4), table.getRowModel(0).getItem(5)); + return new MMessage(table.getRowModel(0)); } @@ -61,7 +61,7 @@ public class DBMessage extends AbstractController { MTableModel table = MysqlDatabase.convertToTableModel(rs); if (table.getNbRows() > 0) { for (int row = 0; row < max; row++) { - messages.add(new MMessage(table.getRowModel(row).getItem(0), table.getRowModel(row).getItem(1), table.getRowModel(row).getItem(2), table.getRowModel(row).getItem(3), table.getRowModel(row).getItem(4), table.getRowModel(row).getItem(5))); + messages.add(new MMessage(table.getRowModel(row))); } } diff --git a/src/main/java/netneutrality/db/models/MMessage.java b/src/main/java/netneutrality/db/models/MMessage.java index a2b22b3..251c323 100644 --- a/src/main/java/netneutrality/db/models/MMessage.java +++ b/src/main/java/netneutrality/db/models/MMessage.java @@ -21,8 +21,14 @@ public class MMessage { this.editedMessage = ""; } - public MMessage() { - + public MMessage(MRowModel row) { + this.serverName = (String) row.getItem(0); + this.channelName = (String) row.getItem(1); + this.sender = (String) row.getItem(2); + this.dateSent = (String) row.getItem(3); + this.messageId = (String) row.getItem(4); + this.message = (String) row.getItem(5); + this.editedMessage = ""; } public MMessage(Object serverName, Object channelName, Object sender, Object dateSent, Object messageId, Object message) { diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index fa5e299..e207e50 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -13,7 +13,7 @@ public class LogHandler { public static void log(Exception e) { MusicBot.LOGGER.error(e.getMessage()); - Settings.getLogChannel().sendMessage("Error : " + e.getMessage()).queue(); + Settings.getLogChannel().sendMessage("Error : " + e).queue(); } } From 7fce8917123460a2bb2196947f3e78345b04e3b0 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 4 Nov 2018 20:21:58 -0500 Subject: [PATCH 008/155] Migrated settings to database and prepared for a onGuildJoin handler --- .../java/netneutrality/db/MysqlDatabase.java | 12 +++++++-- .../db/controllers/DBLogging.java | 10 ++++++++ .../netneutrality/utils/MessageFunction.java | 7 ++++-- .../java/netneutrality/utils/Settings.java | 25 ++++++------------- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index b66879f..acc279c 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -28,7 +28,7 @@ public class MysqlDatabase { connection = new MysqlConnector(dbName, "root", "localhost", "").connect().getConnection(); } catch (SQLException e) { MusicBot.LOGGER.error("Error connecting to database. Shutting down.."); - MusicBot.disconnect(); + MusicBot.shutdown(); System.exit(0); } } @@ -88,6 +88,15 @@ public class MysqlDatabase { return executeUpdate(sql, params); } + public boolean exists(String table, String key, String value) { + ResultSet rs = prepareAndExecute("SELECT 1 FROM " + table + " WHERE " + key + " = ?", value); + try { + return rs.next(); + } catch (SQLException e) { + return false; + } + } + private int executeUpdate(String sql, Object[] params) { try { PreparedStatement query = connection.prepareStatement(sql); @@ -190,7 +199,6 @@ public class MysqlDatabase { * Check if the database is closed. * * @return the connection status - * @throws SQLException */ public boolean isClosed() { try { diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java index d979d09..aefa1fb 100644 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ b/src/main/java/netneutrality/db/controllers/DBLogging.java @@ -7,10 +7,12 @@ package netneutrality.db.controllers; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.TextChannel; import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.db.AbstractController; +import netneutrality.db.DBController; import netneutrality.handler.LogHandler; import java.sql.ResultSet; @@ -19,6 +21,14 @@ import java.util.function.Consumer; public class DBLogging extends AbstractController { + public void logGuild(Guild g) { + ThreadManager.executor.submit(() -> { + if (!database.exists("guilds", "guild_id", g.getId())) { + database.insert("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), g.getName(), g.getOwner().getUser().getName()); + } + }); + } + public void getLoggingChannel(String serverId, Consumer success) { ThreadManager.executor.submit(() -> { TextChannel txt = null; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 9858fd6..e2abd35 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -7,6 +7,7 @@ package netneutrality.utils; */ import java.awt.*; +import java.time.OffsetDateTime; import java.util.List; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; @@ -42,16 +43,18 @@ public class MessageFunction { return false; } - public static MessageEmbed buildAddingTrackMessage(AudioTrack track) { + public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { EmbedBuilder message = new EmbedBuilder(); message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); message.addField("Track title :", track.getInfo().title, false); + message.setFooter("Requested by " + user.getUser().getName(), ""); + message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static void checkBlacklist(String guildId, Message message, TextChannel channel,String msg) { + public static void checkBlacklist(String guildId, Message message, TextChannel channel, String msg) { try { ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guildId, mBlacklists -> { if (!mBlacklists.isEmpty()) { diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index e359063..fffac7b 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -3,34 +3,25 @@ package netneutrality.utils; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.entities.User; +import netneutrality.MusicBot; +import netneutrality.db.DBController; +import netneutrality.db.controllers.DBSettings; public class Settings { public static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - public static String PREFIX = "$"; - private static User owner; - private static Guild ownerGuild; - private static TextChannel logChannel; - + public static String PREFIX = ((DBSettings) DBController.get("settings")).getSettingsByKey("prefix"); + public static User getCreator() { - return owner; - } - - public static void setCreator(User creator) { - Settings.owner = creator; + return MusicBot.getJDA().getUserById(((DBSettings) DBController.get("settings")).getSettingsByKey("owner")); } public static Guild getOwnerGuild() { - return ownerGuild; - } - - public static void setOwnerGuild(Guild ownerGuild) { - Settings.ownerGuild = ownerGuild; - logChannel = ownerGuild.getTextChannelById("400383009330823179"); + return MusicBot.getJDA().getGuildById(((DBSettings) DBController.get("settings")).getSettingsByKey("ownerguild")); } public static TextChannel getLogChannel() { - return logChannel; + return MusicBot.getJDA().getTextChannelById(((DBSettings) DBController.get("settings")).getSettingsByKey("errorchannel")); } From 3b95b44f3050dd67406bcd1c61dfeab674114e14 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 4 Nov 2018 20:32:50 -0500 Subject: [PATCH 009/155] Added config for build --- src/main/resources/META-INF/MANIFEST.MF | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/resources/META-INF/MANIFEST.MF diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..6d311f9 --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: netneutrality.MusicBot + From 3885367a5af0aeb8b78533b9eee824727c6f130d Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 4 Nov 2018 21:05:30 -0500 Subject: [PATCH 010/155] Updated JDA and lavaplayer --- pom.xml | 14 +++++++++++--- src/main/java/netneutrality/MusicBot.java | 1 - src/main/java/netneutrality/http/WebModule.java | 1 + .../music/AudioPlayerSendHandler.java | 2 +- .../java/netneutrality/utils/MessageFunction.java | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 99df7a5..058e058 100644 --- a/pom.xml +++ b/pom.xml @@ -28,15 +28,23 @@ net.dv8tion JDA - 3.5.0_327 + 3.8.1_437 com.squareup.okhttp3 okhttp - 3.9.1 + 3.11.0 + + + org.json + json + 20180813 + + + org.reflections reflections @@ -72,7 +80,7 @@ com.sedmelluq lavaplayer - 1.2.51 + 1.3.10 junit diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index ab30ea3..34e9221 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -12,7 +12,6 @@ import netneutrality.handler.LogHandler; import netneutrality.handler.NewCommandListener; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; -import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index 22d6bb5..28d0ca9 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -5,6 +5,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; + import java.io.IOException; import java.util.List; import java.util.Map; diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index 0db92a7..6af2974 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -41,7 +41,7 @@ public class AudioPlayerSendHandler implements AudioSendHandler { lastFrame = audioPlayer.provide(); } - byte[] data = lastFrame != null ? lastFrame.data : null; + byte[] data = lastFrame != null ? lastFrame.getData() : null; lastFrame = null; return data; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index e2abd35..0bdd585 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -48,7 +48,7 @@ public class MessageFunction { message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); message.addField("Track title :", track.getInfo().title, false); - message.setFooter("Requested by " + user.getUser().getName(), ""); + message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); From d95b4c40d0d6940a995c94ae5489ead1748e5ea1 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 17 Mar 2019 16:20:10 -0400 Subject: [PATCH 011/155] Modified token getter --- src/main/java/netneutrality/MusicBot.java | 22 ++++++++++--------- .../java/netneutrality/utils/Settings.java | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 34e9221..1175d30 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -5,13 +5,13 @@ import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; import net.dv8tion.jda.core.entities.Game; import netneutrality.db.DBController; -import netneutrality.db.controllers.DBSettings; import netneutrality.handler.ConsoleHandler; import netneutrality.handler.EditHandler; import netneutrality.handler.LogHandler; import netneutrality.handler.NewCommandListener; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; +import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,20 +20,22 @@ import javax.security.auth.login.LoginException; public class MusicBot { private static JDA jda; - public static Logger LOGGER = LoggerFactory.getLogger(NewCommandListener.class); + public static Logger LOGGER = LoggerFactory.getLogger(MusicBot.class); public static void main(String[] args) { System.setProperty("log4j.skipJansi", "false"); DBController.init(); - String token = ((DBSettings) DBController.get("settings")).getSettingsByKey("token"); - try { - jda = new JDABuilder(AccountType.BOT).setToken(token).buildBlocking(); - } catch (LoginException | IllegalArgumentException | InterruptedException e) { - LOGGER.error(e.getMessage()); + jda = new JDABuilder(AccountType.BOT).setToken(Settings.TOKEN).build(); + jda.awaitReady(); + } catch (LoginException | IllegalArgumentException e) { LogHandler.log(e); + } catch (InterruptedException e) { + LOGGER.error(e.getMessage()); } + + jda.getPresence().setGame(Game.watching("me load...")); jda.addEventListener(new NewCommandListener(), new EditHandler()); @@ -48,7 +50,6 @@ public class MusicBot { case "quit": shutdown(); - System.exit(0); break; } @@ -56,12 +57,13 @@ public class MusicBot { } public static void shutdown() { - System.out.println("Shutting down..."); + LOGGER.info("[Net Neutrality] Shutting down..."); MusicManager.disconnectPlayers(); disconnect(); DBController.shutdown(); ThreadManager.shutdownExecutor(); - System.out.println("Shutdown complete"); + LOGGER.info("[Net Neutrality] Shutdown complete"); + System.exit(0); } public static JDA getJDA() { diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index fffac7b..e6de21f 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -11,6 +11,7 @@ public class Settings { public static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; public static String PREFIX = ((DBSettings) DBController.get("settings")).getSettingsByKey("prefix"); + public static final String TOKEN = ((DBSettings) DBController.get("settings")).getSettingsByKey("token"); public static User getCreator() { return MusicBot.getJDA().getUserById(((DBSettings) DBController.get("settings")).getSettingsByKey("owner")); From 32d65af2cc9df10e713beeb9ac29323cd80de157 Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 17 Mar 2019 16:21:23 -0400 Subject: [PATCH 012/155] Added dynamic help command --- .../command/basic/HelpCommand.java | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 4adc295..cbd391c 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -14,8 +14,6 @@ import netneutrality.command.Visibility; import netneutrality.utils.Settings; public class HelpCommand extends AbstractCommand { - - private String help = ""; public HelpCommand() { @@ -23,53 +21,44 @@ public class HelpCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String args) { - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.green); - embed.addField("Commands for Net Neutrality", help, false); - - event.getTextChannel().sendMessage(new MessageBuilder().append(event.getAuthor()).append(" help has been sent your way!").build()).queue(); - - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); return null; } public void sendHelp(HashMap commands, HashMap alias, User user, MessageChannel channel) { + StringBuilder help = new StringBuilder(); + for (AbstractCommand command : commands.values()) { if (command.getUsage() != null) - help += Settings.PREFIX + command.getCommand() + " (: " + command.getUsage() + "\n"; + help.append(Settings.PREFIX).append(command.getCommand()).append(" (: ").append(command.getUsage()).append("\n"); } - EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.green); - embed.addField("Commands for Net Neutrality", help, false); + embed.addField("Commands for Net Neutrality", help.toString(), false); if (channel instanceof TextChannel) channel.sendMessage(new MessageBuilder().append(user).append(" help has been sent your way!").build()).queue(); + user.openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); } @Override public boolean needAdmin() { - // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "help"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[0]; } From b249e89b56215850a94c505b26752ed2e287069c Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 17 Mar 2019 16:22:28 -0400 Subject: [PATCH 013/155] Refactored code --- src/main/java/netneutrality/StatusThread.java | 32 --- .../java/netneutrality/ThreadManager.java | 4 +- .../command/basic/PingCommand.java | 4 - .../command/crypto/BitcoinPriceCommand.java | 4 - .../command/crypto/EthereumPriceCommand.java | 4 - .../command/crypto/LitecoinPriceCommand.java | 4 - .../command/message/BlacklistCommand.java | 11 - .../command/message/PruneCommand.java | 8 - .../command/specific/DatabaseCommand.java | 8 - .../command/specific/NiggerCommand.java | 8 - .../command/specific/ShutdownCommand.java | 8 - .../netneutrality/db/AbstractController.java | 2 +- .../java/netneutrality/db/DBController.java | 4 +- .../java/netneutrality/db/MysqlDatabase.java | 6 + .../db/controllers/DBBlacklist.java | 219 +++++++++--------- .../netneutrality/db/models/MRowModel.java | 4 + .../handler/ServerJoinHandler.java | 21 ++ .../netneutrality/http/server/WebApi.java | 2 +- src/main/resources/log4j2.xml | 2 +- .../netneutrality/db/MysqlDatabaseTest.java | 30 +++ 20 files changed, 177 insertions(+), 208 deletions(-) delete mode 100644 src/main/java/netneutrality/StatusThread.java create mode 100644 src/main/java/netneutrality/handler/ServerJoinHandler.java create mode 100644 src/test/java/netneutrality/db/MysqlDatabaseTest.java diff --git a/src/main/java/netneutrality/StatusThread.java b/src/main/java/netneutrality/StatusThread.java deleted file mode 100644 index 1c8af3f..0000000 --- a/src/main/java/netneutrality/StatusThread.java +++ /dev/null @@ -1,32 +0,0 @@ -package netneutrality; - -import net.dv8tion.jda.core.OnlineStatus; -import net.dv8tion.jda.core.managers.Presence; - -public class StatusThread implements Runnable { - - private Presence status; - - public StatusThread(Presence pr) { - this.status = pr; - } - - @Override - public void run() { - try { - while (true) { - status.setStatus(OnlineStatus.ONLINE); - Thread.sleep(10000); - status.setStatus(OnlineStatus.IDLE); - Thread.sleep(10000); - status.setStatus(OnlineStatus.DO_NOT_DISTURB); - Thread.sleep(10000); - } - - } catch (InterruptedException e) { - e.printStackTrace(); - } - - } - -} diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index bd2a69d..614c5e0 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit; public class ThreadManager { public static final ExecutorService executor = Executors.newSingleThreadExecutor(); - public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); public static void shutdownExecutor() { try { @@ -23,7 +23,7 @@ public class ThreadManager { executor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.err.println("[Executor] Running tasks interrupted!"); + System.err.println("[Executor] Running tasks interrupted"); } finally { if (!executor.isTerminated()) { diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 2bff225..3b13a5d 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -21,25 +21,21 @@ public class PingCommand extends AbstractCommand { @Override public boolean needAdmin() { - // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "ping"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[0]; } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 1156a69..03edff2 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -68,25 +68,21 @@ public class BitcoinPriceCommand extends AbstractCommand { @Override public boolean needAdmin() { - // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "bitcoin"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[] {"btc"}; } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 5852dc3..7ae2728 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -60,25 +60,21 @@ public class EthereumPriceCommand extends AbstractCommand { @Override public boolean needAdmin() { - // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "ethereum"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[] {"eth"}; } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 5636395..fa590f6 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -60,25 +60,21 @@ public class LitecoinPriceCommand extends AbstractCommand { @Override public boolean needAdmin() { - // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "litecoin"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[] {"ltc"}; } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 970ad80..ce71bc6 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -1,37 +1,26 @@ package netneutrality.command.message; -import java.util.ArrayList; -import java.util.function.Consumer; - import net.dv8tion.jda.core.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; -import netneutrality.handler.LogHandler; public class BlacklistCommand extends AbstractCommand { - - public BlacklistCommand() { - // TODO Auto-generated constructor stub - } @Override public boolean needAdmin() { - // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "blacklist"; } diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index 21d84d1..fbe9188 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -7,31 +7,23 @@ import netneutrality.utils.ChannelFunction; public class PruneCommand extends AbstractCommand { - public PruneCommand() { - // TODO Auto-generated constructor stub - } - @Override public boolean needAdmin() { - // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "prune"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[] {"purge"}; } diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 96ba1a4..ceae448 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -19,31 +19,23 @@ import netneutrality.utils.Settings; public class DatabaseCommand extends AbstractCommand { - public DatabaseCommand() { - // TODO Auto-generated constructor stub - } - @Override public boolean needAdmin() { - // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "database"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[] { "db" }; } diff --git a/src/main/java/netneutrality/command/specific/NiggerCommand.java b/src/main/java/netneutrality/command/specific/NiggerCommand.java index 9d33f19..11d09ca 100644 --- a/src/main/java/netneutrality/command/specific/NiggerCommand.java +++ b/src/main/java/netneutrality/command/specific/NiggerCommand.java @@ -6,10 +6,6 @@ import netneutrality.command.Visibility; public class NiggerCommand extends AbstractCommand { - public NiggerCommand() { - - } - @Override public String execute(MessageReceivedEvent event, String args) { event.getMessage().delete().queue(); @@ -20,25 +16,21 @@ public class NiggerCommand extends AbstractCommand { @Override public boolean needAdmin() { - // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return true; } @Override public String getCommand() { - // TODO Auto-generated method stub return "nigger"; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return new String[0]; } diff --git a/src/main/java/netneutrality/command/specific/ShutdownCommand.java b/src/main/java/netneutrality/command/specific/ShutdownCommand.java index 8536f2e..23dd64f 100644 --- a/src/main/java/netneutrality/command/specific/ShutdownCommand.java +++ b/src/main/java/netneutrality/command/specific/ShutdownCommand.java @@ -5,32 +5,24 @@ import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; public class ShutdownCommand extends AbstractCommand { - - public ShutdownCommand() { - // TODO Auto-generated constructor stub - } @Override public boolean needAdmin() { - // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { - // TODO Auto-generated method stub return false; } @Override public String getCommand() { - // TODO Auto-generated method stub return null; } @Override public String[] getAlias() { - // TODO Auto-generated method stub return null; } diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/netneutrality/db/AbstractController.java index 75fd1d5..1bcdd72 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/netneutrality/db/AbstractController.java @@ -5,7 +5,7 @@ public abstract class AbstractController { protected MysqlDatabase database; /** - * The controller name to be used in {@link DBController} get(String controller) method + * The controller name to be used in {@link DBController#get(String controller)} method * * @return String */ diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 07e0656..1d96ddd 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -56,9 +56,7 @@ public class DBController { public static void shutdown() { try { database.close(); - } catch (SQLException e) { - e.printStackTrace(); - } + } catch (SQLException | NullPointerException ignored) { } } /** diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index acc279c..39315f0 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -41,6 +41,8 @@ public class MysqlDatabase { * @return {@link ResultSet} */ public ResultSet query(String query) { + MusicBot.LOGGER.debug("Query: " + query); + Statement stmt; try { stmt = connection.createStatement(); @@ -98,6 +100,8 @@ public class MysqlDatabase { } private int executeUpdate(String sql, Object[] params) { + MusicBot.LOGGER.debug("Query: " + sql); + try { PreparedStatement query = connection.prepareStatement(sql); resolveParameters(query, params); @@ -118,6 +122,8 @@ public class MysqlDatabase { * @return a ResultSet object, which can be converted to an model using {@link MysqlDatabase#convertToTableModel(ResultSet)} */ public ResultSet prepareAndExecute(String sql, Object... params) { + MusicBot.LOGGER.debug("Query: " + sql); + try { PreparedStatement query = connection.prepareStatement(sql); resolveParameters(query, params); diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 09cfe57..29b7294 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -14,129 +14,130 @@ import netneutrality.db.models.MTableModel; public class DBBlacklist extends AbstractController { - public DBBlacklist() { - - } - - /** - * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class - * - * @return {@link MysqlDatabase} - */ - public MysqlDatabase getDatabase() { - return database; - } + public DBBlacklist() { - public void add(MBlacklist obj, Consumer success) { - ThreadManager.executor.submit(() -> { - if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { - database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); - success.accept(true); - } else { - success.accept(false); - } + } - }); + /** + * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class + * + * @return {@link MysqlDatabase} + */ + public MysqlDatabase getDatabase() { + return database; + } + public void add(MBlacklist obj, Consumer success) { + ThreadManager.executor.submit(() -> { + if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { + database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); + success.accept(true); + } else { + success.accept(false); + } - } - - public void delete(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - System.out.println("true"); - database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); - success.accept(true); - } else { - success.accept(false); - } - }); - - } - - public void enable(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); - success.accept(true); - } else { - success.accept(false); - } - }); - } - - public void disable(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); - success.accept(true); - } else { - success.accept(false); - } - }); - } - - public void getBlacklistForWord(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - MBlacklist blacklisted = null; - if (isAlreadyBlacklisted(word, serverId)) { - ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); - MTableModel table = database.convertToTableModel(rs); - - if (table.getNbRows() > 0) { - blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3), - (String) table.getRow(0).get(1)); - } - } else { - throw new RuntimeException("Is not blacklisted"); - } - - success.accept(blacklisted); }); - } - public void getBlacklistFromServer(String serverId, Consumer> success) { - ThreadManager.executor.submit(() -> { - ArrayList output = new ArrayList<>(); + } - try { - ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId); - MTableModel model = MysqlDatabase.convertToTableModel(rs); + public void delete(String word, String serverId, Consumer success) { + ThreadManager.executor.submit(() -> { + if (isAlreadyBlacklisted(word, serverId)) { + System.out.println("true"); + database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + success.accept(true); + } else { + success.accept(false); + } + }); - if (model.getNbRows() != 0) { - for (int row = 0; row < model.getNbRows(); row++) { - output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), - (String) model.getRow(row).get(1))); - } - } else { - throw new RuntimeException("Blacklist is empty"); - } + } - } catch (NullPointerException | IndexOutOfBoundsException ignored) { } + public void enable(String word, String serverId, Consumer success) { - success.accept(output); - }); - } + ThreadManager.executor.submit(() -> { + if (isAlreadyBlacklisted(word, serverId)) { + database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); + success.accept(true); + } else { + success.accept(false); + } + }); + } - public boolean isAlreadyBlacklisted(String word, String serverId) { - ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + public void disable(String word, String serverId, Consumer success) { + ThreadManager.executor.submit(() -> { + if (isAlreadyBlacklisted(word, serverId)) { + database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); + success.accept(true); + } else { + success.accept(false); + } + }); + } - try { - if (rs.next()) { - return rs.getInt(1) != 0; - } - } catch (SQLException e) { - //TODO: error log - e.printStackTrace(); - } + public void getBlacklistForWord(String word, String serverId, Consumer success) { + ThreadManager.executor.submit(() -> { + MBlacklist blacklisted = null; - return false; - } + if (isAlreadyBlacklisted(word, serverId)) { + ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + MTableModel table = database.convertToTableModel(rs); - @Override - public String getControllerName() { - return "blacklist"; - } + if (table.getNbRows() > 0) { + blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3), + (String) table.getRow(0).get(1)); + } + } + + success.accept(blacklisted); + }); + + } + + public void getBlacklistFromServer(String serverId, Consumer> success) { + ThreadManager.executor.submit(() -> { + ArrayList output = new ArrayList<>(); + + try { + ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId); + MTableModel model = MysqlDatabase.convertToTableModel(rs); + + if (model.getNbRows() != 0) { + for (int row = 0; row < model.getNbRows(); row++) { + output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), + (String) model.getRow(row).get(1))); + } + } else { + throw new RuntimeException("Blacklist is empty"); + } + + } catch (NullPointerException | IndexOutOfBoundsException ignored) { } + + success.accept(output); + }); + + } + + public boolean isAlreadyBlacklisted(String word, String serverId) { + ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + + try { + if (rs.next()) { + return rs.getInt(1) != 0; + } + } catch (SQLException e) { + //TODO: error log + e.printStackTrace(); + } + + return false; + } + + @Override + public String getControllerName() { + return "blacklist"; + } } diff --git a/src/main/java/netneutrality/db/models/MRowModel.java b/src/main/java/netneutrality/db/models/MRowModel.java index 4469bc1..0d0dae4 100644 --- a/src/main/java/netneutrality/db/models/MRowModel.java +++ b/src/main/java/netneutrality/db/models/MRowModel.java @@ -38,6 +38,10 @@ public class MRowModel { } } + public int count() { + return row.size(); + } + @Override public String toString() { return row.toString(); diff --git a/src/main/java/netneutrality/handler/ServerJoinHandler.java b/src/main/java/netneutrality/handler/ServerJoinHandler.java new file mode 100644 index 0000000..25f5154 --- /dev/null +++ b/src/main/java/netneutrality/handler/ServerJoinHandler.java @@ -0,0 +1,21 @@ +package netneutrality.handler; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.core.events.guild.GuildJoinEvent; +import net.dv8tion.jda.core.hooks.ListenerAdapter; + +public class ServerJoinHandler extends ListenerAdapter { + + @Override + public void onGuildJoin(GuildJoinEvent event){ + + + + } +} diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 2224b07..6aa372a 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -28,7 +28,7 @@ public class WebApi { server.createContext("/guild", new GuildBrowser()); server.setExecutor(null); server.start(); - MusicBot.LOGGER.debug("Web server started at [" + server.getAddress().getAddress().getAddress().toString() + "]"); + MusicBot.LOGGER.debug("Web server started at [" + server.getAddress().getAddress().toString() + "]"); } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index e0516ea..9bc2e7f 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -2,7 +2,7 @@ - + diff --git a/src/test/java/netneutrality/db/MysqlDatabaseTest.java b/src/test/java/netneutrality/db/MysqlDatabaseTest.java new file mode 100644 index 0000000..f11bb4b --- /dev/null +++ b/src/test/java/netneutrality/db/MysqlDatabaseTest.java @@ -0,0 +1,30 @@ +package netneutrality.db; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MysqlDatabaseTest { + + MysqlDatabase db; + + @Before + public void setUp() throws Exception { + db = new MysqlDatabase("discord"); + } + + @Test + public void exists() { + + Assert.assertTrue(db.exists("settings", "skey", "prefix")); + } +} From 35290a83dabac46cdbd2b196efad67b92b7d8cae Mon Sep 17 00:00:00 2001 From: Anthony Robert Date: Sun, 17 Mar 2019 16:23:32 -0400 Subject: [PATCH 014/155] Removed command interfering with blacklist --- .../command/specific/NiggerCommand.java | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 src/main/java/netneutrality/command/specific/NiggerCommand.java diff --git a/src/main/java/netneutrality/command/specific/NiggerCommand.java b/src/main/java/netneutrality/command/specific/NiggerCommand.java deleted file mode 100644 index 11d09ca..0000000 --- a/src/main/java/netneutrality/command/specific/NiggerCommand.java +++ /dev/null @@ -1,47 +0,0 @@ -package netneutrality.command.specific; - -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.Visibility; - -public class NiggerCommand extends AbstractCommand { - - @Override - public String execute(MessageReceivedEvent event, String args) { - event.getMessage().delete().queue(); - event.getTextChannel().sendMessage("Not in my christian server").queue(); - return null; - - } - - @Override - public boolean needAdmin() { - return false; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommand() { - return "nigger"; - } - - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public String getUsage() { - return null; - } - - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } - -} From 5ae7e8f819af100ce2f8a088fe236311a9d2ef2c Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 8 Jan 2020 20:30:20 -0500 Subject: [PATCH 015/155] Starting to implement async in db actions --- .../java/netneutrality/ThreadManager.java | 8 +- .../command/message/BlacklistCommand.java | 2 +- .../netneutrality/db/AsyncMySqlAction.java | 87 ++++++++++++++++++ .../java/netneutrality/db/DBController.java | 4 +- .../java/netneutrality/db/MysqlDatabase.java | 40 ++++++-- .../db/controllers/DBBlacklist.java | 91 ++++++++++--------- .../db/controllers/DBMessage.java | 10 +- .../db/controllers/DBSettings.java | 27 ++---- 8 files changed, 190 insertions(+), 79 deletions(-) create mode 100644 src/main/java/netneutrality/db/AsyncMySqlAction.java diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 614c5e0..4a4239c 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -18,19 +18,19 @@ public class ThreadManager { public static void shutdownExecutor() { try { - System.out.println("[Executor] Shutting down..."); + MusicBot.LOGGER.info("[Executor] Shutting down..."); executor.shutdown(); executor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.err.println("[Executor] Running tasks interrupted"); + MusicBot.LOGGER.warn("[Executor] Running tasks interrupted"); } finally { if (!executor.isTerminated()) { - System.err.println("[Executor] Forcing shutdown of running tasks.."); + MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks.."); } executor.shutdownNow(); - System.out.println("[Executor] Shutdown finished!"); + MusicBot.LOGGER.info("[Executor] Shutdown finished!"); } } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index ce71bc6..e54836c 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -48,7 +48,7 @@ public class BlacklistCommand extends AbstractCommand { switch (parseArgs(args, 0)) { case "get": - event.getTextChannel().sendMessage("Retreiving list, please wait...").queue(t -> { + event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { try { diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java new file mode 100644 index 0000000..fab9ce2 --- /dev/null +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -0,0 +1,87 @@ +package netneutrality.db; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.MusicBot; +import netneutrality.ThreadManager; +import netneutrality.db.models.MTableModel; + +import java.sql.ResultSet; +import java.util.function.Consumer; + +public class AsyncMySqlAction { + + private String sqlString; + private Object[] params; + private MysqlDatabase.CommandType type; + private MysqlDatabase db; + + public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) { + this.db = db; + this.sqlString = sql; + this.params = params; + + type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]); + } + + + public void async(Consumer success) { + switch (type) { + case INSERT: + ThreadManager.executor.submit(() -> { + db.insert(this.sqlString, this.params); + }); + break; + case UPDATE: + ThreadManager.executor.submit(() -> { + db.update(this.sqlString, this.params); + }); + break; + + case DELETE: + ThreadManager.executor.submit(() -> { + db.delete(this.sqlString, this.params); + }); + break; + + case SELECT: + ThreadManager.executor.submit(() -> { + ResultSet result = db.prepareAndExecute(this.sqlString, this.params); + MTableModel table = MysqlDatabase.convertToTableModel(result); + + success.accept(table); + }); + break; + } + } + + public void async() { + async(o -> { + }); + } + + public MTableModel blocking() { + switch (type) { + case INSERT: + db.insert(this.sqlString, this.params); + + case UPDATE: + db.update(this.sqlString, this.params); + + case DELETE: + db.delete(this.sqlString, this.params); + + case SELECT: + ResultSet result = db.prepareAndExecute(this.sqlString, this.params); + + return MysqlDatabase.convertToTableModel(result); + } + + return null; + } +} diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 1d96ddd..ef37578 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -13,7 +13,7 @@ import org.reflections.Reflections; /** * When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class - * A simple thread can't be used in this case because unpredictable errors might happen and some actions might not be executed. + * A simple thread can't be used in this case because overlapping actions might happen and won't be executed. */ public class DBController { @@ -23,7 +23,7 @@ public class DBController { private final static HashMap controllers = new HashMap<>(); - private static MysqlDatabase database = new MysqlDatabase("discord"); + private static MysqlDatabase database = new MysqlDatabase("netneutrality"); /** * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 39315f0..2de9858 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -9,8 +9,10 @@ import java.sql.Statement; import java.sql.Timestamp; import java.sql.Types; import java.util.Calendar; +import java.util.function.Consumer; import netneutrality.MusicBot; +import netneutrality.ThreadManager; import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; import netneutrality.exceptions.UnimplementedParameterException; @@ -18,10 +20,24 @@ import netneutrality.handler.LogHandler; public class MysqlDatabase { + protected enum CommandType { + SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"); + + private String type; + + CommandType(String type) { + this.type = type; + } + + public static CommandType stringToType(String str) { + return CommandType.valueOf(str); + } + } + private Connection connection; private String dbName; - MysqlDatabase(String dbName) { + protected MysqlDatabase(String dbName) { this.dbName = dbName; try { MusicBot.LOGGER.info("Connecting to database..."); @@ -65,7 +81,7 @@ public class MysqlDatabase { public int update(String sql, Object... params) { return executeUpdate(sql, params); } - + /** * Execute an INSERT statement with the specified parameters. * In the SQL query, where there is a parameter to be included, you need to replace it with ? @@ -77,7 +93,7 @@ public class MysqlDatabase { public int insert(String sql, Object... params) { return executeUpdate(sql, params); } - + /** * Execute a DELETE statement with the specified parameters. * In the SQL query, where there is a parameter to be included, you need to replace it with ? @@ -100,7 +116,6 @@ public class MysqlDatabase { } private int executeUpdate(String sql, Object[] params) { - MusicBot.LOGGER.debug("Query: " + sql); try { PreparedStatement query = connection.prepareStatement(sql); @@ -119,7 +134,7 @@ public class MysqlDatabase { * * @param sql The SQL query to execute * @param params The parameters to include in the query - * @return a ResultSet object, which can be converted to an model using {@link MysqlDatabase#convertToTableModel(ResultSet)} + * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} */ public ResultSet prepareAndExecute(String sql, Object... params) { MusicBot.LOGGER.debug("Query: " + sql); @@ -129,12 +144,25 @@ public class MysqlDatabase { resolveParameters(query, params); return query.executeQuery(); } catch (SQLException e) { + MusicBot.LOGGER.error(e.toString()); e.printStackTrace(); } return null; } + /** + * Execute a SELECT statement with the specified parameters. + * In the SQL query, where there is a parameter to be included, you need to replace it with ? + * + * @param sql The SQL query to execute + * @param params The parameters to include in the query + * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} + */ + public AsyncMySqlAction prepareAndExecuteAsync(String sql, Object... params) { + return new AsyncMySqlAction(this, sql, params); + } + /** * Insert parameters (specified with a ?) in the SQL statement * Taken from https://github.com/Kaaz/DiscordBot/blob/master/src/main/java/emily/db/MySQLAdapter.java#resolveParameters @@ -182,7 +210,7 @@ public class MysqlDatabase { * @throws SQLException */ public void close() throws SQLException { - System.out.println("Closing database..."); + MusicBot.LOGGER.info("Closing database..."); connection.close(); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 29b7294..70ccbd8 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -3,8 +3,10 @@ package netneutrality.db.controllers; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.db.AbstractController; import netneutrality.db.DBController; @@ -28,26 +30,25 @@ public class DBBlacklist extends AbstractController { } public void add(MBlacklist obj, Consumer success) { - ThreadManager.executor.submit(() -> { - if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { - database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); + isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> { + if (blacklisted == 0) { + database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()).async(); success.accept(true); } else { success.accept(false); } - }); - } public void delete(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - System.out.println("true"); - database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + isAlreadyBlacklisted(word, serverId, blacklisted -> { + if (blacklisted >= 1) { + database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(); + MusicBot.LOGGER.info("blacklisted"); success.accept(true); } else { + MusicBot.LOGGER.info("not blacklisted"); success.accept(false); } }); @@ -56,26 +57,32 @@ public class DBBlacklist extends AbstractController { public void enable(String word, String serverId, Consumer success) { - - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); + isAlreadyBlacklisted(word, serverId, blacklisted -> { + if (blacklisted >= 1) { + database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId).async(); + MusicBot.LOGGER.info("enabled"); success.accept(true); } else { + MusicBot.LOGGER.info("error enabling"); success.accept(false); } }); + } public void disable(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); + + isAlreadyBlacklisted(word, serverId, blacklisted -> { + if (blacklisted >= 1) { + database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId).async(); + MusicBot.LOGGER.info("disabled"); success.accept(true); } else { + MusicBot.LOGGER.info("error disabled"); success.accept(false); } }); + } public void getBlacklistForWord(String word, String serverId, Consumer success) { @@ -84,7 +91,7 @@ public class DBBlacklist extends AbstractController { if (isAlreadyBlacklisted(word, serverId)) { ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); - MTableModel table = database.convertToTableModel(rs); + MTableModel table = MysqlDatabase.convertToTableModel(rs); if (table.getNbRows() > 0) { blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3), @@ -98,42 +105,44 @@ public class DBBlacklist extends AbstractController { } public void getBlacklistFromServer(String serverId, Consumer> success) { - ThreadManager.executor.submit(() -> { + + database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> { ArrayList output = new ArrayList<>(); - try { - ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId); - MTableModel model = MysqlDatabase.convertToTableModel(rs); - - if (model.getNbRows() != 0) { - for (int row = 0; row < model.getNbRows(); row++) { - output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), - (String) model.getRow(row).get(1))); - } - } else { - throw new RuntimeException("Blacklist is empty"); + if (model.getNbRows() != 0) { + for (int row = 0; row < model.getNbRows(); row++) { + output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), + (String) model.getRow(row).get(1))); } - - } catch (NullPointerException | IndexOutOfBoundsException ignored) { } + } success.accept(output); }); } - public boolean isAlreadyBlacklisted(String word, String serverId) { - ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + @Deprecated + private boolean isAlreadyBlacklisted(String word, String serverId) { + AtomicBoolean result = new AtomicBoolean(); - try { - if (rs.next()) { - return rs.getInt(1) != 0; + database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> { + if (!table.isEmpty()) { + result.set((int) table.getRowModel(0).getItem(0) != 0); } - } catch (SQLException e) { - //TODO: error log - e.printStackTrace(); - } + }); - return false; + return result.get(); + } + + private void isAlreadyBlacklisted(String word, String serverId, Consumer result) { + + database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> { + if (!table.isEmpty()) { + int count = Integer.parseInt(table.getRowModel(0).getItem(0).toString()); + + result.accept(count); + } + }); } @Override diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 0ad205f..91c8faf 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -28,18 +28,12 @@ public class DBMessage extends AbstractController { } public void log(String servername, String channelname, String username, String datesent, String messageId, String message) { - - ThreadManager.executor.submit(() -> { - database.insert("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null); - }); + database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null).async(); } public void logEdit(String messageId, String newMessage) { - - ThreadManager.executor.submit(() -> { - database.update("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId); - }); + database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async(); } diff --git a/src/main/java/netneutrality/db/controllers/DBSettings.java b/src/main/java/netneutrality/db/controllers/DBSettings.java index 96a4185..df5c4ba 100644 --- a/src/main/java/netneutrality/db/controllers/DBSettings.java +++ b/src/main/java/netneutrality/db/controllers/DBSettings.java @@ -1,10 +1,8 @@ package netneutrality.db.controllers; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import netneutrality.ThreadManager; import netneutrality.db.AbstractController; import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MTableModel; @@ -13,26 +11,21 @@ public class DBSettings extends AbstractController { public void getSettingsByKey(String key, Consumer success) { - ThreadManager.executor.submit(() -> { - Object value = null; + database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).async(table -> { + Object value = null; - ResultSet rs; - rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key); - MTableModel table = MysqlDatabase.convertToTableModel(rs); + if (table.getNbRows() == 1) { + value = table.getRowModel(0).getItem(0); + } - if (table.getNbRows() == 1) { - value = table.getRowModel(0).getItem(0); - } - - success.accept(value); - }); + success.accept(value); + }); } + @Deprecated public String getSettingsByKey(String key) { - ResultSet rs; - rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key); - MTableModel table = MysqlDatabase.convertToTableModel(rs); + MTableModel table = database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).blocking(); if (table.getNbRows() == 1) { return table.getRow(0).get(0).toString(); From 7e7a0b1b89e63ee08e8357f4a8e49379b3325bdb Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 8 Jan 2020 21:39:19 -0500 Subject: [PATCH 016/155] Update to JDA v4 --- pom.xml | 7 +- src/main/java/netneutrality/MusicBot.java | 98 ++++++++++--------- .../command/AbstractCommand.java | 2 +- .../netneutrality/command/Visibility.java | 6 +- .../command/basic/HelpCommand.java | 18 ++-- .../command/basic/PingCommand.java | 4 +- .../command/crypto/BitcoinPriceCommand.java | 4 +- .../command/crypto/EthereumPriceCommand.java | 4 +- .../command/crypto/LitecoinPriceCommand.java | 4 +- .../command/message/BlacklistCommand.java | 2 +- .../command/message/PruneCommand.java | 2 +- .../command/music/BitconnectCommand.java | 6 +- .../command/music/DeleteQueueCommand.java | 6 +- .../command/music/JoinCommand.java | 6 +- .../command/music/LeaveCommand.java | 6 +- .../command/music/PlayCommand.java | 6 +- .../command/music/SkipCommand.java | 6 +- .../command/music/StopCommand.java | 6 +- .../command/music/VolumeCommand.java | 6 +- .../command/specific/DatabaseCommand.java | 8 +- .../command/specific/EvalMethod.java | 2 +- .../command/specific/LoggingCommand.java | 2 +- .../command/specific/SellyCommand.java | 2 +- .../command/specific/ShutdownCommand.java | 2 +- .../command/specific/TestCommand.java | 2 +- .../db/controllers/DBLogging.java | 4 +- .../netneutrality/handler/EditHandler.java | 8 +- .../handler/MessageRateLimit.java | 16 +-- .../handler/NewCommandListener.java | 12 ++- .../handler/ServerJoinHandler.java | 4 +- .../http/server/GuildBrowser.java | 4 +- .../music/AudioPlayerSendHandler.java | 8 +- .../netneutrality/music/MusicManager.java | 2 +- .../netneutrality/music/SourceFinder.java | 2 +- .../netneutrality/music/TrackScheduler.java | 2 +- .../netneutrality/utils/ChannelFunction.java | 15 +-- .../netneutrality/utils/MessageFunction.java | 4 +- .../java/netneutrality/utils/Settings.java | 6 +- .../netneutrality/utils/UserFunction.java | 6 +- 39 files changed, 158 insertions(+), 152 deletions(-) diff --git a/pom.xml b/pom.xml index 058e058..bfe2c10 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,6 @@ https://gitlab.xtremcommunity.com/nn.jar - jcenter @@ -28,13 +27,13 @@ net.dv8tion JDA - 3.8.1_437 + 4.1.0_81 com.squareup.okhttp3 okhttp - 3.11.0 + 3.13.0 @@ -80,7 +79,7 @@ com.sedmelluq lavaplayer - 1.3.10 + 1.3.33 junit diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 1175d30..b69c9ba 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -1,9 +1,10 @@ package netneutrality; -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.api.AccountType; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Activity; + import netneutrality.db.DBController; import netneutrality.handler.ConsoleHandler; import netneutrality.handler.EditHandler; @@ -12,6 +13,7 @@ import netneutrality.handler.NewCommandListener; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; import netneutrality.utils.Settings; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,61 +21,61 @@ import javax.security.auth.login.LoginException; public class MusicBot { - private static JDA jda; - public static Logger LOGGER = LoggerFactory.getLogger(MusicBot.class); - - public static void main(String[] args) { - System.setProperty("log4j.skipJansi", "false"); - DBController.init(); + private static JDA jda; + public static Logger LOGGER = LoggerFactory.getLogger(MusicBot.class); - try { - jda = new JDABuilder(AccountType.BOT).setToken(Settings.TOKEN).build(); - jda.awaitReady(); - } catch (LoginException | IllegalArgumentException e) { - LogHandler.log(e); - } catch (InterruptedException e) { - LOGGER.error(e.getMessage()); - } + public static void main(String[] args) { + System.setProperty("log4j.skipJansi", "false"); + DBController.init(); + + try { + jda = new JDABuilder(AccountType.BOT).setToken(Settings.TOKEN).build(); + jda.awaitReady(); + } catch (LoginException | IllegalArgumentException e) { + LogHandler.log(e); + } catch (InterruptedException e) { + LOGGER.error(e.getMessage()); + } - jda.getPresence().setGame(Game.watching("me load...")); - jda.addEventListener(new NewCommandListener(), new EditHandler()); + jda.getPresence().setActivity(Activity.watching("me load...")); + jda.addEventListener(new NewCommandListener(), new EditHandler()); - // WebApi webserver = new WebApi(); + // WebApi webserver = new WebApi(); - jda.getPresence().setGame(Game.watching("rape")); + jda.getPresence().setActivity(Activity.watching("rape")); - - ConsoleHandler consoleInput = new ConsoleHandler(); - switch (consoleInput.init()) { + ConsoleHandler consoleInput = new ConsoleHandler(); - case "quit": - shutdown(); - break; + switch (consoleInput.init()) { + + case "quit": + shutdown(); + break; } - } + } + + public static void shutdown() { + LOGGER.info("[Net Neutrality] Shutting down..."); + MusicManager.disconnectPlayers(); + disconnect(); + DBController.shutdown(); + ThreadManager.shutdownExecutor(); + LOGGER.info("[Net Neutrality] Shutdown complete"); + System.exit(0); + } + + public static JDA getJDA() { + return jda; + } + + public static void disconnect() { + if (jda != null) + jda.shutdown(); + } - public static void shutdown() { - LOGGER.info("[Net Neutrality] Shutting down..."); - MusicManager.disconnectPlayers(); - disconnect(); - DBController.shutdown(); - ThreadManager.shutdownExecutor(); - LOGGER.info("[Net Neutrality] Shutdown complete"); - System.exit(0); - } - - public static JDA getJDA() { - return jda; - } - - public static void disconnect() { - if (jda != null) - jda.shutdown(); - } - } diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index c3c00f6..2ffb9e9 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -3,7 +3,7 @@ package netneutrality.command; import java.util.Arrays; import java.util.List; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; public abstract class AbstractCommand { diff --git a/src/main/java/netneutrality/command/Visibility.java b/src/main/java/netneutrality/command/Visibility.java index 03723e6..a20df14 100644 --- a/src/main/java/netneutrality/command/Visibility.java +++ b/src/main/java/netneutrality/command/Visibility.java @@ -6,9 +6,9 @@ package netneutrality.command; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.MessageChannel; -import net.dv8tion.jda.core.entities.PrivateChannel; -import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.TextChannel; public enum Visibility { diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index cbd391c..cc2c340 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -1,18 +1,18 @@ package netneutrality.command.basic; -import java.awt.Color; -import java.util.HashMap; - -import net.dv8tion.jda.core.EmbedBuilder; -import net.dv8tion.jda.core.MessageBuilder; -import net.dv8tion.jda.core.entities.MessageChannel; -import net.dv8tion.jda.core.entities.TextChannel; -import net.dv8tion.jda.core.entities.User; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.utils.Settings; +import java.awt.*; +import java.util.HashMap; + public class HelpCommand extends AbstractCommand { public HelpCommand() { diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 3b13a5d..6f6a9ea 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -1,6 +1,6 @@ package netneutrality.command.basic; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.MusicBot; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; @@ -13,7 +13,7 @@ public class PingCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String args) { if (countArgs(args) == 0) - event.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getPing() + " ms]").queue(); + event.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); return null; diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 03edff2..3d1ea18 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -7,8 +7,8 @@ import netneutrality.command.Visibility; import org.json.JSONException; import org.json.JSONObject; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.http.WebModule; diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 7ae2728..66cc77a 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -6,8 +6,8 @@ import java.util.function.Consumer; import netneutrality.command.Visibility; import org.json.JSONException; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.http.WebModule; diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index fa590f6..34cda87 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -6,8 +6,8 @@ import java.util.function.Consumer; import netneutrality.command.Visibility; import org.json.JSONException; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.http.WebModule; diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index e54836c..6f65dca 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -1,6 +1,6 @@ package netneutrality.command.message; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.db.DBController; diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index fbe9188..e09f1cc 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -1,6 +1,6 @@ package netneutrality.command.message; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.utils.ChannelFunction; diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 90536e1..11710ee 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index ad99c3f..2371432 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index ef9ae4f..1abdf57 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 8794c4e..eae40f2 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 6002727..022fea4 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index de217fa..21d9b83 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 9ae2ac0..4dccd0b 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 59d212d..84ce9cc 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -6,9 +6,9 @@ package netneutrality.command.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index ceae448..417b0c2 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -6,10 +6,10 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.function.Consumer; -import net.dv8tion.jda.core.EmbedBuilder; -import net.dv8tion.jda.core.entities.PrivateChannel; -import net.dv8tion.jda.core.entities.User; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.db.DBController; diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 01996ab..88575ba 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -6,7 +6,7 @@ package netneutrality.command.specific; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index a275657..dd8f520 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -1,6 +1,6 @@ package netneutrality.command.specific; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java index 7d6ae9d..7a4f802 100644 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ b/src/main/java/netneutrality/command/specific/SellyCommand.java @@ -6,7 +6,7 @@ package netneutrality.command.specific; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.db.DBController; diff --git a/src/main/java/netneutrality/command/specific/ShutdownCommand.java b/src/main/java/netneutrality/command/specific/ShutdownCommand.java index 23dd64f..09a28e5 100644 --- a/src/main/java/netneutrality/command/specific/ShutdownCommand.java +++ b/src/main/java/netneutrality/command/specific/ShutdownCommand.java @@ -1,6 +1,6 @@ package netneutrality.command.specific; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index 15b616e..c4f26b6 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -6,7 +6,7 @@ package netneutrality.command.specific; * This file is closed-source. It should not be distributed or copied in any way or form */ -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.utils.MessageFunction; diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java index aefa1fb..efc4c15 100644 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ b/src/main/java/netneutrality/db/controllers/DBLogging.java @@ -7,8 +7,8 @@ package netneutrality.db.controllers; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.db.AbstractController; diff --git a/src/main/java/netneutrality/handler/EditHandler.java b/src/main/java/netneutrality/handler/EditHandler.java index c6b285b..ab81501 100644 --- a/src/main/java/netneutrality/handler/EditHandler.java +++ b/src/main/java/netneutrality/handler/EditHandler.java @@ -2,9 +2,9 @@ package netneutrality.handler; import java.awt.Color; -import net.dv8tion.jda.core.EmbedBuilder; -import net.dv8tion.jda.core.events.message.MessageUpdateEvent; -import net.dv8tion.jda.core.hooks.ListenerAdapter; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageUpdateEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; import netneutrality.db.controllers.DBMessage; @@ -38,7 +38,7 @@ public class EditHandler extends ListenerAdapter { } editEmbed.setFooter("ID : " + event.getMessageId(), null); - editEmbed.setTimestamp(event.getMessage().getCreationTime()); + editEmbed.setTimestamp(event.getMessage().getTimeCreated()); event.getJDA().getTextChannelById(logChannel.toString()).sendMessage(editEmbed.build()).queue(); } diff --git a/src/main/java/netneutrality/handler/MessageRateLimit.java b/src/main/java/netneutrality/handler/MessageRateLimit.java index 7edd6ec..7751081 100644 --- a/src/main/java/netneutrality/handler/MessageRateLimit.java +++ b/src/main/java/netneutrality/handler/MessageRateLimit.java @@ -1,9 +1,9 @@ package netneutrality.handler; -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.entities.MessageChannel; -import net.dv8tion.jda.core.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.PrivateChannel; import java.time.OffsetDateTime; @@ -20,21 +20,21 @@ public class MessageRateLimit { if (lastSender == null || timestamp == null) { lastSender = member; - timestamp = message.getCreationTime(); + timestamp = message.getTimeCreated(); return false; } if (member.getUser().getId().equals(lastSender.getUser().getId())) { - if (message.getCreationTime().minusNanos(cooldown).isBefore(timestamp)) { + if (message.getTimeCreated().minusNanos(cooldown).isBefore(timestamp)) { lastSender = member; - timestamp = message.getCreationTime(); + timestamp = message.getTimeCreated(); message.delete().queue(); return true; } } lastSender = member; - timestamp = message.getCreationTime(); + timestamp = message.getTimeCreated(); return false; diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index 2e69b32..fe304c8 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -1,9 +1,11 @@ package netneutrality.handler; -import net.dv8tion.jda.core.entities.ChannelType; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; -import net.dv8tion.jda.core.hooks.ListenerAdapter; + + +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandManager; import netneutrality.command.Visibility; @@ -32,7 +34,7 @@ public class NewCommandListener extends ListenerAdapter { if (event.isFromType(ChannelType.TEXT)) { ((DBMessage) DBController.get("message")).log(event.getGuild().getName(), event.getTextChannel().getName(), event.getMember().getUser().getName(), - event.getMessage().getCreationTime().format(DateTimeFormatter.ofPattern(Settings.DATETIMEFORMAT)), event.getMessage().getId(), + event.getMessage().getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.DATETIMEFORMAT)), event.getMessage().getId(), event.getMessage().getContentDisplay().trim()); } diff --git a/src/main/java/netneutrality/handler/ServerJoinHandler.java b/src/main/java/netneutrality/handler/ServerJoinHandler.java index 25f5154..3cb8b6b 100644 --- a/src/main/java/netneutrality/handler/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/ServerJoinHandler.java @@ -7,8 +7,8 @@ package netneutrality.handler; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.core.events.guild.GuildJoinEvent; -import net.dv8tion.jda.core.hooks.ListenerAdapter; +import net.dv8tion.jda.api.events.guild.GuildJoinEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; public class ServerJoinHandler extends ListenerAdapter { diff --git a/src/main/java/netneutrality/http/server/GuildBrowser.java b/src/main/java/netneutrality/http/server/GuildBrowser.java index 86812b4..06e7d02 100644 --- a/src/main/java/netneutrality/http/server/GuildBrowser.java +++ b/src/main/java/netneutrality/http/server/GuildBrowser.java @@ -8,8 +8,8 @@ package netneutrality.http.server; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; import netneutrality.MusicBot; import netneutrality.http.WebModule; diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index 6af2974..df14339 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -8,7 +8,9 @@ package netneutrality.music; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; -import net.dv8tion.jda.core.audio.AudioSendHandler; +import net.dv8tion.jda.api.audio.AudioSendHandler; + +import java.nio.ByteBuffer; /** * This is a wrapper around AudioPlayer which makes it behave as an AudioSendHandler for JDA. As JDA calls canProvide @@ -36,7 +38,7 @@ public class AudioPlayerSendHandler implements AudioSendHandler { } @Override - public byte[] provide20MsAudio() { + public ByteBuffer provide20MsAudio() { if (lastFrame == null) { lastFrame = audioPlayer.provide(); } @@ -44,7 +46,7 @@ public class AudioPlayerSendHandler implements AudioSendHandler { byte[] data = lastFrame != null ? lastFrame.getData() : null; lastFrame = null; - return data; + return ByteBuffer.wrap(data); } @Override diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 7d5ec38..bdf7ca6 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -14,7 +14,7 @@ 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 net.dv8tion.jda.core.entities.*; +import net.dv8tion.jda.api.entities.*; import netneutrality.MusicBot; import netneutrality.handler.LogHandler; import netneutrality.utils.MessageFunction; diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index 2d6a41d..4f69588 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -1,6 +1,6 @@ package netneutrality.music; -import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.api.entities.TextChannel; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 0d757a0..bc27f66 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -11,7 +11,7 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; -import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.api.entities.TextChannel; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index 639cbe7..b5965d8 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -3,16 +3,18 @@ package netneutrality.utils; import java.time.OffsetDateTime; import java.util.List; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.ThreadManager; public class ChannelFunction { public static void bulkDeleteMessage(TextChannel channel, int toDelete) { if (toDelete >= 2500) return; - - Thread deleteMessage = new Thread(() -> { + + ThreadManager.executor.submit(() -> { + int toDeleteFinal = toDelete + 1; int iteration = toDeleteFinal / 100; for (int i = 0; i < iteration; i++) { @@ -27,9 +29,8 @@ public class ChannelFunction { deleteFromList(messages, channel); } + }); - - deleteMessage.start(); } @@ -40,7 +41,7 @@ public class ChannelFunction { } catch (IllegalArgumentException e) { messages.forEach(m -> { - if (!m.getCreationTime().isBefore(OffsetDateTime.now().minusWeeks(Long.parseLong("2")))) { + if (!m.getTimeCreated().isBefore(OffsetDateTime.now().minusWeeks(2))) { m.delete().queue(); } }); diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 0bdd585..9be7812 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -11,8 +11,8 @@ import java.time.OffsetDateTime; import java.util.List; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; -import net.dv8tion.jda.core.EmbedBuilder; -import net.dv8tion.jda.core.entities.*; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.*; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index e6de21f..281a608 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -1,8 +1,8 @@ package netneutrality.utils; -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.TextChannel; -import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.User; import netneutrality.MusicBot; import netneutrality.db.DBController; import netneutrality.db.controllers.DBSettings; diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/netneutrality/utils/UserFunction.java index 5dd7ea6..b86021b 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/netneutrality/utils/UserFunction.java @@ -1,8 +1,8 @@ package netneutrality.utils; -import net.dv8tion.jda.core.Permission; -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.Role; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; public class UserFunction { From b0dcc1d334076e7770eff7035910e88abaad24b8 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 10 Sep 2021 18:37:06 -0400 Subject: [PATCH 017/155] Updated dependencies and added file for basic settings --- pom.xml | 45 ++++++++++--------- src/main/java/netneutrality/MusicBot.java | 14 +++--- .../java/netneutrality/ThreadManager.java | 18 ++++++-- .../java/netneutrality/db/MysqlDatabase.java | 4 +- .../java/netneutrality/utils/Settings.java | 45 +++++++++++++------ src/main/resources/bot.config | 5 +++ 6 files changed, 87 insertions(+), 44 deletions(-) create mode 100644 src/main/resources/bot.config diff --git a/pom.xml b/pom.xml index bfe2c10..207c412 100644 --- a/pom.xml +++ b/pom.xml @@ -3,22 +3,27 @@ 4.0.0 com.xtremcommunity.discord netneutrality - 0.0.1 - MusicBot - Music bot + 1.0.0 + netneutrality-discord-bot + Discord bot + jar - 1.8 - 1.8 + 1.11 + 1.11 - - https://gitlab.xtremcommunity.com/nn.jar - + - jcenter - http://jcenter.bintray.com + central + https://repo1.maven.org/maven2/ + + + + dv8tion + m2-dv8tion + https://m2.dv8tion.net/releases @@ -27,27 +32,27 @@ net.dv8tion JDA - 4.1.0_81 + 4.3.0_277 com.squareup.okhttp3 okhttp - 3.13.0 + 4.9.1 org.json json - 20180813 + 20210307 org.reflections reflections - 0.9.11 + 0.9.12 @@ -58,33 +63,33 @@ org.apache.logging.log4j log4j-api - 2.10.0 + 2.14.1 org.apache.logging.log4j log4j-core - 2.10.0 + 2.14.1 org.apache.logging.log4j log4j-slf4j-impl - 2.10.0 + 2.14.1 org.fusesource.jansi jansi - 1.17 + 2.3.4 runtime com.sedmelluq lavaplayer - 1.3.33 + 1.3.77 junit junit - RELEASE + 4.13.2 diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index b69c9ba..af727d1 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -26,10 +26,11 @@ public class MusicBot { public static void main(String[] args) { System.setProperty("log4j.skipJansi", "false"); + Settings.init(); DBController.init(); try { - jda = new JDABuilder(AccountType.BOT).setToken(Settings.TOKEN).build(); + jda = JDABuilder.createDefault(Settings.TOKEN).build(); jda.awaitReady(); } catch (LoginException | IllegalArgumentException e) { LogHandler.log(e); @@ -42,8 +43,7 @@ public class MusicBot { jda.addEventListener(new NewCommandListener(), new EditHandler()); // WebApi webserver = new WebApi(); - - jda.getPresence().setActivity(Activity.watching("rape")); + jda.getPresence().setActivity(Activity.watching("you")); ConsoleHandler consoleInput = new ConsoleHandler(); @@ -61,9 +61,9 @@ public class MusicBot { public static void shutdown() { LOGGER.info("[Net Neutrality] Shutting down..."); MusicManager.disconnectPlayers(); + ThreadManager.shutdownExecutor(); disconnect(); DBController.shutdown(); - ThreadManager.shutdownExecutor(); LOGGER.info("[Net Neutrality] Shutdown complete"); System.exit(0); } @@ -73,8 +73,10 @@ public class MusicBot { } public static void disconnect() { - if (jda != null) - jda.shutdown(); + if (jda != null) { + jda.shutdownNow(); + } + } diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 4a4239c..379fcba 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -17,10 +17,13 @@ public class ThreadManager { public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); public static void shutdownExecutor() { + MusicBot.LOGGER.info("[Executor] Shutting down..."); + try { - MusicBot.LOGGER.info("[Executor] Shutting down..."); executor.shutdown(); + scheduler.shutdown(); executor.awaitTermination(5, TimeUnit.SECONDS); + scheduler.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { MusicBot.LOGGER.warn("[Executor] Running tasks interrupted"); @@ -28,9 +31,18 @@ public class ThreadManager { finally { if (!executor.isTerminated()) { MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks.."); + executor.shutdownNow(); } - executor.shutdownNow(); - MusicBot.LOGGER.info("[Executor] Shutdown finished!"); + + if (!scheduler.isTerminated()) { + MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks.."); + scheduler.shutdownNow(); + } + } + + MusicBot.LOGGER.info("[Executor] Shutdown finished!"); } + + } diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 2de9858..3648e27 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -117,6 +117,7 @@ public class MysqlDatabase { private int executeUpdate(String sql, Object[] params) { + try { PreparedStatement query = connection.prepareStatement(sql); resolveParameters(query, params); @@ -142,7 +143,8 @@ public class MysqlDatabase { try { PreparedStatement query = connection.prepareStatement(sql); resolveParameters(query, params); - return query.executeQuery(); + ResultSet rs = query.executeQuery(); + return rs; } catch (SQLException e) { MusicBot.LOGGER.error(e.toString()); e.printStackTrace(); diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 281a608..036ddbf 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -7,23 +7,40 @@ import netneutrality.MusicBot; import netneutrality.db.DBController; import netneutrality.db.controllers.DBSettings; +import java.io.*; +import java.util.Properties; + public class Settings { - public static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - public static String PREFIX = ((DBSettings) DBController.get("settings")).getSettingsByKey("prefix"); - public static final String TOKEN = ((DBSettings) DBController.get("settings")).getSettingsByKey("token"); + static Properties prop = new Properties(); + static String configFile = "bot.config"; - public static User getCreator() { - return MusicBot.getJDA().getUserById(((DBSettings) DBController.get("settings")).getSettingsByKey("owner")); - } + public static void init() { + InputStream is = Settings.class.getClassLoader().getResourceAsStream(configFile); + + try (FileInputStream fis = new FileInputStream(configFile)) { + prop.load(fis); + } catch (IOException ignored) { + + } + + } + + public static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; + public static String PREFIX = prop.getProperty("bot.prefix"); + public static final String TOKEN = prop.getProperty("bot.token"); + + public static User getCreator() { + return MusicBot.getJDA().getUserById(prop.getProperty("bot.owner")); + } + + public static Guild getOwnerGuild() { + return MusicBot.getJDA().getGuildById(prop.getProperty("bot.ownerguild")); + } + + public static TextChannel getLogChannel() { + return MusicBot.getJDA().getTextChannelById(prop.getProperty("bot.errorchannel")); + } - public static Guild getOwnerGuild() { - return MusicBot.getJDA().getGuildById(((DBSettings) DBController.get("settings")).getSettingsByKey("ownerguild")); - } - public static TextChannel getLogChannel() { - return MusicBot.getJDA().getTextChannelById(((DBSettings) DBController.get("settings")).getSettingsByKey("errorchannel")); - } - - } diff --git a/src/main/resources/bot.config b/src/main/resources/bot.config new file mode 100644 index 0000000..e2460e0 --- /dev/null +++ b/src/main/resources/bot.config @@ -0,0 +1,5 @@ +bot.token="" +bot.prefix="$" +bot.owner="" +bot.ownerguild="" +bot.errorchannel="" \ No newline at end of file From c92fab3a3cd0df901b893fa501d940271ac1d426 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 10 Sep 2021 19:08:06 -0400 Subject: [PATCH 018/155] Added command description for help --- .../command/AbstractCommand.java | 4 + .../command/basic/HelpCommand.java | 114 +++++++++++------- .../command/basic/PingCommand.java | 5 + .../command/crypto/BitcoinPriceCommand.java | 5 + .../command/crypto/EthereumPriceCommand.java | 5 + .../command/crypto/LitecoinPriceCommand.java | 5 + .../command/message/BlacklistCommand.java | 20 ++- .../command/message/PruneCommand.java | 5 + .../command/music/BitconnectCommand.java | 5 + .../command/music/DeleteQueueCommand.java | 5 + .../command/music/JoinCommand.java | 5 + .../command/music/LeaveCommand.java | 5 + .../command/music/PlayCommand.java | 13 +- .../command/music/SkipCommand.java | 5 + .../command/music/StopCommand.java | 6 + .../command/music/VolumeCommand.java | 5 + .../command/specific/DatabaseCommand.java | 5 + .../command/specific/EvalMethod.java | 5 + .../command/specific/LoggingCommand.java | 5 + .../command/specific/SellyCommand.java | 5 + .../command/specific/ShutdownCommand.java | 5 + .../command/specific/TestCommand.java | 5 + 22 files changed, 184 insertions(+), 58 deletions(-) diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 2ffb9e9..cb3592a 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -35,6 +35,8 @@ public abstract class AbstractCommand { public abstract String getUsage(); + public abstract String getDescription(); + public abstract Visibility getVisibility(); /** @@ -59,4 +61,6 @@ public abstract class AbstractCommand { List args = Arrays.asList(command.split(" ")); return args.get(arg); } + + } diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index cc2c340..d0cbe00 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -7,70 +7,92 @@ import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandManager; import netneutrality.command.Visibility; import netneutrality.utils.Settings; import java.awt.*; import java.util.HashMap; +import java.util.SortedSet; +import java.util.TreeSet; public class HelpCommand extends AbstractCommand { - - public HelpCommand() { - - } - @Override - public String execute(MessageReceivedEvent event, String args) { - return null; - } + public HelpCommand() { - public void sendHelp(HashMap commands, HashMap alias, User user, MessageChannel channel) { - StringBuilder help = new StringBuilder(); + } - for (AbstractCommand command : commands.values()) { - if (command.getUsage() != null) - help.append(Settings.PREFIX).append(command.getCommand()).append(" (: ").append(command.getUsage()).append("\n"); - } + @Override + public String execute(MessageReceivedEvent event, String args) { + sendHelp(CommandManager.commands, CommandManager.commandsAlias, event.getAuthor(), event.getChannel()); - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.green); - embed.addField("Commands for Net Neutrality", help.toString(), false); + return null; + } - if (channel instanceof TextChannel) - channel.sendMessage(new MessageBuilder().append(user).append(" help has been sent your way!").build()).queue(); + @Override + public boolean needAdmin() { + return false; + } - user.openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public boolean needAdmin() { - return false; - } + @Override + public String getCommand() { + return "help"; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public String[] getAlias() { + return new String[0]; + } - @Override - public String getCommand() { - return "help"; - } + @Override + public String getUsage() { + return null; + } - @Override - public String[] getAlias() { - return new String[0]; - } + @Override + public String getDescription() { + return "Get every command with its usage"; + } - @Override - public String getUsage() { - return "Get every command with its usage"; - } - - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } + @Override + public Visibility getVisibility() { + return Visibility.BOTH; + } + public void sendHelp(HashMap commands, HashMap alias, User user, MessageChannel channel) { + StringBuilder help = new StringBuilder(); + + SortedSet keys = new TreeSet<>(commands.keySet()); + for (String key : keys) { + AbstractCommand command = commands.get(key); + + if (command.isEnabled()) { + help.append(Settings.PREFIX).append(command.getCommand()); + if (command.getUsage() != null) + help.append(" ").append(command.getUsage()); + + if (command.getDescription() != null) + help.append(": ").append(command.getDescription()); + + help.append("\n"); + } + + + } + + EmbedBuilder embed = new EmbedBuilder(); + embed.setColor(Color.green); + embed.addField("Commands for Net Neutrality", help.toString(), false); + + if (channel instanceof TextChannel) + channel.sendMessage(new MessageBuilder().append(user).append(" help has been sent your way!").build()).queue(); + + user.openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); + } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 6f6a9ea..831c845 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -41,6 +41,11 @@ public class PingCommand extends AbstractCommand { @Override public String getUsage() { + return null; + } + + @Override + public String getDescription() { return "Pong!"; } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 3d1ea18..46d0331 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -88,6 +88,11 @@ public class BitcoinPriceCommand extends AbstractCommand { @Override public String getUsage() { + return null; + } + + @Override + public String getDescription() { return "Get the bitcoin price"; } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 66cc77a..45fda37 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -80,6 +80,11 @@ public class EthereumPriceCommand extends AbstractCommand { @Override public String getUsage() { + return null; + } + + @Override + public String getDescription() { return "Get the ethereum price"; } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 34cda87..674b612 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -80,6 +80,11 @@ public class LitecoinPriceCommand extends AbstractCommand { @Override public String getUsage() { + return null; + } + + @Override + public String getDescription() { return "Get the litecoin price"; } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 6f65dca..82879df 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -1,12 +1,15 @@ package netneutrality.command.message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.MusicBot; import netneutrality.command.AbstractCommand; import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; +import java.util.ArrayList; + public class BlacklistCommand extends AbstractCommand { @Override @@ -34,6 +37,11 @@ public class BlacklistCommand extends AbstractCommand { return "Manages the blacklist of your server."; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; @@ -50,8 +58,6 @@ public class BlacklistCommand extends AbstractCommand { case "get": event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { - - try { StringBuilder sb = new StringBuilder(); ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId(), mBlacklists -> { for (MBlacklist bl : mBlacklists) { @@ -61,10 +67,12 @@ public class BlacklistCommand extends AbstractCommand { t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); }); - } catch (RuntimeException e) { - e.printStackTrace(); - } - +// ArrayList mBlacklists = ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId()); +// for (MBlacklist bl : mBlacklists) { +// sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); +// } +// +// t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); }); diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index e09f1cc..6607323 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -32,6 +32,11 @@ public class PruneCommand extends AbstractCommand { return "Prune n messages from the channel you are currently on"; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 11710ee..745717e 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -39,6 +39,11 @@ public class BitconnectCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 2371432..75c363e 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -39,6 +39,11 @@ public class DeleteQueueCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 1abdf57..026c977 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -39,6 +39,11 @@ public class JoinCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index eae40f2..b331631 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -39,6 +39,11 @@ public class LeaveCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 022fea4..5b3d5c4 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -39,6 +39,11 @@ public class PlayCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; @@ -56,18 +61,14 @@ public class PlayCommand extends AbstractCommand { if (player.isConnectedTo(vChannel)) { event.getMessage().delete().queue(); - if (args.startsWith("ytsearch:")) { - player.play(args, event.getTextChannel(), event.getMember(), false); - } else { - player.play(args.split(" ")[0], event.getTextChannel(), event.getMember(), false); - } + player.play(args, event.getTextChannel(), event.getMember(), false); } else event.getTextChannel().sendMessage("Not in your voice channel").queue(); } else { player.connect(vChannel); event.getMessage().delete().queue(); - player.play(args.split(" ")[0], event.getTextChannel(), event.getMember(), false); + player.play(args, event.getTextChannel(), event.getMember(), false); } } else event.getTextChannel().sendMessage("You are not in a voice channel").queue(); diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 21d9b83..0ac8c39 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -39,6 +39,11 @@ public class SkipCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 4dccd0b..8ccf159 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -39,6 +39,11 @@ public class StopCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; @@ -55,6 +60,7 @@ public class StopCommand extends AbstractCommand { if (player.isConnected()) { if (player.isConnectedTo(vChannel)) { player.stopMusic(); + player.leave(); } else event.getTextChannel().sendMessage("Not in your voice channel").queue(); } else diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 84ce9cc..b48d2bc 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -39,6 +39,11 @@ public class VolumeCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 417b0c2..de48d7b 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -44,6 +44,11 @@ public class DatabaseCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 88575ba..6708e35 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -43,6 +43,11 @@ public class EvalMethod extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.BOTH; diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index dd8f520..b049f9f 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -35,6 +35,11 @@ public class LoggingCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.CHANNEL; diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java index 7a4f802..1e15e10 100644 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ b/src/main/java/netneutrality/command/specific/SellyCommand.java @@ -43,6 +43,11 @@ public class SellyCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.PRIVATE; diff --git a/src/main/java/netneutrality/command/specific/ShutdownCommand.java b/src/main/java/netneutrality/command/specific/ShutdownCommand.java index 09a28e5..c9a14e5 100644 --- a/src/main/java/netneutrality/command/specific/ShutdownCommand.java +++ b/src/main/java/netneutrality/command/specific/ShutdownCommand.java @@ -31,6 +31,11 @@ public class ShutdownCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.BOTH; diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index c4f26b6..a4bbfc3 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -43,6 +43,11 @@ public class TestCommand extends AbstractCommand { return null; } + @Override + public String getDescription() { + return null; + } + @Override public Visibility getVisibility() { return Visibility.BOTH; From b019852c622697dd73cee97521765d5853eb00ec Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 10 Sep 2021 19:13:23 -0400 Subject: [PATCH 019/155] Improved logging and refactored code --- .../java/netneutrality/db/DBController.java | 10 +- .../java/netneutrality/db/MysqlDatabase.java | 27 ++-- .../db/controllers/DBBlacklist.java | 48 +++++-- .../db/controllers/DBMessage.java | 134 ++++++++++-------- .../netneutrality/db/models/MBlacklist.java | 15 +- .../netneutrality/db/models/MSellyOrder.java | 2 + .../handler/NewCommandListener.java | 76 +++++----- .../netneutrality/utils/MessageFunction.java | 85 ++++++----- 8 files changed, 228 insertions(+), 169 deletions(-) diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index ef37578..6d156af 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -10,6 +10,8 @@ import java.util.concurrent.TimeUnit; import netneutrality.MusicBot; import netneutrality.ThreadManager; import org.reflections.Reflections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class @@ -22,7 +24,7 @@ public class DBController { */ private final static HashMap controllers = new HashMap<>(); - + private final static Logger logger = LoggerFactory.getLogger(DBController.class); private static MysqlDatabase database = new MysqlDatabase("netneutrality"); /** @@ -46,7 +48,7 @@ public class DBController { public static MysqlDatabase get() { if (database.isClosed()) { - MusicBot.LOGGER.info("Reconnecting to database.."); + logger.info("Reconnecting to database.."); database.reconnect(); } @@ -75,7 +77,7 @@ public class DBController { * Loads all the controllers which extends {@link AbstractController} */ private static void loadControllers() { - MusicBot.LOGGER.info("Loading databases controllers.."); + logger.info("Loading databases controllers.."); Reflections reflections = new Reflections("netneutrality.db.controllers"); Set> classes = reflections.getSubTypesOf(AbstractController.class); @@ -91,7 +93,7 @@ public class DBController { if (!controllers.containsKey(c.getControllerName())) { controllers.put(c.getControllerName(), c); - MusicBot.LOGGER.debug("Loaded controller: " + c.getControllerName()); + logger.debug("Loaded controller: " + c.getControllerName()); } } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) { diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 3648e27..23c7e54 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -17,9 +17,15 @@ import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; import netneutrality.exceptions.UnimplementedParameterException; import netneutrality.handler.LogHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MysqlDatabase { + private final static Logger logger = LoggerFactory.getLogger(MysqlDatabase.class); + private Connection connection; + private String dbName; + protected enum CommandType { SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"); @@ -34,16 +40,15 @@ public class MysqlDatabase { } } - private Connection connection; - private String dbName; + protected MysqlDatabase(String dbName) { this.dbName = dbName; try { - MusicBot.LOGGER.info("Connecting to database..."); + logger.info("Connecting to database..."); connection = new MysqlConnector(dbName, "root", "localhost", "").connect().getConnection(); } catch (SQLException e) { - MusicBot.LOGGER.error("Error connecting to database. Shutting down.."); + logger.error("Error connecting to database. Shutting down.."); MusicBot.shutdown(); System.exit(0); } @@ -57,14 +62,14 @@ public class MysqlDatabase { * @return {@link ResultSet} */ public ResultSet query(String query) { - MusicBot.LOGGER.debug("Query: " + query); + logger.debug("Query: " + query); Statement stmt; try { stmt = connection.createStatement(); return stmt.executeQuery(query); } catch (SQLException e) { - e.printStackTrace(); + logger.error(e.toString()); } return null; @@ -138,7 +143,7 @@ public class MysqlDatabase { * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} */ public ResultSet prepareAndExecute(String sql, Object... params) { - MusicBot.LOGGER.debug("Query: " + sql); + logger.debug("Query: " + sql); try { PreparedStatement query = connection.prepareStatement(sql); @@ -146,7 +151,7 @@ public class MysqlDatabase { ResultSet rs = query.executeQuery(); return rs; } catch (SQLException e) { - MusicBot.LOGGER.error(e.toString()); + logger.error(e.toString()); e.printStackTrace(); } @@ -212,7 +217,7 @@ public class MysqlDatabase { * @throws SQLException */ public void close() throws SQLException { - MusicBot.LOGGER.info("Closing database..."); + logger.info("Closing database..."); connection.close(); } @@ -222,10 +227,10 @@ public class MysqlDatabase { public void reconnect() { try { - System.out.println("Reconnecting to database..."); + logger.info("Reconnecting to database..."); connection = new MysqlConnector(dbName, "root", "localhost", "").connect().getConnection(); } catch (SQLException e) { - System.err.println("Error connecting to database. Shutting down.."); + logger.error("Error connecting to database. Shutting down.."); MusicBot.shutdown(); System.exit(0); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 70ccbd8..c84fdda 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -13,9 +13,13 @@ import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MBlacklist; import netneutrality.db.models.MTableModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DBBlacklist extends AbstractController { + private final static Logger logger = LoggerFactory.getLogger(DBBlacklist.class); + public DBBlacklist() { } @@ -45,10 +49,10 @@ public class DBBlacklist extends AbstractController { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(); - MusicBot.LOGGER.info("blacklisted"); + logger.info("blacklisted"); success.accept(true); } else { - MusicBot.LOGGER.info("not blacklisted"); + logger.info("not blacklisted"); success.accept(false); } }); @@ -60,10 +64,10 @@ public class DBBlacklist extends AbstractController { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId).async(); - MusicBot.LOGGER.info("enabled"); + logger.info("enabled"); success.accept(true); } else { - MusicBot.LOGGER.info("error enabling"); + logger.info("error enabling"); success.accept(false); } }); @@ -75,16 +79,17 @@ public class DBBlacklist extends AbstractController { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId).async(); - MusicBot.LOGGER.info("disabled"); + logger.info("disabled"); success.accept(true); } else { - MusicBot.LOGGER.info("error disabled"); + logger.info("error disabled"); success.accept(false); } }); } + @Deprecated public void getBlacklistForWord(String word, String serverId, Consumer success) { ThreadManager.executor.submit(() -> { MBlacklist blacklisted = null; @@ -94,8 +99,7 @@ public class DBBlacklist extends AbstractController { MTableModel table = MysqlDatabase.convertToTableModel(rs); if (table.getNbRows() > 0) { - blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3), - (String) table.getRow(0).get(1)); + blacklisted = new MBlacklist(table.getRow(0)); } } @@ -109,10 +113,14 @@ public class DBBlacklist extends AbstractController { database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> { ArrayList output = new ArrayList<>(); - if (model.getNbRows() != 0) { + + if (model.getNbRows() > 0) { + + for (int row = 0; row < model.getNbRows(); row++) { - output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), - (String) model.getRow(row).get(1))); + logger.debug("enter loop"); + MBlacklist bl = new MBlacklist(model.getRow(row)); + output.add(bl); } } @@ -121,6 +129,23 @@ public class DBBlacklist extends AbstractController { } + @Deprecated + public ArrayList getBlacklistFromServer(String serverId) { + + MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).blocking(); + ArrayList output = new ArrayList<>(); + + if (model.getNbRows() > 0) { + + for (int row = 0; row < model.getNbRows(); row++) { + MBlacklist bl = new MBlacklist(model.getRow(row)); + output.add(bl); + } + } + + return output; + } + @Deprecated private boolean isAlreadyBlacklisted(String word, String serverId) { AtomicBoolean result = new AtomicBoolean(); @@ -131,6 +156,7 @@ public class DBBlacklist extends AbstractController { } }); + return result.get(); } diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 91c8faf..529d3d8 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -1,87 +1,101 @@ package netneutrality.db.controllers; import java.sql.SQLException; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.sql.ResultSet; -import netneutrality.ThreadManager; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.User; import netneutrality.db.AbstractController; import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MMessage; import netneutrality.db.models.MTableModel; import netneutrality.handler.LogHandler; - -import javax.swing.table.TableModel; +import netneutrality.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DBMessage extends AbstractController { - - public DBMessage() { } - /** - * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class - * - * @return {@link MysqlDatabase} - */ - public MysqlDatabase getDatabase() { - return database; - } - - public void log(String servername, String channelname, String username, String datesent, String messageId, String message) { - database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null).async(); + private final static Logger logger = LoggerFactory.getLogger(DBMessage.class); + public DBMessage() { + } - } - - public void logEdit(String messageId, String newMessage) { - database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async(); + /** + * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class + * + * @return {@link MysqlDatabase} + */ + public MysqlDatabase getDatabase() { + return database; + } - } - - public MMessage getMessage(String messageId) { - ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE messageId = ?", messageId); - MTableModel table = MysqlDatabase.convertToTableModel(rs); - if (table.getNbRows() > 0) { - return new MMessage(table.getRowModel(0)); - } + public void log(Guild guild, TextChannel channel, User author, Message message) { + String servername = guild.getName(); + String channelname = channel.getName(); + String username = author.getName(); + String datesent = message.getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.DATETIMEFORMAT)); + String messageid = message.getId(); + String msg = message.getContentRaw().trim(); + + database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageid, msg, null).async(); + + } + + public void logEdit(String messageId, String newMessage) { + database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async(); + + } + + public MMessage getMessage(String messageId) { + ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE messageId = ?", messageId); + MTableModel table = MysqlDatabase.convertToTableModel(rs); + if (table.getNbRows() > 0) { + return new MMessage(table.getRowModel(0)); + } - return null; - } - - public ArrayList getMessagesFromUser(String username, String serverName, int max) { - ArrayList messages = new ArrayList<>(); + return null; + } - ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE userName = ? AND serverName = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max); - MTableModel table = MysqlDatabase.convertToTableModel(rs); - if (table.getNbRows() > 0) { - for (int row = 0; row < max; row++) { - messages.add(new MMessage(table.getRowModel(row))); - } - } + public ArrayList getMessagesFromUser(String username, String serverName, int max) { + ArrayList messages = new ArrayList<>(); + + ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE userName = ? AND serverName = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max); + MTableModel table = MysqlDatabase.convertToTableModel(rs); + if (table.getNbRows() > 0) { + for (int row = 0; row < max; row++) { + messages.add(new MMessage(table.getRowModel(row))); + } + } - return messages; - } - - public String getMessageString(String messageId) { - - try { - ResultSet rs = database.prepareAndExecute("SELECT message FROM log_message WHERE messageId = ?", messageId); - if (rs.next()) { - return rs.getString(1); - } + return messages; + } - } catch (SQLException e) { - LogHandler.log(e); - } + public String getMessageString(String messageId) { - return "No message found"; - } - + try { + ResultSet rs = database.prepareAndExecute("SELECT message FROM log_message WHERE messageId = ?", messageId); + if (rs.next()) { + return rs.getString(1); + } + + } catch (SQLException e) { + logger.error(e.getMessage()); + LogHandler.log(e); + } + + return "No message found"; + } - @Override - public String getControllerName() { - return "message"; - } + @Override + public String getControllerName() { + return "message"; + } } diff --git a/src/main/java/netneutrality/db/models/MBlacklist.java b/src/main/java/netneutrality/db/models/MBlacklist.java index 3dad482..8d6eb91 100644 --- a/src/main/java/netneutrality/db/models/MBlacklist.java +++ b/src/main/java/netneutrality/db/models/MBlacklist.java @@ -1,10 +1,12 @@ package netneutrality.db.models; +import java.util.List; + public class MBlacklist { - protected String word; - protected boolean enabled; - protected String creatorId; + protected String word = ""; + protected boolean enabled = false; + protected String creatorId= ""; protected String serverId; public MBlacklist(String word, boolean enabled, String creatorId, String serverId) { @@ -14,6 +16,13 @@ public class MBlacklist { this.serverId = serverId; } + public MBlacklist(List row) { + this.word = (String) row.get(0); + this.enabled = (Boolean) row.get(2); + this.creatorId = (String) row.get(3); + this.serverId = (String) row.get(1); + } + /** * @return String The blacklisted word */ diff --git a/src/main/java/netneutrality/db/models/MSellyOrder.java b/src/main/java/netneutrality/db/models/MSellyOrder.java index bfcc27c..e3db853 100644 --- a/src/main/java/netneutrality/db/models/MSellyOrder.java +++ b/src/main/java/netneutrality/db/models/MSellyOrder.java @@ -38,6 +38,8 @@ public class MSellyOrder { this.createdAt = createdAt; } + //TODO: Construct from JSONObject + public String getId() { return id; diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index fe304c8..df0ae95 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -1,7 +1,6 @@ package netneutrality.handler; - import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; @@ -20,51 +19,44 @@ import java.time.format.DateTimeFormatter; public class NewCommandListener extends ListenerAdapter { - public NewCommandListener() { - CommandManager.init(); - } - - @Override - public void onMessageReceived(MessageReceivedEvent event) { - - if (event.getAuthor().isBot()) return; - if (event.isWebhookMessage()) return; - if (MessageRateLimit.check(event.getMember(), event.getMessage(), event.getChannel())) return; + public NewCommandListener() { + CommandManager.init(); + } - if (event.isFromType(ChannelType.TEXT)) { - ((DBMessage) DBController.get("message")).log(event.getGuild().getName(), event.getTextChannel().getName(), - event.getMember().getUser().getName(), - event.getMessage().getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.DATETIMEFORMAT)), event.getMessage().getId(), - event.getMessage().getContentDisplay().trim()); - } + @Override + public void onMessageReceived(MessageReceivedEvent event) { - Message message = event.getMessage(); - String msg = message.getContentDisplay().trim(); - - if (msg.startsWith(Settings.PREFIX)) { - msg = msg.substring(1); - String cmd = msg.split(" ", 2)[0]; + if (event.getAuthor().isBot()) return; + if (event.isWebhookMessage()) return; + if (MessageRateLimit.check(event.getMember(), event.getMessage(), event.getChannel())) return; - if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { + if (event.isFromType(ChannelType.TEXT)) { + ((DBMessage) DBController.get("message")).log(event.getGuild(), event.getTextChannel(), event.getAuthor(), event.getMessage()); + } - AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); + Message message = event.getMessage(); + String msg = message.getContentDisplay().trim(); - if (Visibility.check(event.getChannel(), c.getVisibility())) { - if (c.needAdmin() && c.getVisibility() != Visibility.PRIVATE) { - if (!UserFunction.isAdmin(event.getMember())) { - return; - } - } + if (msg.startsWith(Settings.PREFIX)) { + msg = msg.substring(1); + String cmd = msg.split(" ", 2)[0]; - if (cmd.equals("help")) { - ((HelpCommand) CommandManager.commands.get("help")).sendHelp(CommandManager.commands, CommandManager.commandsAlias, event.getAuthor(), event.getChannel()); - } else { - c.execute(event, msg.replaceFirst("(" + cmd + ")( )?", "")); - } - } - } - } else { - MessageFunction.checkBlacklist(event.getGuild().getId(), event.getMessage(), event.getTextChannel(), msg); - } - } + if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { + + AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); + + if (Visibility.check(event.getChannel(), c.getVisibility())) { + if (c.needAdmin()) { + if (!UserFunction.isAdmin(event.getMember())) { + return; + } + } + + c.execute(event, msg.replaceFirst("(" + cmd + ")( )?", "")); + } + } + } else { + MessageFunction.checkBlacklist(event.getGuild().getId(), event.getMessage(), event.getTextChannel(), msg); + } + } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 9be7812..0251baa 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -16,53 +16,62 @@ import net.dv8tion.jda.api.entities.*; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MessageFunction { - public static Member getStartingMention(Message message) { - if (isStartingWithMention(message)) { - return message.getMentionedMembers().get(0); - } + private final static Logger logger = LoggerFactory.getLogger(MessageFunction.class); - return null; - - - } - - public static boolean isStartingWithMention(Message message) { - if (!message.isFromType(ChannelType.TEXT)) - return false; + public static Member getStartingMention(Message message) { + if (isStartingWithMention(message)) { + return message.getMentionedMembers().get(0); + } - List mentions= message.getMentionedMembers(); - - for (Member member : mentions) { - if (message.getContentDisplay().startsWith("@" + member.getUser().getName())) - return true; - } - - return false; - } + return null; - public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { - EmbedBuilder message = new EmbedBuilder(); - message.setTitle("Adding track to queue.."); - message.setColor(Color.BLUE); - message.addField("Track title :", track.getInfo().title, false); - message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); - message.setTimestamp(OffsetDateTime.now()); - return message.build(); - } + } - public static void checkBlacklist(String guildId, Message message, TextChannel channel, String msg) { - try { - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guildId, mBlacklists -> { + public static boolean isStartingWithMention(Message message) { + if (!message.isFromType(ChannelType.TEXT)) + return false; + + List mentions = message.getMentionedMembers(); + + for (Member member : mentions) { + if (message.getContentDisplay().startsWith("@" + member.getUser().getName())) + return true; + } + + return false; + } + + public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { + EmbedBuilder message = new EmbedBuilder(); + message.setTitle("Adding track to queue.."); + message.setColor(Color.BLUE); + message.addField("Track title :", track.getInfo().title, false); + message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setTimestamp(OffsetDateTime.now()); + + + return message.build(); + } + + public static void checkBlacklist(String guildId, Message message, TextChannel channel, String msg) { + try { + ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guildId, mBlacklists -> { if (!mBlacklists.isEmpty()) { + logger.debug("Not Empty"); boolean found = false; for (MBlacklist aBlacklist : mBlacklists) { - if (msg.toLowerCase().contains(aBlacklist.getWord())) + logger.debug("TESTING WORD:" + aBlacklist.getWord()); + if (msg.toLowerCase().contains(aBlacklist.getWord())) { + found = true; + } } if (found) { @@ -71,8 +80,8 @@ public class MessageFunction { } } }); - } catch (RuntimeException ignored) { - } - } - + } catch (RuntimeException ignored) { + } + } + } From c92b9317de06e84f2474ef5dfdb667de9636816b Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 10 Sep 2021 19:14:51 -0400 Subject: [PATCH 020/155] Added auto-disconnect for music player and improved scheduler --- .../netneutrality/music/MusicManager.java | 50 +++++++++++++------ .../netneutrality/music/SourceFinder.java | 11 ++-- .../netneutrality/music/TrackScheduler.java | 11 ++-- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index bdf7ca6..82704eb 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -16,22 +16,26 @@ import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.*; import netneutrality.MusicBot; +import netneutrality.ThreadManager; import netneutrality.handler.LogHandler; import netneutrality.utils.MessageFunction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; public class MusicManager { + private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); - private AudioPlayer player; - private TrackScheduler scheduler; + private final AudioPlayer player; + private final TrackScheduler scheduler; private final static Map managers = new ConcurrentHashMap<>(); - private long guildId; - private boolean isPlaying = false; + private final long guildId; private String topic; private MusicManager(Guild guild) { @@ -65,6 +69,11 @@ public class MusicManager { if (vChannel != null && !isConnectedTo(vChannel)) { Guild guild = MusicBot.getJDA().getGuildById(guildId); guild.getAudioManager().openAudioConnection(vChannel); + + ThreadManager.scheduler.scheduleWithFixedDelay(() -> { + if (getCurrentlyPlaying() == null && scheduler.queue.isEmpty()) + leave(); + }, 10, 10, TimeUnit.SECONDS); } else MusicBot.LOGGER.error("Error connecting!"); } @@ -74,11 +83,11 @@ public class MusicManager { return guild != null && guild.getAudioManager().getConnectedChannel() != null; } - public AudioTrack getCurrentlyPlaying() { + public synchronized AudioTrack getCurrentlyPlaying() { return player.getPlayingTrack(); } - public void leave() { + public synchronized void leave() { if (isConnected()) { stopMusic(); } @@ -97,25 +106,26 @@ public class MusicManager { player.destroy(); } - public static void disconnectPlayers() { + public synchronized static void disconnectPlayers() { for (MusicManager mm : managers.values()) { mm.leave(); } } - public synchronized void play(String url, TextChannel channel, Member user, boolean silent ) { + public synchronized void play(String url, TextChannel channel, Member user, boolean silent) { - String identifier = SourceFinder.getIdentifier(url, channel); - System.out.println(identifier); + String identifier = SourceFinder.getIdentifier(url); + logger.debug(identifier); scheduler.setTextChannel(channel); if (identifier != null) { playerManager.loadItem(identifier, new AudioLoadResultHandler() { @Override public void trackLoaded(AudioTrack audioTrack) { - if (!silent) - channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); + if (!silent) { + channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); + } scheduler.queue(audioTrack); } @@ -124,7 +134,10 @@ public class MusicManager { public void playlistLoaded(AudioPlaylist playlist) { if (identifier.startsWith("ytsearch:")) { - scheduler.queue(playlist.getTracks().get(0)); + AudioTrack track = playlist.getTracks().get(0); + + channel.sendMessage(MessageFunction.buildAddingTrackMessage(track, user)).queue(); + scheduler.queue(track); } else { for (AudioTrack track : playlist.getTracks()) { scheduler.queue(track); @@ -134,7 +147,7 @@ public class MusicManager { @Override public void noMatches() { - System.out.println("Oh shit! I got nothing"); + channel.sendMessage("No matches found").queue(); } @Override @@ -144,17 +157,22 @@ public class MusicManager { }); + } else { + channel.sendMessage("No source found to play the given url").queue(); + leave(); } } public synchronized void skip() { if (!scheduler.queue.isEmpty()) { scheduler.nextTrack(); - } else + } else { stopMusic(); + leave(); + } } - public void setVolume(int volume) { + public synchronized void setVolume(int volume) { player.setVolume(volume); } diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index 4f69588..2196ff4 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -21,9 +21,9 @@ enum SourceEnum { } public class SourceFinder { - private static Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&\\?]{12,}))?", Pattern.CASE_INSENSITIVE); + private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&\\?]{12,}))?", Pattern.CASE_INSENSITIVE); + private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); private static Matcher youtubeMatcher; - private static Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); private static Matcher soundcloudMatcher; private static Matcher BandcampMatcher; private static Matcher vimeoMatcher; @@ -38,13 +38,13 @@ public class SourceFinder { if (soundcloudMatcher.find()) return SourceEnum.Soundcloud; - if (url.startsWith("ytsearch:")) + if (!(url.startsWith("http://") || url.startsWith("https://"))) return SourceEnum.YTSearch; return SourceEnum.Nothing; } - public static String getIdentifier(String url, TextChannel channel) { + public static String getIdentifier(String url) { String identifier = null; switch (getSource(url)) { @@ -56,11 +56,10 @@ public class SourceFinder { identifier = url; break; case YTSearch: - identifier = url; + identifier = "ytsearch:" + url; break; case Nothing: identifier = null; - channel.sendMessage("No source found to play the given url").queue(); break; } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index bc27f66..05bf815 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -28,7 +28,7 @@ public class TrackScheduler extends AudioEventAdapter { this.queue = new LinkedBlockingQueue<>(); } - public void queue(AudioTrack track) { + public synchronized void queue(AudioTrack track) { // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. @@ -67,11 +67,14 @@ public class TrackScheduler extends AudioEventAdapter { // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are // giving null to startTrack, which is a valid argument and will simply stop the player. AudioTrack track = queue.poll(); - if (track != null) + if (track != null) { channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); - else + player.startTrack(track, false); + } else { channel.getManager().setTopic(topic).queue(); - player.startTrack(track, false); + + } + } @Override From 967856ce57a6050f4483d61ad1f8586e900fcb56 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 10 Sep 2021 19:55:34 -0400 Subject: [PATCH 021/155] Updated MySQL connector to 8.x --- netneutrality.sql | 95 +++++++++++++++++++ pom.xml | 2 +- .../java/netneutrality/db/MysqlConnector.java | 5 +- 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 netneutrality.sql diff --git a/netneutrality.sql b/netneutrality.sql new file mode 100644 index 0000000..62209aa --- /dev/null +++ b/netneutrality.sql @@ -0,0 +1,95 @@ +-- Database for the bot + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET AUTOCOMMIT = 0; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Base de données : `netneutrality` +-- + +-- -------------------------------------------------------- + +-- +-- Structure de la table `blacklist` +-- + +DROP TABLE IF EXISTS `blacklist`; +CREATE TABLE IF NOT EXISTS `blacklist` ( + `word` varchar(255) NOT NULL, + `serverId` varchar(255) NOT NULL, + `isEnabled` tinyint(4) NOT NULL, + `creatorId` varchar(255) NOT NULL, + PRIMARY KEY (`word`,`serverId`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `guilds` +-- + +DROP TABLE IF EXISTS `guilds`; +CREATE TABLE IF NOT EXISTS `guilds` ( + `guild_id` varchar(255) NOT NULL, + `name` varchar(255) NOT NULL, + `owner` varchar(255) NOT NULL, + PRIMARY KEY (`guild_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `logging` +-- + +DROP TABLE IF EXISTS `logging`; +CREATE TABLE IF NOT EXISTS `logging` ( + `serverId` varchar(255) NOT NULL, + `channelId` varchar(255) NOT NULL, + `enabled` tinyint(4) NOT NULL, + PRIMARY KEY (`serverId`,`channelId`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `log_message` +-- + +DROP TABLE IF EXISTS `log_message`; +CREATE TABLE IF NOT EXISTS `log_message` ( + `serverName` varchar(255) NOT NULL, + `channelName` varchar(255) NOT NULL, + `userName` varchar(255) NOT NULL, + `dateSent` varchar(255) NOT NULL, + `messageId` varchar(255) NOT NULL, + `message` varchar(2000) DEFAULT NULL, + `editedMessage` varchar(2000) DEFAULT NULL, + PRIMARY KEY (`messageId`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `settings` +-- + +DROP TABLE IF EXISTS `settings`; +CREATE TABLE IF NOT EXISTS `settings` ( + `skey` varchar(60) NOT NULL, + `value` varchar(2048) NOT NULL, + PRIMARY KEY (`skey`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/pom.xml b/pom.xml index 207c412..684495b 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ mysql mysql-connector-java - 5.1.45 + 8.0.26 org.apache.logging.log4j diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index 37fadac..b91191c 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -1,9 +1,10 @@ package netneutrality.db; +import com.mysql.cj.jdbc.MysqlConnectionPoolDataSource; + import java.sql.Connection; import java.sql.SQLException; -import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource; public class MysqlConnector { @@ -34,7 +35,7 @@ public class MysqlConnector { dataSource.setPort(3306); dataSource.setDatabaseName(dbName); dataSource.setAutoReconnect(true); - dataSource.setAutoReconnectForConnectionPools(true); + dataSource.setAutoReconnectForPools(true); c = dataSource.getConnection(); return this; } From a7d4c7d711997fb3c7ade99c779cc540b5dcb9e6 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 10 Sep 2021 19:57:59 -0400 Subject: [PATCH 022/155] Changed settings class into a singleton and improved logging --- src/main/java/netneutrality/MusicBot.java | 16 ++++----- .../java/netneutrality/ThreadManager.java | 14 +++++--- .../netneutrality/command/CommandManager.java | 7 ++-- .../command/basic/HelpCommand.java | 2 +- .../command/specific/DatabaseCommand.java | 4 +-- .../command/specific/EvalMethod.java | 2 +- .../command/specific/TestCommand.java | 2 +- .../db/controllers/DBMessage.java | 2 +- .../netneutrality/handler/ConsoleHandler.java | 7 ++-- .../netneutrality/handler/LogHandler.java | 10 ++++-- .../handler/NewCommandListener.java | 2 +- .../netneutrality/http/server/WebApi.java | 9 +++-- .../netneutrality/music/MusicManager.java | 2 +- .../java/netneutrality/utils/Settings.java | 35 ++++++++++++------- .../netneutrality/utils/UserFunction.java | 2 +- src/main/resources/bot.config | 10 +++--- 16 files changed, 75 insertions(+), 51 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index af727d1..5eaed0c 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -22,20 +22,18 @@ import javax.security.auth.login.LoginException; public class MusicBot { private static JDA jda; - public static Logger LOGGER = LoggerFactory.getLogger(MusicBot.class); + private final static Logger logger = LoggerFactory.getLogger(MusicBot.class); public static void main(String[] args) { System.setProperty("log4j.skipJansi", "false"); - Settings.init(); DBController.init(); try { - jda = JDABuilder.createDefault(Settings.TOKEN).build(); + jda = JDABuilder.createDefault(Settings.getInstance().getToken()).build(); jda.awaitReady(); - } catch (LoginException | IllegalArgumentException e) { - LogHandler.log(e); - } catch (InterruptedException e) { - LOGGER.error(e.getMessage()); + } catch (LoginException | IllegalArgumentException | InterruptedException e) { + logger.error(e.getMessage()); + shutdown(); } @@ -59,12 +57,12 @@ public class MusicBot { } public static void shutdown() { - LOGGER.info("[Net Neutrality] Shutting down..."); + logger.info("[Net Neutrality] Shutting down..."); MusicManager.disconnectPlayers(); ThreadManager.shutdownExecutor(); disconnect(); DBController.shutdown(); - LOGGER.info("[Net Neutrality] Shutdown complete"); + logger.info("[Net Neutrality] Shutdown complete"); System.exit(0); } diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 379fcba..9d361e6 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -6,6 +6,9 @@ package netneutrality; * This file is closed-source. It should not be distributed or copied in any way or form */ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -13,11 +16,12 @@ import java.util.concurrent.TimeUnit; public class ThreadManager { + private final static Logger logger = LoggerFactory.getLogger(ThreadManager.class); public static final ExecutorService executor = Executors.newSingleThreadExecutor(); public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); public static void shutdownExecutor() { - MusicBot.LOGGER.info("[Executor] Shutting down..."); + logger.info("[Executor] Shutting down..."); try { executor.shutdown(); @@ -26,22 +30,22 @@ public class ThreadManager { scheduler.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - MusicBot.LOGGER.warn("[Executor] Running tasks interrupted"); + logger.warn("[Executor] Running tasks interrupted"); } finally { if (!executor.isTerminated()) { - MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks.."); + logger.warn("[Executor] Forcing shutdown of running tasks.."); executor.shutdownNow(); } if (!scheduler.isTerminated()) { - MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks.."); + logger.warn("[Executor] Forcing shutdown of running tasks.."); scheduler.shutdownNow(); } } - MusicBot.LOGGER.info("[Executor] Shutdown finished!"); + logger.info("[Executor] Shutdown finished!"); } diff --git a/src/main/java/netneutrality/command/CommandManager.java b/src/main/java/netneutrality/command/CommandManager.java index 58aea94..d351f50 100644 --- a/src/main/java/netneutrality/command/CommandManager.java +++ b/src/main/java/netneutrality/command/CommandManager.java @@ -9,6 +9,8 @@ package netneutrality.command; import netneutrality.MusicBot; import org.reflections.Reflections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; @@ -17,6 +19,7 @@ import java.util.Set; public class CommandManager { + private final static Logger logger = LoggerFactory.getLogger(CommandManager.class); public static HashMap commands = new HashMap<>(); public static HashMap commandsAlias = new HashMap<>(); @@ -26,7 +29,7 @@ public class CommandManager { } private static void initCommands() { - MusicBot.LOGGER.info("Loading commands.."); + logger.info("Loading commands.."); Reflections reflections = new Reflections("netneutrality.command"); Set> classes = reflections.getSubTypesOf(AbstractCommand.class); @@ -51,7 +54,7 @@ public class CommandManager { } } - MusicBot.LOGGER.info("Loaded " + commands.size() + " commands!"); + logger.info("Loaded " + commands.size() + " commands!"); } private static void initAlias() { diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index d0cbe00..4b6741b 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -73,7 +73,7 @@ public class HelpCommand extends AbstractCommand { AbstractCommand command = commands.get(key); if (command.isEnabled()) { - help.append(Settings.PREFIX).append(command.getCommand()); + help.append(Settings.getInstance().getPrefix()).append(command.getCommand()); if (command.getUsage() != null) help.append(" ").append(command.getUsage()); diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index de48d7b..775db24 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -59,7 +59,7 @@ public class DatabaseCommand extends AbstractCommand { //TODO: Clean up the mess event.getMessage().delete().queue(); - if (!event.getAuthor().getDiscriminator().equals(Settings.getCreator().getDiscriminator())) + if (!event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) return null; if (countArgs(args) > 0) { @@ -74,7 +74,7 @@ public class DatabaseCommand extends AbstractCommand { EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.BLUE); embed.setTimestamp( - DateTimeFormatter.ofPattern(Settings.DATETIMEFORMAT).parse(message.getDateSent())); + DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT).parse(message.getDateSent())); embed.setFooter("Guild : " + message.getServerName() + " | ID : " + message.getMessageId(), null); embed.setDescription( "Message from " + message.getSender() + " on the channel " + message.getChannelName()); diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 6708e35..3435c89 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -56,7 +56,7 @@ public class EvalMethod extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String args) { - if (event.getAuthor().getId().equals(Settings.getCreator().getId())) { + if (event.getAuthor().getId().equals(Settings.getInstance().getCreator().getId())) { ScriptEngine se = new ScriptEngineManager().getEngineByName("Nashorn"); try { se.eval("var imports = new JavaImporter(java.io, java.lang, java.util);"); diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index a4bbfc3..99c719e 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -55,7 +55,7 @@ public class TestCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String args) { - if (event.getAuthor().getDiscriminator().equals(Settings.getCreator().getDiscriminator())) { + if (event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) { MessageFunction.isStartingWithMention(event.getMessage()); } diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 529d3d8..c0767bd 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -38,7 +38,7 @@ public class DBMessage extends AbstractController { String servername = guild.getName(); String channelname = channel.getName(); String username = author.getName(); - String datesent = message.getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.DATETIMEFORMAT)); + String datesent = message.getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT)); String messageid = message.getId(); String msg = message.getContentRaw().trim(); diff --git a/src/main/java/netneutrality/handler/ConsoleHandler.java b/src/main/java/netneutrality/handler/ConsoleHandler.java index 96490f9..3988453 100644 --- a/src/main/java/netneutrality/handler/ConsoleHandler.java +++ b/src/main/java/netneutrality/handler/ConsoleHandler.java @@ -1,6 +1,7 @@ package netneutrality.handler; -import netneutrality.MusicBot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; @@ -8,9 +9,9 @@ import java.io.InputStreamReader; public class ConsoleHandler { - + private final static Logger logger = LoggerFactory.getLogger(ConsoleHandler.class); public ConsoleHandler() { - MusicBot.LOGGER.info("Console input ready!"); + logger.info("Console input ready!"); } public String init() { diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index e207e50..0e5911a 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -2,9 +2,13 @@ package netneutrality.handler; import netneutrality.MusicBot; import netneutrality.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LogHandler { + private final static Logger logger = LoggerFactory.getLogger(LogHandler.class); + /** * Log the exception to the owner's log TextChannel as defined in {@link Settings#getLogChannel()} * @@ -12,8 +16,10 @@ public class LogHandler { */ public static void log(Exception e) { - MusicBot.LOGGER.error(e.getMessage()); - Settings.getLogChannel().sendMessage("Error : " + e).queue(); + logger.error(e.getMessage()); + + //TODO: to remove or add check if jda is started + Settings.getInstance().getLogChannel().sendMessage("Error : " + e).queue(); } } diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index df0ae95..d049d54 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -37,7 +37,7 @@ public class NewCommandListener extends ListenerAdapter { Message message = event.getMessage(); String msg = message.getContentDisplay().trim(); - if (msg.startsWith(Settings.PREFIX)) { + if (msg.startsWith(Settings.getInstance().getPrefix())) { msg = msg.substring(1); String cmd = msg.split(" ", 2)[0]; diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 6aa372a..a31130b 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -7,18 +7,21 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpServer; -import netneutrality.MusicBot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetSocketAddress; public class WebApi { + private final static Logger logger = LoggerFactory.getLogger(WebApi.class); + private int port = 9000; private HttpServer server; public WebApi() { - MusicBot.LOGGER.debug("Starting web server..."); + logger.debug("Starting web server..."); try { server = HttpServer.create(new InetSocketAddress(port), 0); } catch (IOException e) { @@ -28,7 +31,7 @@ public class WebApi { server.createContext("/guild", new GuildBrowser()); server.setExecutor(null); server.start(); - MusicBot.LOGGER.debug("Web server started at [" + server.getAddress().getAddress().toString() + "]"); + logger.debug("Web server started at [" + server.getAddress().getAddress().toString() + "]"); } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 82704eb..2420b02 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -75,7 +75,7 @@ public class MusicManager { leave(); }, 10, 10, TimeUnit.SECONDS); } else - MusicBot.LOGGER.error("Error connecting!"); + logger.error("Error connecting!"); } public boolean isConnected() { diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 036ddbf..0e7d211 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -12,33 +12,42 @@ import java.util.Properties; public class Settings { - static Properties prop = new Properties(); - static String configFile = "bot.config"; + public static Settings INSTANCE; + private Properties prop = new Properties(); - public static void init() { + public Settings() { + String configFile = "bot.config"; InputStream is = Settings.class.getClassLoader().getResourceAsStream(configFile); - try (FileInputStream fis = new FileInputStream(configFile)) { - prop.load(fis); - } catch (IOException ignored) { - + try { + prop.load(is); + } catch (IOException e) { + e.printStackTrace(); } } - public static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - public static String PREFIX = prop.getProperty("bot.prefix"); - public static final String TOKEN = prop.getProperty("bot.token"); + public static Settings getInstance() { + if(INSTANCE == null) { + INSTANCE = new Settings(); + } - public static User getCreator() { + return INSTANCE; + } + + public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; + public String getPrefix() { return prop.getProperty("bot.prefix"); } + public String getToken() { return prop.getProperty("bot.token"); } + + public User getCreator() { return MusicBot.getJDA().getUserById(prop.getProperty("bot.owner")); } - public static Guild getOwnerGuild() { + public Guild getOwnerGuild() { return MusicBot.getJDA().getGuildById(prop.getProperty("bot.ownerguild")); } - public static TextChannel getLogChannel() { + public TextChannel getLogChannel() { return MusicBot.getJDA().getTextChannelById(prop.getProperty("bot.errorchannel")); } diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/netneutrality/utils/UserFunction.java index b86021b..5d46d3c 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/netneutrality/utils/UserFunction.java @@ -9,7 +9,7 @@ public class UserFunction { public static boolean isAdmin(Member user) { // This check will only be present during the development of the bot - if (user.getUser().getId().equals(Settings.getCreator().getId())) { + if (user.getUser().getId().equals(Settings.getInstance().getCreator().getId())) { return true; } diff --git a/src/main/resources/bot.config b/src/main/resources/bot.config index e2460e0..2d0eb74 100644 --- a/src/main/resources/bot.config +++ b/src/main/resources/bot.config @@ -1,5 +1,5 @@ -bot.token="" -bot.prefix="$" -bot.owner="" -bot.ownerguild="" -bot.errorchannel="" \ No newline at end of file +bot.token= +bot.prefix=$ +bot.owner= +bot.ownerguild= +bot.errorchannel= \ No newline at end of file From fd4c54e56820d5160c2adebcdf74cf0088b9dea2 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 12 Sep 2021 19:43:10 -0400 Subject: [PATCH 023/155] Added required intents --- src/main/java/netneutrality/MusicBot.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 5eaed0c..a2d0318 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -1,14 +1,13 @@ package netneutrality; -import net.dv8tion.jda.api.AccountType; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.db.DBController; import netneutrality.handler.ConsoleHandler; import netneutrality.handler.EditHandler; -import netneutrality.handler.LogHandler; import netneutrality.handler.NewCommandListener; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; @@ -29,7 +28,9 @@ public class MusicBot { DBController.init(); try { - jda = JDABuilder.createDefault(Settings.getInstance().getToken()).build(); + jda = JDABuilder.createDefault(Settings.getInstance().get("bot.token")) + .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) + .build(); jda.awaitReady(); } catch (LoginException | IllegalArgumentException | InterruptedException e) { logger.error(e.getMessage()); From 3ecda23983432847c14c98c0bf3a0a8d49b3eabc Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 15 Sep 2021 14:35:39 -0400 Subject: [PATCH 024/155] Prepare for role-basaed command permission --- pom.xml | 24 ++- .../java/netneutrality/ThreadManager.java | 21 +- .../command/AbstractCommand.java | 8 +- .../netneutrality/command/CommandType.java | 14 ++ .../command/PermissionManager.java | 28 +++ .../netneutrality/command/Visibility.java | 2 +- .../command/basic/HelpCommand.java | 36 +--- .../command/basic/PingCommand.java | 9 +- .../command/crypto/BitcoinPriceCommand.java | 6 + .../command/crypto/Currency.java | 2 +- .../command/crypto/EthereumPriceCommand.java | 28 +-- .../command/crypto/LitecoinPriceCommand.java | 28 +-- .../command/message/BlacklistCommand.java | 204 +++++++++--------- .../command/message/PruneCommand.java | 6 + .../command/music/BitconnectCommand.java | 12 +- .../command/music/DeleteQueueCommand.java | 6 + .../command/music/JoinCommand.java | 6 + .../command/music/LeaveCommand.java | 6 + .../command/music/PlayCommand.java | 6 + .../command/music/SkipCommand.java | 6 + .../command/music/StopCommand.java | 6 + .../command/music/VolumeCommand.java | 6 + .../command/specific/DatabaseCommand.java | 6 + .../command/specific/EvalMethod.java | 8 +- .../command/specific/LoggingCommand.java | 6 + .../command/specific/SellyCommand.java | 6 + .../command/specific/ShutdownCommand.java | 6 + .../command/specific/TestCommand.java | 6 + .../db/controllers/DBBlacklist.java | 25 +-- .../netneutrality/db/controllers/DBGuild.java | 18 ++ .../db/controllers/DBMessage.java | 19 +- .../db/controllers/DBSettings.java | 3 +- .../db/entities/EntityInterface.java | 14 ++ .../java/netneutrality/db/entities/Guild.java | 16 ++ .../netneutrality/db/entities/Permission.java | 53 +++++ .../netneutrality/db/models/MTableModel.java | 6 +- .../java/netneutrality/http/WebModule.java | 2 +- .../netneutrality/music/MusicManager.java | 4 +- .../netneutrality/utils/ChannelFunction.java | 8 +- .../netneutrality/utils/MessageFunction.java | 69 ++++-- .../java/netneutrality/utils/Settings.java | 20 +- .../netneutrality/db/MysqlDatabaseTest.java | 30 --- 42 files changed, 528 insertions(+), 267 deletions(-) create mode 100644 src/main/java/netneutrality/command/CommandType.java create mode 100644 src/main/java/netneutrality/command/PermissionManager.java create mode 100644 src/main/java/netneutrality/db/controllers/DBGuild.java create mode 100644 src/main/java/netneutrality/db/entities/EntityInterface.java create mode 100644 src/main/java/netneutrality/db/entities/Guild.java create mode 100644 src/main/java/netneutrality/db/entities/Permission.java delete mode 100644 src/test/java/netneutrality/db/MysqlDatabaseTest.java diff --git a/pom.xml b/pom.xml index 684495b..90548ac 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,13 @@ 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + com.xtremcommunity.discord netneutrality 1.0.0 @@ -9,8 +16,7 @@ jar - 1.11 - 1.11 + 11 @@ -56,9 +62,9 @@ - mysql - mysql-connector-java - 8.0.26 + org.mariadb.jdbc + mariadb-java-client + 2.7.4 org.apache.logging.log4j @@ -75,6 +81,12 @@ log4j-slf4j-impl 2.14.1 + + commons-logging + commons-logging + 1.1.1 + + org.fusesource.jansi jansi @@ -91,6 +103,8 @@ junit 4.13.2 + + \ No newline at end of file diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 9d361e6..1c24f4b 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -6,6 +6,8 @@ package netneutrality; * This file is closed-source. It should not be distributed or copied in any way or form */ +import netneutrality.thread.BaseThread; +import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,9 +18,24 @@ import java.util.concurrent.TimeUnit; public class ThreadManager { + private static ThreadManager INSTANCE; private final static Logger logger = LoggerFactory.getLogger(ThreadManager.class); - public static final ExecutorService executor = Executors.newSingleThreadExecutor(); - public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); + public static final ExecutorService executor = Executors.newSingleThreadExecutor(new BaseThread("executor")); + public static final ExecutorService dBExecutor = Executors.newSingleThreadExecutor(new BaseThread("db-action")); + public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5, new BaseThread("scheduled-action")); + + + public ThreadManager() { + + } + + public static ThreadManager getInstance() { + if(INSTANCE == null) { + INSTANCE = new ThreadManager(); + } + + return INSTANCE; + } public static void shutdownExecutor() { logger.info("[Executor] Shutting down..."); diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index cb3592a..4395888 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -39,13 +39,15 @@ public abstract class AbstractCommand { public abstract Visibility getVisibility(); + public abstract CommandType getType(); + /** - * @param event * @param args the arguments to the command - * @return */ public abstract String execute(MessageReceivedEvent event, String args); - + + + public int countArgs(String command) { if (command.isEmpty()) return 0; diff --git a/src/main/java/netneutrality/command/CommandType.java b/src/main/java/netneutrality/command/CommandType.java new file mode 100644 index 0000000..ff7fd0e --- /dev/null +++ b/src/main/java/netneutrality/command/CommandType.java @@ -0,0 +1,14 @@ +package netneutrality.command;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +public enum CommandType { + MUSIC(1), ADMINISTRATION(0), UTILITY(5); + + CommandType(int i) { + + } +} diff --git a/src/main/java/netneutrality/command/PermissionManager.java b/src/main/java/netneutrality/command/PermissionManager.java new file mode 100644 index 0000000..dec8203 --- /dev/null +++ b/src/main/java/netneutrality/command/PermissionManager.java @@ -0,0 +1,28 @@ +package netneutrality.command;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import netneutrality.db.DBController; +import netneutrality.db.entities.Permission; +import netneutrality.db.models.MTableModel; + +import java.util.List; + +public class PermissionManager { + + public static boolean CheckPermissionForUser(Guild guild, Member member, AbstractCommand command) { + + //Permission permissions = DBController.get().prepareAndExecuteAsync("SELECT * FROM permissions WHERE guild_id = ?").blocking(); + + List roles = member.getRoles(); + + return false; + } + +} diff --git a/src/main/java/netneutrality/command/Visibility.java b/src/main/java/netneutrality/command/Visibility.java index a20df14..413f4e0 100644 --- a/src/main/java/netneutrality/command/Visibility.java +++ b/src/main/java/netneutrality/command/Visibility.java @@ -15,7 +15,7 @@ public enum Visibility { PRIVATE, CHANNEL, BOTH; public static boolean check(MessageChannel channel, Visibility v) { - if (v == BOTH && channel instanceof TextChannel || channel instanceof PrivateChannel) + if (v == BOTH && (channel instanceof TextChannel || channel instanceof PrivateChannel)) return true; if (v == PRIVATE && channel instanceof PrivateChannel) diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 4b6741b..792a9b2 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -1,6 +1,5 @@ package netneutrality.command.basic; -import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.TextChannel; @@ -8,13 +7,11 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandManager; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; -import netneutrality.utils.Settings; +import netneutrality.utils.MessageFunction; -import java.awt.*; import java.util.HashMap; -import java.util.SortedSet; -import java.util.TreeSet; public class HelpCommand extends AbstractCommand { @@ -64,35 +61,16 @@ public class HelpCommand extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return CommandType.UTILITY; + } public void sendHelp(HashMap commands, HashMap alias, User user, MessageChannel channel) { - StringBuilder help = new StringBuilder(); - - SortedSet keys = new TreeSet<>(commands.keySet()); - for (String key : keys) { - AbstractCommand command = commands.get(key); - - if (command.isEnabled()) { - help.append(Settings.getInstance().getPrefix()).append(command.getCommand()); - if (command.getUsage() != null) - help.append(" ").append(command.getUsage()); - - if (command.getDescription() != null) - help.append(": ").append(command.getDescription()); - - help.append("\n"); - } - - - } - - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.green); - embed.addField("Commands for Net Neutrality", help.toString(), false); if (channel instanceof TextChannel) channel.sendMessage(new MessageBuilder().append(user).append(" help has been sent your way!").build()).queue(); - user.openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); + user.openPrivateChannel().queue(t -> t.sendMessage(MessageFunction.buildHelpMessage(commands, alias)).queue()); } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 831c845..5c91b8a 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -3,13 +3,11 @@ package netneutrality.command.basic; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.MusicBot; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; public class PingCommand extends AbstractCommand { - public PingCommand() { - } - @Override public String execute(MessageReceivedEvent event, String args) { if (countArgs(args) == 0) @@ -54,4 +52,9 @@ public class PingCommand extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return null; + } + } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 46d0331..a61ce0d 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -3,6 +3,7 @@ package netneutrality.command.crypto; import java.io.IOException; import java.util.function.Consumer; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import org.json.JSONException; import org.json.JSONObject; @@ -101,4 +102,9 @@ public class BitcoinPriceCommand extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return null; + } + } diff --git a/src/main/java/netneutrality/command/crypto/Currency.java b/src/main/java/netneutrality/command/crypto/Currency.java index 8447223..2b8235a 100644 --- a/src/main/java/netneutrality/command/crypto/Currency.java +++ b/src/main/java/netneutrality/command/crypto/Currency.java @@ -18,7 +18,7 @@ public enum Currency { WST("WST"), XAF("XAF"), XAG("XAG"), XAU("XAU"), XBA("XBA"), XBB("XBB"), XBC("XBC"), XBD("XBD"), XCD("XCD"), XDR("XDR"), XFU("XFU"), XOF("XOF"), XPD("XPD"), XPF("XPF"), XPT("XPT"), XSU("XSU"), XTS("XTS"), XUA("XUA"), XXX("XXX"), YER("YER"), ZAR("ZAR"), ZMW("ZMW"); - private String iso4217Code; + private final String iso4217Code; Currency(String code) { this.iso4217Code = code; diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 45fda37..6e1ef17 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -3,6 +3,7 @@ package netneutrality.command.crypto; import java.io.IOException; import java.util.function.Consumer; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import org.json.JSONException; @@ -38,21 +39,17 @@ public class EthereumPriceCommand extends AbstractCommand { } - event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(new Consumer() { + event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - @Override - public void accept(Message t) { - - try { - WebModule ethereumHttp = new WebModule(currencyUrl + currency.toUpperCase()).request(); - price = Double.toString(ethereumHttp.getAsObject().getDouble(currency)); - - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - t.editMessage("Error getting ethereum price!").queue(); - } - t.editMessage(messageBuilder(price)).queue(); + try { + WebModule ethereumHttp = new WebModule(currencyUrl + currency.toUpperCase()).request(); + price = Double.toString(ethereumHttp.getAsObject().getDouble(currency)); + + } catch (IOException | RuntimeException e) { + e.printStackTrace(); + t.editMessage("Error getting ethereum price!").queue(); } + t.editMessage(messageBuilder(price)).queue(); }); return null; @@ -93,4 +90,9 @@ public class EthereumPriceCommand extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return null; + } + } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 674b612..2c8bb6e 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -3,6 +3,7 @@ package netneutrality.command.crypto; import java.io.IOException; import java.util.function.Consumer; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import org.json.JSONException; @@ -38,21 +39,17 @@ public class LitecoinPriceCommand extends AbstractCommand { } - event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(new Consumer() { + event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - @Override - public void accept(Message t) { - - try { - WebModule litecoinHttp = new WebModule(currencyUrl + currency).request(); - price = litecoinHttp.getAsArray().getJSONObject(0).getString("price_" + currency.toLowerCase()); - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - t.editMessage("Error getting litecoin price!").queue(); - } - t.editMessage(messageBuilder(price)).queue(); - + try { + WebModule litecoinHttp = new WebModule(currencyUrl + currency).request(); + price = litecoinHttp.getAsArray().getJSONObject(0).getString("price_" + currency.toLowerCase()); + } catch (IOException | RuntimeException e) { + e.printStackTrace(); + t.editMessage("Error getting litecoin price!").queue(); } + t.editMessage(messageBuilder(price)).queue(); + }); return null; @@ -92,4 +89,9 @@ public class LitecoinPriceCommand extends AbstractCommand { public Visibility getVisibility() { return Visibility.BOTH; } + + @Override + public CommandType getType() { + return null; + } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 82879df..3618cba 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -1,134 +1,130 @@ package netneutrality.command.message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.MusicBot; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; -import java.util.ArrayList; - public class BlacklistCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - @Override - public boolean isEnabled() { - return true; - } + @Override + public boolean needAdmin() { + return true; + } - @Override - public String getCommand() { - return "blacklist"; - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public String[] getAlias() { - return new String[] {"bl"}; - } + @Override + public String getCommand() { + return "blacklist"; + } - @Override - public String getUsage() { - return "Manages the blacklist of your server."; - } + @Override + public String[] getAlias() { + return new String[] {"bl"}; + } - @Override - public String getDescription() { - return null; - } + @Override + public String getUsage() { + return null; + } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + @Override + public String getDescription() { + return "Manages the blacklist of your server."; + } - @Override - public String execute(MessageReceivedEvent event, String args) { + @Override + public Visibility getVisibility() { + return Visibility.CHANNEL; + } - if (countArgs(args) > 0 && countArgs(args) < 3) { - String word = (countArgs(args) == 2 ? parseArgs(args, 1) : ""); - - switch (parseArgs(args, 0)) { - - case "get": - event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { + @Override + public CommandType getType() { + return null; + } - StringBuilder sb = new StringBuilder(); + @Override + public String execute(MessageReceivedEvent event, String args) { + + if (countArgs(args) > 0 && countArgs(args) < 3) { + String word = (countArgs(args) == 2 ? parseArgs(args, 1) : ""); + + switch (parseArgs(args, 0)) { + + case "get": + event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { + + StringBuilder sb = new StringBuilder(); ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId(), mBlacklists -> { - for (MBlacklist bl : mBlacklists) { - sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); - } + for (MBlacklist bl : mBlacklists) { + sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); + } - t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); - }); + t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); + }); -// ArrayList mBlacklists = ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId()); -// for (MBlacklist bl : mBlacklists) { -// sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); -// } -// -// t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); + }); - }); - - break; - - case "add": + break; - ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, event.getAuthor().getId(), event.getGuild().getId()), response -> { - if (response) { - event.getTextChannel().sendMessage("Added the word \"" + word + "\" to the blacklist.").queue(); - } else { - event.getTextChannel().sendMessage("Error adding \"" + word + "\" to the blacklist. It's already blacklisted!").queue(); - } - }); - break; - - case "remove": + case "add": - ((DBBlacklist) DBController.get("blacklist")).delete(word, event.getGuild().getId(), success -> { - if (success) { - event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } else { - event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); - } - }); + ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, event.getAuthor().getId(), event.getGuild().getId()), response -> { + if (response) { + event.getTextChannel().sendMessage("Added the word \"" + word + "\" to the blacklist.").queue(); + } else { + event.getTextChannel().sendMessage("Error adding \"" + word + "\" to the blacklist. It's already blacklisted!").queue(); + } + }); + break; - break; - - case "disable": + case "remove": - ((DBBlacklist) DBController.get("blacklist")).disable(word, event.getGuild().getId(), success -> { - if (success) { - event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } else { - event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); - } - }); - - break; - - case "enable": + ((DBBlacklist) DBController.get("blacklist")).delete(word, event.getGuild().getId(), success -> { + if (success) { + event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + } + }); - ((DBBlacklist) DBController.get("blacklist")).enable(word, event.getGuild().getId(), success -> { - if (success) { - event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } else { - event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); - } - }); - - break; - - } - } - - return null; - } + break; + + case "disable": + + ((DBBlacklist) DBController.get("blacklist")).disable(word, event.getGuild().getId(), success -> { + if (success) { + event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + } + }); + + break; + + case "enable": + + ((DBBlacklist) DBController.get("blacklist")).enable(word, event.getGuild().getId(), success -> { + if (success) { + event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + } + }); + + break; + + } + } + + return null; + } } diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index 6607323..6fda00e 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -2,6 +2,7 @@ package netneutrality.command.message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.utils.ChannelFunction; @@ -42,6 +43,11 @@ public class PruneCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { if (countArgs(args) == 1) diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 745717e..896c31b 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class BitconnectCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); @@ -59,16 +65,14 @@ public class BitconnectCommand extends AbstractCommand { if (player.isConnected()) { if (player.isConnectedTo(vChannel)) { - player.play("https://www.youtube.com/watch?v=A8M70M7tzTI", event.getTextChannel(), event.getMember(), true); + player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", event.getTextChannel(), member, true); } else event.getTextChannel().sendMessage("Not in your voice channel").queue(); } else { player.connect(vChannel); - player.play("https://www.youtube.com/watch?v=A8M70M7tzTI", event.getTextChannel(), event.getMember(), true); + player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", event.getTextChannel(), member, true); } - - } else event.getTextChannel().sendMessage("You are not in a voice channel").queue(); diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 75c363e..2b20368 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class DeleteQueueCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 026c977..3667fbe 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class JoinCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index b331631..3bb094d 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class LeaveCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 5b3d5c4..f8c87e2 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class PlayCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 0ac8c39..cf031ab 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class SkipCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 8ccf159..bf45cc0 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class StopCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index b48d2bc..fec6c46 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; @@ -49,6 +50,11 @@ public class VolumeCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 775db24..f348f59 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.PrivateChannel; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; @@ -54,6 +55,11 @@ public class DatabaseCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { //TODO: Clean up the mess diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 3435c89..9b9677a 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -8,6 +8,7 @@ package netneutrality.command.specific; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; import netneutrality.utils.Settings; @@ -25,7 +26,7 @@ public class EvalMethod extends AbstractCommand { @Override public boolean isEnabled() { - return true; + return false; } @Override @@ -53,6 +54,11 @@ public class EvalMethod extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index b049f9f..3ea3b70 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -2,6 +2,7 @@ package netneutrality.command.specific; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; public class LoggingCommand extends AbstractCommand { @@ -45,6 +46,11 @@ public class LoggingCommand extends AbstractCommand { return Visibility.CHANNEL; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java index 1e15e10..cd30092 100644 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ b/src/main/java/netneutrality/command/specific/SellyCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.specific; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBSettings; @@ -53,6 +54,11 @@ public class SellyCommand extends AbstractCommand { return Visibility.PRIVATE; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { diff --git a/src/main/java/netneutrality/command/specific/ShutdownCommand.java b/src/main/java/netneutrality/command/specific/ShutdownCommand.java index c9a14e5..1c6432a 100644 --- a/src/main/java/netneutrality/command/specific/ShutdownCommand.java +++ b/src/main/java/netneutrality/command/specific/ShutdownCommand.java @@ -2,6 +2,7 @@ package netneutrality.command.specific; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; public class ShutdownCommand extends AbstractCommand { @@ -41,6 +42,11 @@ public class ShutdownCommand extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { event.getJDA().shutdown(); diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index 99c719e..076b24c 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.specific; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.command.Visibility; import netneutrality.utils.MessageFunction; import netneutrality.utils.Settings; @@ -53,6 +54,11 @@ public class TestCommand extends AbstractCommand { return Visibility.BOTH; } + @Override + public CommandType getType() { + return null; + } + @Override public String execute(MessageReceivedEvent event, String args) { if (event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) { diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index c84fdda..f2b9370 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -1,15 +1,13 @@ package netneutrality.db.controllers; import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; -import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.db.AbstractController; -import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MBlacklist; import netneutrality.db.models.MTableModel; @@ -18,21 +16,12 @@ import org.slf4j.LoggerFactory; public class DBBlacklist extends AbstractController { - private final static Logger logger = LoggerFactory.getLogger(DBBlacklist.class); + private final Logger logger = LoggerFactory.getLogger(DBBlacklist.class); public DBBlacklist() { } - /** - * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class - * - * @return {@link MysqlDatabase} - */ - public MysqlDatabase getDatabase() { - return database; - } - public void add(MBlacklist obj, Consumer success) { isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> { if (blacklisted == 0) { @@ -49,7 +38,7 @@ public class DBBlacklist extends AbstractController { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(); - logger.info("blacklisted"); + logger.debug("removed word from blacklist"); success.accept(true); } else { logger.info("not blacklisted"); @@ -82,7 +71,7 @@ public class DBBlacklist extends AbstractController { logger.info("disabled"); success.accept(true); } else { - logger.info("error disabled"); + logger.info("error disabling"); success.accept(false); } }); @@ -109,16 +98,12 @@ public class DBBlacklist extends AbstractController { } public void getBlacklistFromServer(String serverId, Consumer> success) { - database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> { ArrayList output = new ArrayList<>(); - if (model.getNbRows() > 0) { - for (int row = 0; row < model.getNbRows(); row++) { - logger.debug("enter loop"); MBlacklist bl = new MBlacklist(model.getRow(row)); output.add(bl); } @@ -130,7 +115,7 @@ public class DBBlacklist extends AbstractController { } @Deprecated - public ArrayList getBlacklistFromServer(String serverId) { + public ArrayList getBlacklistFromServer(String serverId) throws ExecutionException, InterruptedException { MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).blocking(); ArrayList output = new ArrayList<>(); diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java new file mode 100644 index 0000000..84edf01 --- /dev/null +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -0,0 +1,18 @@ +package netneutrality.db.controllers;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.db.AbstractController; + +public class DBGuild extends AbstractController { + + + + @Override + public String getControllerName() { + return "guild"; + } +} diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index c0767bd..7b32ec9 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -4,6 +4,7 @@ import java.sql.SQLException; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.sql.ResultSet; +import java.util.function.Consumer; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; @@ -35,7 +36,7 @@ public class DBMessage extends AbstractController { } public void log(Guild guild, TextChannel channel, User author, Message message) { - String servername = guild.getName(); + String servername = guild.getId(); String channelname = channel.getName(); String username = author.getName(); String datesent = message.getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT)); @@ -62,6 +63,22 @@ public class DBMessage extends AbstractController { return null; } + public void getMessagesFromUser(String username, String serverName, int max, Consumer> success) { + database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE userName = ? AND serverName = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).async(table -> { + ArrayList messages = new ArrayList<>(); + + if (table.getNbRows() > 0) { + for (int row = 0; row < max; row++) { + messages.add(new MMessage(table.getRowModel(row))); + } + } + + success.accept(messages); + }); + + } + + @Deprecated public ArrayList getMessagesFromUser(String username, String serverName, int max) { ArrayList messages = new ArrayList<>(); diff --git a/src/main/java/netneutrality/db/controllers/DBSettings.java b/src/main/java/netneutrality/db/controllers/DBSettings.java index df5c4ba..a8e1fe9 100644 --- a/src/main/java/netneutrality/db/controllers/DBSettings.java +++ b/src/main/java/netneutrality/db/controllers/DBSettings.java @@ -1,10 +1,9 @@ package netneutrality.db.controllers; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import netneutrality.db.AbstractController; -import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MTableModel; public class DBSettings extends AbstractController { diff --git a/src/main/java/netneutrality/db/entities/EntityInterface.java b/src/main/java/netneutrality/db/entities/EntityInterface.java new file mode 100644 index 0000000..65940aa --- /dev/null +++ b/src/main/java/netneutrality/db/entities/EntityInterface.java @@ -0,0 +1,14 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.db.models.MTableModel; + +public interface EntityInterface { + + public E ConvertFromTableModel(MTableModel table); + +} diff --git a/src/main/java/netneutrality/db/entities/Guild.java b/src/main/java/netneutrality/db/entities/Guild.java new file mode 100644 index 0000000..c562498 --- /dev/null +++ b/src/main/java/netneutrality/db/entities/Guild.java @@ -0,0 +1,16 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +public class Guild { + + private int guildID; + + public Guild() { + + } +} diff --git a/src/main/java/netneutrality/db/entities/Permission.java b/src/main/java/netneutrality/db/entities/Permission.java new file mode 100644 index 0000000..553b1ed --- /dev/null +++ b/src/main/java/netneutrality/db/entities/Permission.java @@ -0,0 +1,53 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.command.CommandType; +import netneutrality.db.models.MTableModel; + +import java.util.List; + +public class Permission implements EntityInterface { + private final String guild_id; + private final String role_id; + private final CommandType type; + private final String command; + + public Permission(String guild_id, String role_id, CommandType type, String command) { + this.guild_id = guild_id; + this.role_id = role_id; + this.type = type; + this.command = command; + } + + public Permission(List row) { + this.guild_id = (String) row.get(0); + this.role_id = (String) row.get(1); + this.type = (CommandType) row.get(2); + this.command = (String) row.get(3); + } + + public String getGuild_id() { + return guild_id; + } + + public String getRole_id() { + return role_id; + } + + public CommandType getType() { + return type; + } + + public String getCommand() { + return command; + } + + @Override + public Permission ConvertFromTableModel(MTableModel table) { + return null; + } +} diff --git a/src/main/java/netneutrality/db/models/MTableModel.java b/src/main/java/netneutrality/db/models/MTableModel.java index 520d10a..5a93c95 100644 --- a/src/main/java/netneutrality/db/models/MTableModel.java +++ b/src/main/java/netneutrality/db/models/MTableModel.java @@ -12,9 +12,8 @@ import java.util.LinkedList; import java.util.List; public class MTableModel { - private List column; - private MRowsModel rows; - private String tableName; + private final List column; + private final MRowsModel rows; public MTableModel() { @@ -25,7 +24,6 @@ public class MTableModel { public MTableModel(String tableName) { this.column = new LinkedList<>(); this.rows = new MRowsModel(); - this.tableName = tableName; } public MTableModel(String... columns) { diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index 28d0ca9..c955828 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -58,7 +58,7 @@ public class WebModule { } public WebModule post(TreeMap params, Map headers) throws IOException { - RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), createJson(params)); + RequestBody body = RequestBody.create(createJson(params), MediaType.parse("application/json; charset=utf-8")); Request.Builder builder = new Request.Builder().url(this.url) .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"); diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 2420b02..a497fb9 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -71,9 +71,9 @@ public class MusicManager { guild.getAudioManager().openAudioConnection(vChannel); ThreadManager.scheduler.scheduleWithFixedDelay(() -> { - if (getCurrentlyPlaying() == null && scheduler.queue.isEmpty()) + if ((getCurrentlyPlaying() == null && scheduler.queue.isEmpty()) || vChannel.getMembers().size() == 0) leave(); - }, 10, 10, TimeUnit.SECONDS); + }, 120, 120, TimeUnit.SECONDS); } else logger.error("Error connecting!"); } diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index b5965d8..e8300d0 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -6,9 +6,13 @@ import java.util.List; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.ThreadManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ChannelFunction { + private static final Logger logger = LoggerFactory.getLogger(ChannelFunction.class); + public static void bulkDeleteMessage(TextChannel channel, int toDelete) { if (toDelete >= 2500) return; @@ -34,10 +38,10 @@ public class ChannelFunction { } - private static void deleteFromList(List messages, TextChannel channel) { + private synchronized static void deleteFromList(List messages, TextChannel channel) { try { channel.deleteMessages(messages).complete(); - System.out.println("Deleted " + messages.size() + " messages"); + logger.debug("Deleted " + messages.size() + " messages"); } catch (IllegalArgumentException e) { messages.forEach(m -> { diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 0251baa..849801c 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -8,11 +8,15 @@ package netneutrality.utils; import java.awt.*; import java.time.OffsetDateTime; +import java.util.HashMap; import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; +import netneutrality.command.AbstractCommand; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; @@ -23,6 +27,12 @@ public class MessageFunction { private final static Logger logger = LoggerFactory.getLogger(MessageFunction.class); + public static void logMessageIfNeeded(Guild guild, TextChannel channel, User author, Message message) { + + + } + + public static Member getStartingMention(Message message) { if (isStartingWithMention(message)) { return message.getMentionedMembers().get(0); @@ -59,29 +69,52 @@ public class MessageFunction { return message.build(); } + public static MessageEmbed buildHelpMessage(HashMap commands, HashMap alias) { + EmbedBuilder message = new EmbedBuilder(); + message.setTitle("Commands for Net Neutrality"); + message.setColor(Color.green); + + SortedSet keys = new TreeSet<>(commands.keySet()); + for (String key : keys) { + AbstractCommand command = commands.get(key); + String usage = "None"; + String description = "No description yet"; + + if (command.isEnabled()) { + if (command.getUsage() != null) + usage = command.getUsage(); + + if (command.getDescription() != null) + description = command.getDescription(); + + } + + message.addField(Settings.getInstance().get("bot.prefix") + command.getCommand() + " - Arguments: " + usage, description, false); + } + + return message.build(); + } + public static void checkBlacklist(String guildId, Message message, TextChannel channel, String msg) { - try { - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guildId, mBlacklists -> { - if (!mBlacklists.isEmpty()) { - logger.debug("Not Empty"); - boolean found = false; - for (MBlacklist aBlacklist : mBlacklists) { - logger.debug("TESTING WORD:" + aBlacklist.getWord()); - if (msg.toLowerCase().contains(aBlacklist.getWord())) { + ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guildId, mBlacklists -> { + if (!mBlacklists.isEmpty()) { - found = true; - } - } - - if (found) { - message.delete().queue(); - channel.sendMessage("Not in my christian server").queue(); + boolean found = false; + for (MBlacklist aBlacklist : mBlacklists) { + if (msg.toLowerCase().contains(aBlacklist.getWord())) { + found = true; + break; } } - }); - } catch (RuntimeException ignored) { - } + + if (found) { + message.delete().queue(); + channel.sendMessage("Not in my christian server").queue(); + } + } + }); + } } diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 0e7d211..68c6c30 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -12,15 +12,16 @@ import java.util.Properties; public class Settings { - public static Settings INSTANCE; - private Properties prop = new Properties(); + private static Settings INSTANCE; + private final Properties prop = new Properties(); public Settings() { String configFile = "bot.config"; - InputStream is = Settings.class.getClassLoader().getResourceAsStream(configFile); try { + InputStream is = Settings.class.getClassLoader().getResourceAsStream(configFile); prop.load(is); + is.close(); } catch (IOException e) { e.printStackTrace(); } @@ -35,20 +36,23 @@ public class Settings { return INSTANCE; } + public String get(String key) { + return prop.getProperty(key); + + } + public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - public String getPrefix() { return prop.getProperty("bot.prefix"); } - public String getToken() { return prop.getProperty("bot.token"); } public User getCreator() { - return MusicBot.getJDA().getUserById(prop.getProperty("bot.owner")); + return MusicBot.getJDA().getUserById(get("bot.owner")); } public Guild getOwnerGuild() { - return MusicBot.getJDA().getGuildById(prop.getProperty("bot.ownerguild")); + return MusicBot.getJDA().getGuildById(get("bot.ownerguild")); } public TextChannel getLogChannel() { - return MusicBot.getJDA().getTextChannelById(prop.getProperty("bot.errorchannel")); + return MusicBot.getJDA().getTextChannelById(get("bot.errorchannel")); } diff --git a/src/test/java/netneutrality/db/MysqlDatabaseTest.java b/src/test/java/netneutrality/db/MysqlDatabaseTest.java deleted file mode 100644 index f11bb4b..0000000 --- a/src/test/java/netneutrality/db/MysqlDatabaseTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package netneutrality.db; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class MysqlDatabaseTest { - - MysqlDatabase db; - - @Before - public void setUp() throws Exception { - db = new MysqlDatabase("discord"); - } - - @Test - public void exists() { - - Assert.assertTrue(db.exists("settings", "skey", "prefix")); - } -} From 7393b3ecda0be1b0cf44159d10fe0df733d94627 Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 15 Sep 2021 14:36:47 -0400 Subject: [PATCH 025/155] Switch from MySQL driver to MariaDB --- .../netneutrality/db/AbstractController.java | 9 +++ .../netneutrality/db/AsyncMySqlAction.java | 67 ++++++++++++------- .../java/netneutrality/db/DBController.java | 5 +- .../java/netneutrality/db/MysqlConnector.java | 20 +++--- .../java/netneutrality/db/MysqlDatabase.java | 35 +++++----- .../exceptions/ExecutorException.java | 16 +++++ .../netneutrality/handler/LogHandler.java | 4 ++ .../handler/MessageRateLimit.java | 3 +- .../handler/NewCommandListener.java | 2 +- .../music/LoadResultHandler.java | 34 ++++++++++ .../java/netneutrality/thread/BaseThread.java | 30 +++++++++ 11 files changed, 170 insertions(+), 55 deletions(-) create mode 100644 src/main/java/netneutrality/exceptions/ExecutorException.java create mode 100644 src/main/java/netneutrality/music/LoadResultHandler.java create mode 100644 src/main/java/netneutrality/thread/BaseThread.java diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/netneutrality/db/AbstractController.java index 1bcdd72..e1d33d8 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/netneutrality/db/AbstractController.java @@ -10,6 +10,15 @@ public abstract class AbstractController { * @return String */ public abstract String getControllerName(); + + /** + * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class + * + * @return {@link MysqlDatabase} + */ + protected MysqlDatabase getDatabase() { + return database; + } protected void setDatabase(MysqlDatabase database) { this.database = database; diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java index fab9ce2..63b0d99 100644 --- a/src/main/java/netneutrality/db/AsyncMySqlAction.java +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -7,19 +7,22 @@ package netneutrality.db; * https://discord.gg/CdFcyQ */ -import netneutrality.MusicBot; import netneutrality.ThreadManager; +import netneutrality.db.entities.EntityInterface; import netneutrality.db.models.MTableModel; import java.sql.ResultSet; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.function.Consumer; public class AsyncMySqlAction { - private String sqlString; - private Object[] params; - private MysqlDatabase.CommandType type; - private MysqlDatabase db; + private final String sqlString; + private final Object[] params; + private final MysqlDatabase.CommandType type; + private final MysqlDatabase db; public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) { this.db = db; @@ -29,28 +32,31 @@ public class AsyncMySqlAction { type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]); } + public void async() { + async( success -> {} ); + } public void async(Consumer success) { switch (type) { case INSERT: - ThreadManager.executor.submit(() -> { + ThreadManager.dBExecutor.submit(() -> { db.insert(this.sqlString, this.params); }); break; case UPDATE: - ThreadManager.executor.submit(() -> { + ThreadManager.dBExecutor.submit(() -> { db.update(this.sqlString, this.params); }); break; case DELETE: - ThreadManager.executor.submit(() -> { + ThreadManager.dBExecutor.submit(() -> { db.delete(this.sqlString, this.params); }); break; case SELECT: - ThreadManager.executor.submit(() -> { + ThreadManager.dBExecutor.submit(() -> { ResultSet result = db.prepareAndExecute(this.sqlString, this.params); MTableModel table = MysqlDatabase.convertToTableModel(result); @@ -60,28 +66,41 @@ public class AsyncMySqlAction { } } - public void async() { - async(o -> { - }); - } - public MTableModel blocking() { - switch (type) { - case INSERT: - db.insert(this.sqlString, this.params); + try { + switch (type) { + case INSERT: + ThreadManager.dBExecutor.submit(() -> { + db.insert(this.sqlString, this.params); + }).get(); - case UPDATE: - db.update(this.sqlString, this.params); + case UPDATE: + ThreadManager.dBExecutor.submit(() -> { + db.update(this.sqlString, this.params); + }).get(); - case DELETE: - db.delete(this.sqlString, this.params); + case DELETE: + ThreadManager.dBExecutor.submit(() -> { + db.delete(this.sqlString, this.params); + }).get(); - case SELECT: - ResultSet result = db.prepareAndExecute(this.sqlString, this.params); + case SELECT: + Callable task = () -> { + ResultSet result = db.prepareAndExecute(this.sqlString, this.params); + MTableModel table = MysqlDatabase.convertToTableModel(result); - return MysqlDatabase.convertToTableModel(result); + return table; + }; + + Future future = ThreadManager.dBExecutor.submit(task); + return future.get(); + } + } catch (InterruptedException | ExecutionException e) { + return null; } return null; } + + } diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 6d156af..7217f7f 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; import netneutrality.MusicBot; import netneutrality.ThreadManager; +import org.jetbrains.annotations.NotNull; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +26,7 @@ public class DBController { private final static HashMap controllers = new HashMap<>(); private final static Logger logger = LoggerFactory.getLogger(DBController.class); - private static MysqlDatabase database = new MysqlDatabase("netneutrality"); + private static final MysqlDatabase database = new MysqlDatabase("netneutrality"); /** * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method @@ -45,7 +46,7 @@ public class DBController { return null; } - + public static MysqlDatabase get() { if (database.isClosed()) { logger.info("Reconnecting to database.."); diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index b91191c..b892f41 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -1,17 +1,17 @@ package netneutrality.db; -import com.mysql.cj.jdbc.MysqlConnectionPoolDataSource; + +import org.mariadb.jdbc.MariaDbPoolDataSource; import java.sql.Connection; import java.sql.SQLException; - public class MysqlConnector { - private String dbName; - private String dbUser; - private String dbHost; - private String dbPass; + private final String dbName; + private final String dbUser; + private final String dbHost; + private final String dbPass; private Connection c; MysqlConnector(String dbName, String dbUser, String dbHost, String dbPass) { @@ -22,20 +22,18 @@ public class MysqlConnector { } /** - * Connect to a MySQL instance using the provided informations + * Connect to a MySQL instance using the provided information * * @return {@link MysqlConnector} - * @throws SQLException */ public MysqlConnector connect() throws SQLException { - MysqlConnectionPoolDataSource dataSource = new MysqlConnectionPoolDataSource(); + + MariaDbPoolDataSource dataSource = new MariaDbPoolDataSource(); dataSource.setUser(dbUser); dataSource.setPassword(dbPass); dataSource.setServerName(dbHost); dataSource.setPort(3306); dataSource.setDatabaseName(dbName); - dataSource.setAutoReconnect(true); - dataSource.setAutoReconnectForPools(true); c = dataSource.getConnection(); return this; } diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 23c7e54..39a8484 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -8,15 +8,16 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.sql.Types; +import java.util.ArrayList; import java.util.Calendar; -import java.util.function.Consumer; +import java.util.List; import netneutrality.MusicBot; -import netneutrality.ThreadManager; +import netneutrality.db.entities.EntityInterface; import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; import netneutrality.exceptions.UnimplementedParameterException; -import netneutrality.handler.LogHandler; +import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +25,7 @@ public class MysqlDatabase { private final static Logger logger = LoggerFactory.getLogger(MysqlDatabase.class); private Connection connection; - private String dbName; + private final String dbName; protected enum CommandType { SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"); @@ -41,16 +42,18 @@ public class MysqlDatabase { } - protected MysqlDatabase(String dbName) { this.dbName = dbName; + String dbUser = Settings.getInstance().get("mysql.user"); + String dbPass = Settings.getInstance().get("mysql.password"); + String dbHost = Settings.getInstance().get("mysql.host"); + try { logger.info("Connecting to database..."); - connection = new MysqlConnector(dbName, "root", "localhost", "").connect().getConnection(); + connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); } catch (SQLException e) { logger.error("Error connecting to database. Shutting down.."); MusicBot.shutdown(); - System.exit(0); } } @@ -83,7 +86,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - public int update(String sql, Object... params) { + public synchronized int update(String sql, Object... params) { return executeUpdate(sql, params); } @@ -95,7 +98,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - public int insert(String sql, Object... params) { + public synchronized int insert(String sql, Object... params) { return executeUpdate(sql, params); } @@ -107,11 +110,11 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - public int delete(String sql, Object... params) { + public synchronized int delete(String sql, Object... params) { return executeUpdate(sql, params); } - public boolean exists(String table, String key, String value) { + public synchronized boolean exists(String table, String key, String value) { ResultSet rs = prepareAndExecute("SELECT 1 FROM " + table + " WHERE " + key + " = ?", value); try { return rs.next(); @@ -120,8 +123,8 @@ public class MysqlDatabase { } } - private int executeUpdate(String sql, Object[] params) { - + private synchronized int executeUpdate(String sql, Object[] params) { + logger.debug("Query: " + sql); try { PreparedStatement query = connection.prepareStatement(sql); @@ -142,8 +145,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} */ - public ResultSet prepareAndExecute(String sql, Object... params) { - logger.debug("Query: " + sql); + public synchronized ResultSet prepareAndExecute(String sql, Object... params) { try { PreparedStatement query = connection.prepareStatement(sql); @@ -151,7 +153,7 @@ public class MysqlDatabase { ResultSet rs = query.executeQuery(); return rs; } catch (SQLException e) { - logger.error(e.toString()); + logger.error(e.getMessage()); e.printStackTrace(); } @@ -277,4 +279,5 @@ public class MysqlDatabase { return table; } + } diff --git a/src/main/java/netneutrality/exceptions/ExecutorException.java b/src/main/java/netneutrality/exceptions/ExecutorException.java new file mode 100644 index 0000000..398236c --- /dev/null +++ b/src/main/java/netneutrality/exceptions/ExecutorException.java @@ -0,0 +1,16 @@ +package netneutrality.exceptions;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.handler.LogHandler; + +public class ExecutorException implements Thread.UncaughtExceptionHandler { + + @Override + public void uncaughtException(Thread t, Throwable e) { + LogHandler.logThread(t, e); + } +} diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index 0e5911a..578fdf4 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -22,4 +22,8 @@ public class LogHandler { Settings.getInstance().getLogChannel().sendMessage("Error : " + e).queue(); } + + public static void logThread(Thread t, Throwable e) { + logger.error("Exception thrown in thread " + t, e); + } } diff --git a/src/main/java/netneutrality/handler/MessageRateLimit.java b/src/main/java/netneutrality/handler/MessageRateLimit.java index 7751081..3e19285 100644 --- a/src/main/java/netneutrality/handler/MessageRateLimit.java +++ b/src/main/java/netneutrality/handler/MessageRateLimit.java @@ -4,6 +4,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.PrivateChannel; +import netneutrality.ThreadManager; import java.time.OffsetDateTime; @@ -11,7 +12,7 @@ public class MessageRateLimit { private static Member lastSender; private static OffsetDateTime timestamp; - private static int cooldown = 500000000; // 1 seconds = 1000000000 nanoseconds + private static final long cooldown = 500000000L; // 1 seconds = 1000000000 nanoseconds public synchronized static boolean check(Member member, Message message, MessageChannel channel) { diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index d049d54..cf7b4a8 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -37,7 +37,7 @@ public class NewCommandListener extends ListenerAdapter { Message message = event.getMessage(); String msg = message.getContentDisplay().trim(); - if (msg.startsWith(Settings.getInstance().getPrefix())) { + if (msg.startsWith(Settings.getInstance().get("bot.prefix"))) { msg = msg.substring(1); String cmd = msg.split(" ", 2)[0]; diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java new file mode 100644 index 0000000..4ab17ce --- /dev/null +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -0,0 +1,34 @@ +package netneutrality.music;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; + +public class LoadResultHandler implements AudioLoadResultHandler { + + @Override + public void trackLoaded(AudioTrack audioTrack) { + + } + + @Override + public void playlistLoaded(AudioPlaylist audioPlaylist) { + + } + + @Override + public void noMatches() { + + } + + @Override + public void loadFailed(FriendlyException e) { + + } +} diff --git a/src/main/java/netneutrality/thread/BaseThread.java b/src/main/java/netneutrality/thread/BaseThread.java new file mode 100644 index 0000000..0c00b7f --- /dev/null +++ b/src/main/java/netneutrality/thread/BaseThread.java @@ -0,0 +1,30 @@ +package netneutrality.thread;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.exceptions.ExecutorException; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +public class BaseThread implements ThreadFactory { + + private final AtomicLong threadId = new AtomicLong(1); + private final String name; + + public BaseThread(String name) { + this.name = name; + } + + @Override + public Thread newThread(@NotNull Runnable r) { + Thread thread = new Thread(r); + thread.setName(name + "-" + threadId.getAndIncrement()); + thread.setUncaughtExceptionHandler(new ExecutorException()); + return thread; + } +} From a2d3e22b9ad0f2ece26d217af4c21b76fa63e142 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sat, 18 Sep 2021 16:15:57 -0400 Subject: [PATCH 026/155] Update build steps to include manifest --- lib/jansi-1.17.jar | Bin 283202 -> 0 bytes pom.xml | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+) delete mode 100644 lib/jansi-1.17.jar diff --git a/lib/jansi-1.17.jar b/lib/jansi-1.17.jar deleted file mode 100644 index dceada8b606263eb94f7c807bbccb7eb2a1fb9c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 283202 zcmeFaWpEuqnk8y6Sj>_I7Be$5Gc#Mv%xEz)SmE|{DKfR z9I(Ge|L{iT0L{V`P}jenynzV>(q#>8;K>zhE2T2CqWvYIJcZ;GEIry{vY)eKNolbV zaz+t^h5M`feuS@&=ba|YWoelHCr%`;n7>3OCJKZWjYR_8);E~oz1f1E_wV2VoUS;H zQgQs|m&VBNEQ%5cF7&IzmU9(}igVP2fn7+D$5dQCSP2k7r8 z8UX1kPiE;h`cGnMwt$zFRe(JHIZ7|;FSkr7HJqXOY4`2*4gy1&GbT;rF*ZKL=rhl3 zxODXy)k6;X7flMF+*Oa^dCaG7kDXSse1W}IYnqNtFvZqQm6#wST++a0LSAiIC)nxV zUUkt9RjyVQl9Lk&dl~iW%_d~}7eb2gmqq;L;4&$qL@1+y6*+7TOnC2@v;^sYRH?v- zsK@g5W)8)3GF|2Ni~!Gy!%Rt+uov5JWCbg*nk-UD(^}~?OCE)8p_10X#oL_5U}xo? z%(P1%d9OQlY=|r?6O1#&DKp7-LJ=rF4$P@$5w85?x%=We98xR6=Yj{3PHeSj%=5ZY zyYRB{ll~{w;M$<$@L0VHB2}Ad)4EAt`3>w}Mo=mu{^(zZ5GwGO-y`bp4L_#;ID#y6 z9Stn0t!#~`3?1wY?5rGY^$nA%U@V6)4;u@cWfs} zmkA&o=9`>MD}>dnF+n0{ojgww5TOw|8nQ#bKCmBveXWfRAS>KxWAAWty036@0i{+T zBYKSIv<+mE!4CDix*hh^SZB>RJ?XsOV2uEwf$!6*w$Irzw}nCN*)lrNW5MXsEHWk# zLzmAT>=ry0I@zASnMad#=nWT)V0o8Rm1xR_h~vmYxDDuT{7(B`8x8Pk4&3F>?nlpG zxf12^4nlq^2*J7pgo<$qNYRBM%6i+lr zG)R3}dw%16C`60-TvR+vSf`>qI6H!oeVxCx>xi<(M$#zivWu<=N${pg7u;5U&jX2s z6pK7ODgwd>C`#Cugd${3m@Kpamf5SOEFf1JLz73S9{)U8CWXzkMx3eb_meZ?dzkqn zTST|9H)DGDUc=K4LVAB_pL0Ew6@C)64qe8Y--tC=&kRKc@Hwz4zy8uIj^ zaP;V-2%^54z)`e!oiT8cZ@>AN-f3t7p(trCpi_uGyNpaSy+MAFjFzt=T>`zNeR!+s za2+PtLs^ubxIT1anug|5*$b;nR_nz_&+GcjCd}CU{OCxU9$0;{;$8dxR&hkD_QMP~ zqTM!4dF>L^sNAXC+@?ZrUH(TS)O+7zQ7%AQ%E9&$Or<_ID#X}w9?Wsl1(t4tE;5UK z`A^raSA~#j@YpXW&27rHxbf?@`)-=8x`;(fDZLmz30t)&&sx;;Q7Z@7VXITZ8z)ji zJ`19i>*b{4<*HKBX3wd+437c17d3DwSVcmTELmg;r8M`T;y0@}e5tHclcv3#GKR{{ zkf!*%W0+!}ksvc&y z4g1xv`4HgQCCAM&PAHmlY*a6vwJTvCWP4Q+;L2oWl(F(Ecm3iZV~X@k1%FaT7p}cJ zrEa$kU$rqa+;#$?CuSRIJF!(QJuHi=h!_W8sCfPL-TP1*ZwUnS<%=fhKl-;Z{D1!2 zOm!{oOsN0*O=)OrV4!FBgP!h>=1qcsvW-8P_W1tEd;aHs|LvqF??@#kNg*mJD^jdr zO(7yNE~0oTNg+NaPcu(HU$aXlPDwUCI#I(oTeB%fJxon`DN!{>Ew&&|PANq>PE9E$ zH8&zQN>$7n+IcPD<6*)q3|H22PZZDQoETcJuA9+r{BhfAT7W zMG7p7K7op!tp)LLY01uh_2g|6^C6;Lcst@d=vRg=`0l1g{U!SM)w9k7Ck6rtV#GLN z#2C_1&k+8{iBin$57YC*#j`9Ugsn~rEDkSdqy!3KTCHq9h&Vey0uo_)40r()Tv3p0 z2uRgbAtYj4UOTdLq;LGaAP6{65KJg&m9(1$mkf1Ra42$GPc4XeoL8++?&o@hB_q|z zs3sieZQoMUw4o=kqLj~_GX(tX;-WijQ+%>_2)ju|5VvUu(Y9EVK(|zdbR=m=&p2`b zPu+r8euc1(gUck#P|>lC3-&4an`c&qf9darU^|4J(sB0oJcb49;m^D}(Yd{Uegl77 z?r1yH4hKEpxAzDgFRxgK68d>U?%d4tRsws-{j-EQFvvU08(K9tIS$7!cRJ_?9wie& zE?#GxiI1}wA6p*oVf?5q2flHCryGI{SRO$rX`=8DZ!3gMu(1RP3gooR@EHq?vrikp2rAcT{iv``BIHL-(2Jhe8tZS1ECG7rC1YBy5(w=!ccP7F_eNDt<(& zT=h;WDd|SQcKxgv6EH(#tN=h3SnBuFw+N9h zxSFS$u)QN4gfFsAkmqBn>HfVBkd6J_$(iz)kY7rpQsesCjVMht5J$VB-RyVWU{Uld zHdj?g7TX3O3Xt!a?COp=-r|H*yv2JnPF^X`E67Io)O__3It@Lx&rOM=WX%vv_?(lb z6tHD3Lw^L8Z`NW5T}vVSeARH7qE-gF%(V%i7i*M&BDwy_BbuL}xDe_Gj1IxouL0F}Y|jI;ygmdY+sQ!)|VoG&mA_&8wl zlSc)lycEb*Myz-$k6w^6*Lb2v6w70BNW;_O!)T5cdG7Z2glLeMCPLj`8tL0T%G)l` z{RnD5%zK78K#4}ooG{BErzd~x%n#RIPlhbE#6u`k2#}U8Ya80R6rziwHx@xpBe*3D z?(w^1a!`b!RTBWr42FN<0ANo)wU9r8Xg89b&L!UU5txo2#|{_%HdJ8)3XnIao`)PY zj_iEDMAryA5g+8J;2I-iplUEAb*6%0Nf8+=-&Jj36E?j=3}D1#pNv3^8=A^4W1R_~ z;v+3Z!Li55|1&rM18gmUpyb`a+y_#hW_-;z{F+Xx8q6Au+E)$5C4f+cDSS~5wLo9p ztAeU!0x|WPoygKjVL0<<%oM%U!nI8C>#DSOm-05>`!&USg3uYHLQkQqAJ$5m%UZ|C zB=B1|d&-pGQnRV##x&HxVW~=aF7P1*Ng)yKd)YgqLhjd>bS(=}97zRsX>g3#4plzi z3~J%=j!uJ6BYppn$9a5h(o}@Q));HW6EPW=-IEjmc@NVykvc*WGKB~%=ijtA%&oTxA=&_o}5CR6tbBJ|~#JTkIk652G3=QFoSj$O&$<{^i z2ijuItKsO$uFozuyOwQ{{9c_pXsZaQMpHrqw6>Umws6IhsDU95v9%Rvs>Dd7^)r;r z(qen$eu&BQN~1S)!82@*pW?ndvvgofB!XR6Ku2aK=n#hg0Fsz!fDa8KC>21rbR^Tb zNT5JixjiiY&{hVRk2Xer8iV)=0o8;p2*EbTEpGfO4cp{+OO9TLR@h6u$|XITRK<#U zC~|Ele^XrpBj3e=4Sx`5p-IG!Ru7ed4AcG0HXf3J0*6``6iNl*SeB1lsmhwkO&GU= z9avoQmOmU$A*$;(MAVZbX*)>V7Foxk2UEo-vW=FizSfYMGYDzC!H;8=r+gYOlxCPX z7rvn+FLUMYS)Zic8dy`=5UbGD&}4^*^tm6Ju(ABR#P<_FI`J4!WjdPMuh!w7v6Ct0 zQ-jDGBm}CdzQhJCLVMy5#?%M*l6qXWSp~*KCWnbxLny9GuWc0u_q3C70`^t0y8SM6 z!HzIbS}m%BzJA5rrSpLZ8V}W?I*a`*S@Ls8lcLb1{-;ua;1yBUFr>(KRA36w<=NwC zewMUF%u2qNWQ zx}-Noh2alkR?w@2$DvD0B{yStPU$W@m{J_$xtISE zymiAGOcVwo*vAKxNPO(^q9_upinG>o40`{}73~ z4xvh>6V5>0m~-W>&6AhZ7b*5Qhg>~eM;;N%o4WMwUTmM-N)C1q;fU0y*fFG6Gf5aT zzBlM%(s0oPK0gysa0L8iGq=}(|Lr33c-w})zDa1k*cGiI2WfKIdd(IJ#aa@#ToH-9 zSTTPz$$i31dJ$xFJiKotQj7|CBOCUPccT@lXq1V~tlW6EoV@KB`*ID`EW_RF@npCSI_%=?&FX3tLDg; zlg#sV?VRs*Cnek>M_k>gq-$y1qEmb$8`#=;hmw)kx?&Hs?Gi^^+XbX+15ZqOEoVDO zw}aRxb$-J*Uck11a zy&7$ciRt>Idx~d9cJX`2$VPg$+|(PC0`}%HMUuJ?D?tIOW)}#hRZFGIXJIZ|gxa{P z#w;ltQI>WmKWh@u&<;MCbhGV`&Kwa zJrx!n?Xn#?Z^g!1_0RK$4Z7|^RuTr5CHMEPosFeq1&J)J*zHVCo)qkwt*%F{?zohO zTb{H;} zI(W=UZK(yGqLl4tAV9SYQ@8n!bN_|Mi{t_Am_UB{qDKCY5beLjESMPnh*|tgEZ}z= zf6D@}hN>XFzat54trftfAZ7<81Q?qh;#xkdGa0Xz@LFm2F15>#K@D5Gy4~7Gb7m?x z!#kL@&q60eZ7(MAo}~`gHPT*Ly2Fc*nd?f0ARyVmq?^CL!`2z;ATBuloAP0N-CL#g z-@^g^J(^Dr@W}x_Ilw0e_~Zbe9N?1!d~$$K4)DnV{?Bs&x<692%}p#Fod0lbf#+Xp z;cxN(KUxKtq~H73RsrnjZp6s{pEZDpmF>m9;D6oUQ-je4_tP^#6(eKhggu z`u{}#pXmP+{ePnWPxSx)OZ5MT`ajQ~Bj*32{{Q!(|51s5a{%qM+Xel%p#M+p|I`2T z>Hqok|9tv?KK(zR{-00(&!_+A)Bp2-jsJ)CkFdF=uDyxlpQU4Q|0@mrt@4jG)b`u? z1NUX~FU}wK5O6ij?4qo|##@GO3gbA3XQA^KCrm^XKX#u68ME3&uop=NAq>$3@W;78 z8N2Z?2T~k!@YpLE1B?nlT)qeL-^LP3CfS>VSis2LOf1>?QwEv0rKhgdt+W$oR zpJ@LR?SG>E|MO`7&(eIIOe}v`IobW8$^XyNeE(+~e~bLFhG`+aX`pzf+9uhNQYi~V zLw~ZcItMKZmGR??s$boQyq;Z^1j8e^)^HiNc48T$kf2E#b<~m#B9Op@pVciVUo*b= zI5()HAPt{Rro#~$gQRwYQhD@H-(h7Js5dK>p#DYjzgf>9()*3?js776__OVP{x+h& z@&Gft6{c%9!)qKkX)Xec*f>q?6gCF8VtwZ0zUl$F^1p8Q<45q94S#Y8HHkjnP+;XY z`70Efs1IO+8(S7pQC_|ry*CE&-HOObsk+

p4Zj1$&@OI=kB3>e^ehaXnADJ@N&O2j_hzN&nU=4}h(%<@1m4#S z0`zR!Yt=YEqya8oyOgn9%&|Tc4lYw{^HkmM1C`%>3W7z0tn=+rylN=K$FYpKGFDWM z&1&qA{X$~cFJ2Ore{RKtu$3_4Y)4r~$XzQ-$9aKLw{;%%yB z1s4C-?Bczh8SSnj;P4(>a~)>=UifVVfI~B9eG~s#+3WHi4gL~!5I2+n8O1wA;V}ky z+J>Kxj7%a)E||Et0P*;z$rZzZyl*}fA1P?44BvE+ZB+p#5)|;SC?STPWMIZqK;8sG zKuXaipeuS{8}yq{{5CLnPlBqZuTBlj8tS7f9UsHq9FdIS3#qHN$(hzAY79{5$z zbVK_&5a9t!SU3+59@C%XO0fL09FP!nIMd&j-fGOKovn9^qO9>zqGW^{h+P_`K!}PE z7N1#e6gHb?;`T(jFTJZceT)w%q&>FTKr~{v7;+F#jlQVLszQWn4DgufdGxj+zU=lo zU`uXEk!o_)i#Om{kD4fg$pZz~r+Z29rSiH9Xk&<>k+qhaey^g92m(8qyI(2k>lEE4 zP~>UMm=-WkdC|77w0K9KEgV?vI5Kx@(FNY7b@V zPQY>};A5ReCJ~5E5SY5Ui8d|tqnAtjI!s`Fg262@Qd5}Q^heh3?Q?4RqHduXSK{n) z2`mo}84SdoqnEzgJTH+S`-DtQ6}v+_%v+Y}3oRCP3-s-} zp*pYFr~sLp1^P`Bd&h4=#j&HrASK^*ex%1_$bUA%-r8-OQ~Y4;bo;kUxcP$#<0n@xu_s3*%xeLD~6f z4ivU}21X(2t5>@+NYA2rv|%{@F044uLH%fZrlUepCKE?PFKuPPeVxm~MELYzU_8$T zQ&j*GZShQV1SNm2z?_vqX2O79142GfA{L4Es&dffS{t{#Yp}&{9-WaaI_-H0b^sIx|2xm++$~CXOxm#i!Zr) z`&BY=6DQFb&8}u`no*BdNjWQ@eQyffw9PaT!||=k3%&2`EZeH|Cv;5lDOiH#!Y&j2j}RZC52=X<5=whM?vKw!?(})PnvrJj}$X z`ft6AhCj9fU3gNAT>Wp@unL$1j-lPAssz=1eT!s&DMQ>bSCDK$lk1MEmL&BU^ zhmv$Uz*Cma8^jt?JsB3n3qlAeHQ)Gn7-XEHUzCq;5i{8nQ9fa&*cflo`!95KbPK*T zney>9FOCWBaKLo0-S9ev{~YvvtUfD6jzd@nZ|j`N#>boqHYYchDG69bMfrjeFKJxWG|OToRXPd%G`TSsh|_K`+y?Z zIFV_n)o#HVEB9!=nCc~kLXPY;J2ioatUjHkXOCqplGxWy{Z%46aSU6Y_G>-U%YzYf ziFu)1eoNLtjnpafXZv*3vb4>bJnCDGJ6&Kebj|bl&FT8gX_ld?K3;_a3_>U>oX|3ESAp}pC5=#`Wj=uWIb~&1~Q!a}B2Ky*DIq> z1-ack)NYHKm&<6GR!qsif`zpFQC?Zu=%QZ;d$_MoQaiDy+w?=yNUN_7+PfIn(!#_5 zh?9`k$1e9yzX72pk8?`-K;G;l6%?mS|n$1pl^Y0k*jm%=;!7lPjw? z!64RBGxt1HGVR@9)bCD^{`>UD6HzJCEU6A;tw6z6P)E}3SKhJC>;fHS>o&EHD)9GC zCgo@ks}K>!jSA$qR;c@v{Pt2CrRs81O7>hU_?F@nv|M>k&8ZDc5JWx$jU0mrR{t9wEeb*x0fA0WPPVtXq z?th6I{9y*bzeElGOAf$)q6R^DR507So49)4>R`eN%C^stpH_BI@$m_64P8d9eOIPN zt#ujd-lmWF5_qaA%nRoF<0gh4dVguwWXc!@-g}eql5Zj@Ss#7#B)x#+T$^T6Yx@f| zu#+1_{%@iN|1lHblNx+dgHLMkNew=!!6!BNqz0eV;FB7BQiK27r~%oZIAH$BAM{6N z`v0^M=s)cZqGvexC(i@m2mb8?0t3Iw6LV4e9rItjL4V&D^hYTZf9?D4wSYP04Z9f@ zIL`@fTsjUO;`$l6%?Nr!K9d9Y1p+7tFb>)fN@BA5-Pqk%mVl2prRtbvo0NQ~+boVK z*Sh7m+oKuNy$)4F(iB8oQlpBM0n3JP@K9%orCW!WoyYE{yf-4_r%22K|4H--WnU>H zNKRI_5UJ)h?X=kQEAd=IU>medr~+_Q)BZlhr&)`xIB^VkBGE8N6hvJPH`a*Ffe8Ca zZ39R9ZO19Zv&nk?vw{v@KV)i|0OcSXe@M~q!0{wmq`W`Sqcw1cWqNBk@{$CBDGO7Q z8JL2;;t9Z6krzGVmNIC)S>-Fd58t4K`iDX*C59FyCU{P_KuwH;<=BB; z9;4%^iscIUzG}(OV*cE zn1MY2?wXnFn_r*lFwaX70tSG3pU0ta0 z*ITm(vjxrJMl55}NAyTh(>u&0@OI@IlLAb~)S}Lyu?$G9U0qBb8D;<%ajl@BM&%^Y zW4Dv3Y1FTRh?t}_Nj3wv2X67v({t&En~R*DM{YM_ju&hmX2PRqD$9XeVZf0cE9U2Q zJ+K?}`pcw5bO;O!y`Wx)B5Jj0np>=(SQ5Y}y?=6rbWF=L zn_~a#5^oRu^D6C&$qc^clWLVftIP=>`<6ICQTdcL@1ZaGFh;CRk<9oFUSBpHw{(>+ zL9#%z)GDG+s4d8ZlqXx@!`H{YBYuF`$fczg`r75rIf9oC&6*OrEZUI$^1A zpzae!9ZOM*LEIMR;iu>ZBT)!B^-e;^H+Vpu+2(Gp@%&h-8&L#Jc_%t^h_!(HAliAh zGqbbMS8_B#QUBS-=4Ak6#KX21rujqZ&|S&VZpF{lK}V5lvsgS7?YxPBu~mU|&I6Wt zp1kpvfa5Dth&S~iQ`EVNeyXhy3{htGx%v2cHxDhY?>j%t&gP=Wy3Ut?p%?-Gqw9)r zMZ39TWkA#K0Om`~&fH&o_G`}R_E_S5o**drRKnlMypDrgv69JzTviO%BI|$PiU1;T zhb<#M z(QmA{&$m@3@$m}-2I{oMT|$33Q;KH}AZ0pl z<}1xiWlBA%8l1+gFGHHk+B_UQk=%rbR=3_gb_$*sVXbwF321lf?r&}5Q3r7Jspe;U zkCxKesTfng`sL$pRY3P1*^3x6y~jJ9o}}EB)$Mtn{_a=IyVIFJMw1iV)Meb-QVR}q zAp|jpC0-c%A|~OVvn*nr*6VJ0HehJG)_zc#LJ4+-EUQ1{*ceG_H_ot|1|7Qc^P@KM zLXqQ_?sy_A>adG;!a_a}UrV+V%&py+TiRA_@?r~R4US<0ubVwdeOkmz=h;M=^rGZ1 zyB<;U!1tZ88IH(sdQgw9cOXZ4GKy^U+w87-j)fGa#7@Vuz5Rg2xCI=o5BF8O?k@j@ z3+V39o2kV!?ME$2q3{sN`Ik~zr;Y#z&2X36jFFZFyi%kuYQl-^rm{KGODbC)xc77M z8Cf(6TaKJWBlGJ_*OWAgkl<<`f6YoGtM0|3`h6-87}`I28Dad#SMT{Sf{y>i^H4n49SR^^hMbJFC++7k4DVcdm6sdd{@~kr+cZFklhB?*QHK0z93J zJUmg>B0Mrt>~P;P1FRt+(cox1L3x1%`@SV={y;{yLgKhok%d=)lZ6NJtqua$dTP%& zK0Z$tg)Mz~YW1v`!0G6eP`gC2yJrzJ5ntJ` z{GsQiPADlGZ%)W>QbF!$m)wCNqvcp@kZ8}LSaq2|Qm9ZcZz1u{L`ll9aOk_vEZ871@7~Zjf zN8)4&P}}i{NBH4fy4I{g9!MMA(VUcC@a=G(a>{5A2<@#Ye+5B>5P1T3>pMfFNAW5V zNdmR|Z82h=dz9AD?X*EVb{kc~kxCz%)X{BsSKtJO2!*1h{BC{ys^N$Qx$Bg!Y|3N_ zRT~|WS?MPAcn%i+5wbLNyQa^De)n^H0FytT$qdkbp=9ZTXJ)_IjiBR5;sR~L7v{8U>V35VW*?zA z(cWl=M>R2bv_0}89m&|IynF|leHrIFFQm`XP~^0EMLs%7bDwd> z>-J%uJN!?rV7Hiaukrb>!SG&h2)$j;uR1t@2Q*Z9-`UaS+94u{CF=?4yio7FfFws3 ze!L@MMoO4%245jet;6E=A1KbY*VUbIjJ?C}5J@Cwh8;3iP6Sm6<_Yc)OHh-OVJ#M@ z56zMa0ttsxkyg`K{pd|v%8}_RjDcX5yDv`02Nlt3h>@KsK$TQ3$6&OZ4Jyjp5f1ys zyHrFkHh>hK#9}&p3xQ80fr}B3IaQ|9eK;+fXD1XFKbA~qN>`kw#bi2~3$GtS9FE4V zuW+Oyh=(usq2Pg-ADQjzRX!L8Vc=EXIZJCmh%a>8T)fFmG1=^J!ejv^og^oM{cTDJ zU0Z>Oo|6bEJ}j*~2r~XCy5*yUDZDXvA%l#?L2W9|WS7=-wljNr2r*ykgSs>^JZpRR zQOO`4h6`<3d4ku|S;Hr%->>OSNZH%j4z++EG|i zx8kHZklA#!khV{73vp>YysGmuZ+JXhHbi)g>=%ncH+V|Fz&BYX4K)VSQrkI356mCt zvS`x{3qhXpkoj`e%3I*OwkE*@*2kru^uy2LC-Mv~rbn0sm%Flrgz^JnNlc3N7QKbj z)3SC*W(7Uy%4!NoU7b{UKe`Xm4G_iDq%xMTt1DqsZE}d>zF+|rw$Wu9pB7fj_M&lm zu&Lx3)S3;e(Dfa#Nwv>5 z)QsG;62A|}h)TcKFw!Y^NcT!oL(RMiCNqa%kD$~9Pwh>RGM3U8Kd>~a$_vfesO;;5 zi-+Azg;#G*f|ypyxe5AVe)Nimtllgl){{VmM^}{>`(|!_1V{j;&Sqp5PMLO6-gLcfdO%f^c0Ixp-bLdKX@}wX z5Hwo28ZD7cm|PH>SgVg^Ul=urBU4WU20M-D+FHv7`x;*mdv-g0@B!6D10DH6m`i$B zw$>T^x=gU0{+dORBZcU?uow-C4TJjnX;7M93*JRRljGY{te1i^tlG1ruA(vq;a4Y( zXqX0(ntMt5WhrZr7ZCK_^?c6yfEXDsABu)^2vGXvs8Q2G)lFDH8!RYbwKgKT$) z6p9V*+}9GLr)gzv&gH1KyRId4M?vI{tZYpMSO3O8*ds_7B z3b$f<(d$so{o=EFgf%*Hj-kd1ZQ>u5RXjPGOlysY!A->kJq?+T-P4XKHj+8)2fmw{ zK3%1TRFAe6OZm;vUkKbE_%FGgx_es>I8ln|1UruIH_O;OtVJd;5=!9P-wBDfcvre>oKag0VX(lC~L z9FwR#`!sZ%R9e*8LWrXPOxAs@(q5dUSV46Nl2sP0HE+N%C-X0NC1DG_5Y z(dsxj{S`e!NrTW-^^#akwt#{-vi@qTjr4Wq4tT^CWwz94F{8Y|GI=A1Q_!n9-POP| z@?PR;<_;UE~XZ|M}#ngy0oG!x*E}SLW1hZ1a<8pl}Bts#&Pw0Z3l5OpBFIGYbqLZ^Ja{NY{dPB*b6C^ znL5f|VVKJD?r@q7jChp!l7zuisH)yu;@L>Sy~Q)g*@{ZyvhWCEnJ7r@eMF9nN)+p4 zk?5$Nm&2Y-wBuX+u8*;8}Lfdt=55YDDC(MUXywDmBE4B*|5p-a9QvEdj2x+%2nb|vpow|VN2!Ar<|!nL z`;lmI-ENFuW8VZhi*zb643&G%ZaVy3yajy1Oks6qfq}xkroRUo(st0x#;$iC^JXc} zGX_t}7sozIEg|ncnbUssY=nkK+T~=o{lk%Yp}wI}3BlQ9H=@#j9DQ%q9crhSse&S& z_zVogiHqXt3|h#7?a>EkfU#c)Dctx&C4I;xy(FPo2~PR4N}34`tpxPz>0>jOq&m{y zXnFNYAU&%MtM{mi3vLLT=#3MQz=gw0a+#jao~BY7H_pmZ_zRxICkCG+%2?e&%bw`q z%Z3V?g<>k6N8~e?s|i;|-m6=^)qL;9*oaGA&uUo~Oi6|NX;|q3g6=?!kbsIPgXzPr z)1LSPF9z4%*R*ak>V=CvBXEuU#wQd^ollChvT^wl`ko}!Q_+KNeudwpO5X}*WgOl= zV^r7gFPa?>?6J%HgYlhw+!4=u&A(opESSxH?7%F+A5DC?xtws!yc73t6wO%o!t!EX zDO?MlgcL-CB5I{Ph06E2>ZjRF(wdt|5_vg%xQvjKZDwGeU{S+i`8^OZ1EF{KX6`OKGgqj9 z;w;*+nuAH+g}$>F?+4b?-o)Zg!*LhR*2K$6X9nwaO{GyE(bmj)t=L2-U5b^Ys@Ghq zSI->sPkS}jUMZs@HRuJ{5abue=2w!+{U@H%U=$SUO7gdKok>6kX__TKeTcaG-Y*$o zmG{?OSGCORTt9O>Su>a)Z#9zxK$25ZG4h5?l=hMpTnHL(hs~cQv|N?Sh3B80#7ez{ z3Ola(-wd?BDBQ7AMCL?#PM+`mA80=_+0 zwbiR5sh9EN*!6JTr9N#LSBlbW%+{{mZC$R7ZsGv#IQ|HY%sXq=Sh9nRJ&c89j0mPS z_}(SzlKF%ARTB$`ZbO>=<_#x=aYOqd>B34&r~Tuk`{r%u>%;>!6~l%}zMDj+*uf3M z4#D$+%zb2n>#=@dh-5*}zP7sCJEySnJA-HMou2xU=Eyvq4T*l0S8A&Fd@#IW2uQ#B zX8h_`WO}$lZaus&d20Zs&8ZMs2L*~bUT_N^Hd$v@-l2 z8fn%-Z#x#Sv`}$}!H^+u*ZTfu+EQ449iY957o*r@<$;hT&7sfDAUp;!|cRGsv;_sR;KOs&2HEX5IfS2 zpC+`oGoZN1muS67rA8U-c{V-*OO;tMRkh$bUQ90zUoR{g3>dx|r`eozbm<9#EaO&G zUy~!Cc&SA1t_qXHdYq=J&R0H1xWJ=oGmv{2uT7oU3|vP%f+vk%alv%FiznVU!v2_?_9i9BsrfrBBI23{^U?CdHojO&d7lk*Ww!)SO#hN_t zPsH{!`F>VbLn1%m_MwH*K8Zg>E;_1(+jB&cgpEDdSkQbw;_``hhut~57Nx&N>#ltB zn4hp{y1B!(Zu7Rxf66w23MYZv|KYl3&Y)^<EqHa3wa3xRL$v~%}o66$_ z8fE1bK-2XOxd__N3Hgy1QFse50*(MZ5ok>PsmBw)ovi zRv0?1uEtQ|Rc#tsgZ^&4fO()}UpeijWQLLg1Bw8-Y~g4MSGN5zg?YaOWtZW7EksSI zfN4a03XAD}p%P(EewY>Vbz_m6$O$+ukj_ImqPl^@IH`4%u1IQbUX77f#m-z}V`>yzr;jM*dW15MOLS7vHGlIlIxT)lz1j=`JTsGCit0+yO2} zC zI?FB3gB15Y_`>8#`03;0o%^W=!u1fvi{;b^XdWd6QACv8IKdFJS9+0B4Z0?PV?{uV|oZK)5p9>_`)pWWEW=etEKoc%gpUO4Hm#nf5)?XyAw=%~WE| zxypD&q1Hd4q3Dd{BXsn`>K#PA<%qdZ((TB>Ps`{KIrHmF6zb8Ii_xmSzcU zo&lm7N`BptMaIhWbS+bvot=7Z{>Ryj?TUl>TKi63(?XtP3Jn{jd{ec0Lxjmvb$9K% zy!c3dfx|B~IXQ-W^X^$v$(iN))5+`UkIC)0k3l@cg1aL0&P^artd1rF-aG_aujS$VAQ4}ytzXYJ%v-CgzV&%`AWMb5 zouXi*pPI0>2G(7|*rEi9cM5f&eJfvgqh(swz{ue0VAB;#?tV*&1m#$myP)b8`YDj+ z`0gWF+7V+I;)N9s-0n%FSoqA0F+W&Pj94V~0d=ur$^S`^d=coZ>~_ zb|UgDUL@ZRoArFP!H@J|oSOf%BGWTxs2P>YHzu!s&wov48kZ6}3G78UmfdNjh%HRl z3W4`AbEIZ5%786j0fTA9bk3zkB$NSfDktYsGJ!4mgv}%s0Gag_OBkgfMk_#!OA%CL zaDovCE8*hFJ!i2S_t4C>BnOx(omm3)`=?(7-%J8Gy!9=~5#6kM*MXPeU$`g(-+B6a zYIn9R(SlIF%^EpgEcSG{zQt8~qC`BVt#8}Roak!nP|ue(YF;k4LuU^=GWY{# zn8PVzcfU&u#@h@;tw-9MYoJVn#S~^;*_c^l!rbTE)0~4fzK-CD5f5Z-cWyn!Nrk(? zrQ)BEq@g^}sX5*fiW&76Eqb}*9Pu|_9(;J+Z+@SkDdk>8+&f4APzmoyN(nNpRNaiOCV5hNp(0(!Z{QrjK@OO(7YR= zkwQyBGnEE~tFQ-(?UE3JS%)L36xt%6kb%DQTW9b`D$Jn;1a+4&;=CW-2!dx1+^C_lY(5=;+ysvu zQ#4%(VmXhOS|xIv>aR=S<@pd!(d0V_FJ23a#XyJ39}7NH^-yXxfr$A)CIiQE7tBOq z!VT2=Sfn=(z!I@M#7wDl>InVc?O0p<>C_PeI&oc2d56u#I|Vf}$=!a^Q4_g`7T+vY zeNT7?xIB!f=vRnKgK*l4y49m3y-@;8zX5fv0f=*9?h?qSCeIr^_dBtve6C@PTZ)x| zO$Io18Fr7^>|w#|<;ofL@#`@j*SQBXfFVTEpVS_qLogAQeuNoA?{AjNC&Ptl#~$yO z-FNOrm}QDtlS+<-*rA#3uM{S=W80!-X%A}SO|F5^j7Fb`klAO}XIN#A<_#^T!AGH@ z)U}Acq}7w?=1m?hm*(?MiT3qjOk3k?QZaM~>Y-mG8t$XVhlxlUyC=Zy9dZWBKd7>c z6E_snWOz4Bh?cMmL?@TA#66L0VlZ3{wGCZj7&f5Gfp>55E6dSfq95M!Sy?h00*_`0 zu@O+Jv?5(dL3c@_il^WLX}}IcoeESur3GYXTv2-6~EWgnw0G8-c%bW{hh@){1EWSU3*D_jL;ac-i zd}mLt!oHUZxjUp(%br}3*W-0fM90ZlHL1coGZgZgeWHJfH(lZ%fUQf_hyFHMs^347 zB;8SM8OPokhHHF>V-B?kL#q#Qtni31jAaO#ehSR8A<#sI5nU+1cOi4mLeJ$x%F#a`DFNw{E@=c2>F$zFN$C`jR0NUk zZs``3?v|JChC4_6f8V`p={b9L{C3Pf=UFq%^CTW}U8y8rk6GL~u4-3teKc2P>y64U z`{{rF?JXy-XGi0fH_p0Ry(77_810=_f3D-IR#g#)U%1n!ImV9ip$$q^wlvb+XY{Fu zSxm_tQ9~Bm7^TTd$1$YU%axig8ypg1cOJNk=PuHcLRs|y)GQA(KcRLx=rZiug_2WCQdQ|0N-V?6N z*KweUZ1=S0%{{k!E_GkBQB68}vnma{VM}d4jl{bZX>wwZwXaa`F~``ILNu7CVh6*! z*Ur(9RQh?2<_Kp8eLaoIjg&X@y<6z9G6}WNq(!8F%#nIx;ad0lpKFWEL^+TzOk{g` z6Z-muTA`t#5c}sjPrEq;R9wk=^tnGU8+0OJWuf^>7p9!8ADu|+4=IEk;TB)iw>qyP zM+R`VBsl5R9im6~zr1syw<9M}ZlA2Ij~OnhbqxGs>g?gu-`pGZtIQYIUb%jEjwq;Q zWK&Dsj)7NWN~f2ByL(95n9+)9GlJ=yjrR^_gni>&-Hw;s@^^iZs7$@^T-{?^?S9eh zIfl8E5DM1SJd)M397kcH)&K_XFPAd3IKKI78BA^|q@>UC_LsggYIQ}OFVBzPX!etD zcI!pPa(k=e&i#CTwNz=$x~N$HYc3_w$?Z6c(JhIz*x**r&J3y~$;Q;}jhfJp6Jko5 z^GB44!8)J2y~^&evc&l3&6gyf93Zvgez_L;O4>bOe6z*!_8T#&BN@der8?UmF03cy zQ=NYOKNQthtxkNnO4AgNN6ZtKzuPQpfp2x0Ck9;7Q7Y8G%qqtane9(jW1BUHcZkef zPOEfG8|Q=Bp1qJswBF@vkzUN&G-sNeFyE1?C-k`e_Wa(vyOi-9WnZFxSOgAx;k}lJ zrTSb7x6+R*3}3?aBcE=O*M1qTa`l-a#w0gK^!J~f9*eAcfiDP+SV@Bj=7Lu5FevBH zYMr964+gxvk=H{mA{R%`=WmGn(T|C1I~HWTdDo?{BE5bNH{TGgcV9(nsqW#%F`p5i zuMq8S9u8UFT}HxKOpEz4t$(|WlqU<7xDn|8co}Ki>oc^eVplWrg3Nb`w55dKj*xWQ zuvC699R#2m*=}sK!E!`=fe_e+e22$je@v|Je+joJRd4!RiR`2Lje+x=0nfoB;RD?J z45vb$ZljBJ^GwO)6lCCRf5s3Rl(8nzt=?xkWmwcr!VSxA(LdWejKycEjiaI7{D z_bE>KY|J{^iq&`J`YF4NGw3b43G6GOMKOUlT?{ZxbSAoV6+}p5?EFao@u)_53>KXG z&aSjP!=M)Q_jjRhstOXVW$rnBh4hw4?b3d!P0*HnSf%jYn*d3a4uydQS9mll$AIk# zYo-i729qAVoeOL6puCOQSE74VjVx=!@Y8GL$k>^lu-rZ*^=?`LCvDTuIzw8^3Ol6U zq-@`n#qk(^aPY=i?hENG%@0ds*NNISaJD;HGN5!M_$j^5Bt82~f}-a->VuvJQ3WA; zD7C8&CC6IZ)zi6XqQbFU!QC1ICXDyc5P}8MYCu5O`IJPsKUub#l+_Jw%;Vc2~P8f z3nN0e@^eoFXH~Vw5Bm`vhTf?WTB0YTjj~O#f!IPrIy1f zjgd|?6Qu9k@*eOQj4qc;V>3A8Nvqq0HM{>rXMSFPoN_xzzf3T2IjA|?xiI=+%*M4M zedkv;mf@LITGbw`nfXlTB(S+N;XiK`j+w5t!LhqbAK5`pbJu>J{X8v&COKeP^}{o- zV8u61FqOu(D@mv+x|uXuAu%JyXT)hIJ&yz_Nr(7M0Dw zN<-KK_NGjt$PvNWTKM`mdlM%f?S=j6TEoFdhNi;I^wzpoE!>gDA8U&1A4VFwRsQIrc|iVF%GIMLWiXbz(bpc4s)JcD%q5rCF5Z`g^R3U@^pIr=vWyA`j~<;wnByUcC+=2icX$h4mlYFmQFm%M>WpXQTN;p8KgGD z>Z7}JpXif=W14n_%vVKaYLD}W+KaasU40ppjILApY;u0>b+%KOn%*YEW#KpPZU0)2 zZ=p}8O|D5BTd(q(!PU!RGasN(z6gHD-|Kf0B&v{XjLX|?{bO@%J+}WeD1mED_Rl_Y z?MN)5Lji-gV#vugin2SxuHxKV+=}Fr@wWT*_XAISm=E@a9qM!TVWO{(+vF37bwusw2jwm$w^LMQN@8QchQ-T=81i`PZ0a#+rA_C zlqsKn!{|y`#P^>y#LXCuXcP`O4t)vGEpe4z5C{Bc-p_-_S0<#q^$31TE|VMcv*Jqe zax9C7#5bE=1jLqht6feiFUICyVsH2v)SNVgQkfWjO=2KEu_RG=0b&>f**UECxF4x;j-Wuep|li$MUl&?S$!5Wgd0`Qgw2Y1_nknWp!AlwbBfTij z{Xen184m<2f83N)!Dpe~Y!yAz62b{sgu7WSddA*F9?<&eCa>rj;tf{7K4P?t0`;x^ zdXt>iEy@@^hNT>Qei&6Qb|&8h^*pwcm3dr4VAXHxc~T`3t2p|As%dIlGzQi(S-;0y zw4o;&d|TKNRrooT7+dQOW3vQX>ahnq%$-tfTZj=Sh_brmYC&0#u<{vf-&v2_NcMHA zg;Fka3h_{@QOmmV=O88bNxAaKvI_vJ*+SbFJ*imRmHncJ+&AbvTIWW6Ne6dN_&_~P z%8~97jp&zsepz!QJG)K{_9r04MR3a|_ z5m7`|eGgB5B-(&iw$<42C#cDSwuelT?byqfmJg8Z=K2i~BUrE%Ylb@||H=4US%quDz>3Opob_GJ2WhZoq3nn$>k z^CA&#gIrq{-}-Xi?fnc!_YiQJvZJAR6Ec0U-dou;Cz~UJg~a0}L$m9g6L>f{8d>h` zRo(2|()My`PL`Yp;j02&3aoz!Q;5*VkgN0x`z4R+iH*66i?;xHCrQ$d`^9C z4^2J?#YUf4wGDjuf@rb5Ss6R-!|{BRWJPZNk=zm&UKq2b+pjxQ_mK3K7v%+guVuol za#gQqet$|M8uT}yp+<uWR zD`eO0@2$9j(`NjmVPOfH&Tix@I*pKGy=WI2==NTLmAXSSLLgiUUSH}@f7!TWN|bm= zaWtV^Z`rs}To9U02335lVIeLD3q;dF^b;Cn;u-;MI$)UhfzD*=KaIb7^pK1fVp!$N z0*v7xZUt~{Nk;|RGT%#OnE#6sHxias-9#}wdnc8_a59C9cS`@RYC=+~S^H0U57U3% zUw%>)en&;42cY7Pdko;l`WhQJ)_u#EG+^!V9Zjd%HegEdV`yL5IEuIZ{iW%Y)f2qA zYUA-@N(ZJ6O$p%q1DXyx$aS{N2#L7nsv-9oAB@b4I9AiC{}$wGfGp0ikebtmTQa0L z1mp-;eh8StA7ZpYu)ZF;O{^W7n8{tUoHnPu;qE#i#S}iA3rU8BJ&RGb0OEY{uV~RR z8W_$023Y2v0zh}?6fka0!)ZG-{nAzdt|$RNr_IOmYck@R|BPqBl?00zc=&HeA1Fp) zLv(iqE})B9`(J}_^fYWiP698TO{NO^Du8}!r>7v`2haZjXc{#$z!mzGIxtW)hd@*N ze0gk$Yi5GRfrS-M;}0MonnscdDXuYC2U@mW6p(=Q>>CJawqhTc%tUvAm`*t-`hjl7 z>n}jSZe9st_3SwTU9GbKz&f5L1m?~0uMlm4Ndz|}v3Jb{lIw~?AlV&x3QPq2g_l8G zVmm&-BZiqMRD(B3Yk*}~)C_b(E586;^1cm_g9}szEi1FD69hs&b&)lI&SRn)iY-UoxPWOjq9q{LR zRs;lEWpIF1Y*GNxP2cR;sP(LIZ7BX~s(g8VBIh7nxep4i?7E*jS zs02ACLxrwd6YappuZ$Wb`RW3yno|qJdAhjQU-l}B(iK=sy#+4@E0z&JTiNO@0Z;BC zLqNyHJr@L`*aE#QcfjeNVsuu@ebT-R`|D~(R7B^A49k1pyV9T6V>GU(ClC|(aZw_^2^0B zascybU)~Ko^ZM?u8lX;M2h7tw!( ztNIZ4)M^iu(2ClA4Y&|%N&_h&9&>qv_>jn9BTzUZ(d0(pwD2N5cHqb2> zf_iY(gAgRHgteXn-guodpr$UIS&*3YA_G{ku8u%mLVw>0bSp2XUxKKHb7w$Mp131W zOL;GJ014`)EI>&*CIxfakWva&9j9d)2ox@L0E%w+U%x1S{mN%T@PZfIkYH#N@`%0& z%}Vu+3jkRdiUA%^^(a;W>)L}0uteHQodBYQcQ#0la=8|2QjR-bNHV+#`J(q71isQd z(t*78pauZ@#Op&|if_yytqw}ap64zJ$g?&XKu62>^aG31gAz#hV+?4J|1er0kkVs9 zki!+dDCnPYT_LD9_77kINK4NqR0-ZisLnAL+rV&spcQ(U8E6>5)wcxdM=E>hL6K;J z9+cJ%b>Qg=U4I#{o^m*Y3JcSlMMG_UAq^1k+Vr8|neO6%vfoM`q|6lqO%VSARBpe6 zCM>{;b6GT}FquLHJtOeunqLWksem`^Q}6)*RNZZ3LBB9q@PfW|iGRTYl(cm=K_~rN zdxz$BpuKjpE4qGbA%Vrwojeo!1P%NAQ)kP|?FEHA_f5?VZ1#b-gqqUjRWoAn8%g{h zyiK0rAXU{d)5MXkt|xqAAcuEJ>yXGSD6U~`A?>C%(P{Elxzu&HME0}Liry~7sxy~e zzehk^u>8+qtyqLhj7At*de^|B{dbC7qH`_IEd0czhiK<@BGz&~XXAg@WRfCN&B9_l z9y(wxP9d#$A3k^O1eV@mVCj86HNH&4I_M%gBdbY7Ll(pElaLf=Ul+I5j?watfXBQ5 z(Y)Z4&J)38Dmh{_LJ&N5Z-$4J#yRz){STz#v}@SD1D8{KU( zcXmJ~=o)Udm2)oyYa@<89QKp%5;OI`HwMG)Hs9zJ_$1e6q}kjA|8d=`=GT|3J+@L& zDz>s0T%6)7>H0dQs@PXQ7D&7MygGMg)!NA*FD6P$vX*OlLkN3*SYEw=Y2m!)xGL(N zXnwed2ay*!dx{?s!|uGgwC{b!RTvKCf2yHX&h>=J9dSaSFLn0?*sF9Yr3;$;X2tsbJ-OzR7Xj zqWFU~>G+edE$(qPcJB05pHl^)6!i}q%(SW%STly{PIGnx*XrU)5eJG&_G!Ag8~&{6 zQX8WI3rWiw&G5GG z-9!j);`Zw}&Cq(l^HtbyCHV}>{*(NjB<9bYx2N-bmp^_Xq8OMF*!Iah7&u+K5ne_1 zvx}&6>?ozbNh=<++eV&Ls5XDkFgL1cne6#va)xC8W9Gq*hDTG4`wurU>E=dg)hz;d zlY_{nd~goiW7{M9RwPFRuBjT4joU9QR_y$|E%#d~`GF-xozT}-1ovD-wk(km_?9lX zbdf^To%X403chiP+)<&Ua)-9)4Esr1jc?0EPq^sP^`@hy>tyYlr)2U^|-IVzl zBq-X-GadHPw$7cD-D!3ey}#3&ux}~6-#-A0=sUiH(!Yys*nf-d7+Cu?u-Lw(`JT|| z0hZPFDBh8XY{@5jZ3B>=@}s+0XqX$TLi^*MJCs)K$ZSq0icD&0)xhYy7DL@P>=Ae; zC8C&w(3nwagm}TC_n|N}nK8jfy_^nV!(bUve>26o6PL-YkIa8E=OCLzmdvE%l?SIV zdLd4wawxn>^=UXPkqrNQie^ulEc)lITxk<*qq()X>tP@x1~D0hULAeef77tL>9Taw z1QzEXBxj~zcjMw@-?RQ~;lLp_N3GJ5p+U8If3_jJW~cM{R+Fv*AIbZ!IB*WjiRkXh z68*cIv?=hCo@z+;g3Z~GwAhPH3W_b_Fne({m$h&u2(7o1G#iCwx&GLOK+Elu3U^9` zvH26%T8SAV@rsch%$qpIxwx4x!3Fwm4F{Z)%OAbgaqt!6%}>JQ7L-kkxcTpR)&;Agd`NeJpj6Rrnz{#HuC}Yv(HK z7L;(MlY>nqycWBM&M;Ia8}Y((09t9!+s08KZUsqrK21Lfm%1X9bw9&jp-Fx>MRSX! z<`s&!oOhN~cX{+}m~fO%qDW|AS*8vxMiEb;CZleUTB`0PTSbD{Rh~q+!?Y;tzzB~^ zw%y*Ndj+rxZ)Rt`s|5>e43xdjATw36PX>KC390-Qwv2VSjnER?wfsVh$Ju0A#erdA z>40|5E3hl;aSJ!?mn8xQa?*58qhLa9ek;nyV2Q2J#`>o;bQE8qkTsSaT4V1|_3|U~ zn^%8rAYNby>v3HCyzHJybVU8i_{C%ZR)hZYu|Oy6GVWn@vX#2nEp8;2BBao^8ZVuY z6(r)BDWPoILe(Qv^L+~I{f&*I#6w!rFByVq1Ipd%7`jujd9+zGik%Vz&q&SF1}dBA z<37Ac49BwBkfPz|A8U8tu+Y?L*)`l}sdP&<+3F9p_(}g4LnVnkPmot zm8T*yA;QGyjwVwH97JTqXC`&1TT-RJ3BQwQsOX~<(~inyRJLs*yyOy{Gxkxyr`IZvRA$# z3BiLYT}%5i0y_D@j^Wsp*FgdHpIZNvhG8+(`p6Q|WqVr67{-nVVjx*kI8(m*Rzp~@ zo8pfwg*67#g^2HN@H_}c>qnnR#$~5b^8ue!paqFW$N}dazn0QCk395k0yu zu#*u|I8PmX0w8GRCImTPBu4{$=+VRj{Di;4@V`QQNM;Gid;=jyayXsF($&k?g{c)lTDte_wsNZZzC?Rf(>f@oH`)Hl^gxaf_HyK=xu#bho0$Nm`bKQF``>XjtcK zDgCzmhB_Q6{SW>4S>JDy&JA&6-ko;Md#@CPF0hB7%z+qvXRD3&k#>Sng!F*-@Z2g| zvF~lTK`27djRn8%!p@@^r*+As^FJN^Tw62{$uGf9+4m@K{mep%$Uz1pE43T%Kr!oD zY^yQVkrB5~eSTbRo|O1W*}DMy7B@!ii1$0 zU1e7j5JY(DaC?25I2;B-x_9H&Sb|jZ)O%xWA^4G{*_&s1F!ilW2FF4S_n|g z8=QfhGgFW2Q34DC<%5# zwcTO}TBs(7a~ATiJ5Ar;LqQ2N?v1X>hK-kpTIlIzutVfV?19mNGd*N%^w=vN#ojszcdb!KjW85yJFIWAWVsnoS2kZw_yWrd5X{T^O@Nv#*2(k^zmU5zWGUqOjQFVoFt|1Qmiywdozd$p zRPAj%peA%YNmwbyr1CxuWTr4R^pC2o>{0vt7f!3pP5pslo>mrrYzKUm8lnI9KrMDP zj0dC4fhhHRKWvQWfpjOe80}(i(EN~l3 z{_)H-^}q`U3RJG9{2x#AOicJ8Z}VyP2fwXt2Pe5fpFqg$2-Es?VzWWSjFQ&2MM($PipPY?x)Cu%VNpTyrJ{W_&5L;t3B zpR&wsGVwQ1%2^f4hw!*+nnfPcfN}l)j}rU#-2bnIXy+ISs4^&(U)Rw;iqedh^npid zi29GG#UUi=9@mW{J;D*v^LTcv&R7y`zVs?V6Pks$J*qPZ!W4Z%kmL3VdJ}>@m_~@W z;}ZP+=phWUW8R>LAU`gPwZlM$_wAlM4?Hb*@?|2kp#$<6o9{j=*0tjC}^iUxduz>%510@~)U}JwQZV&b)h=GMg4w@&}j1qOt!B zIzFO32sMSc;re?EFIq*Q)_i(r#L!Gtoeq`u@wcoq{Pi=oN>z~>^>OI{* zkeK^)n7<({d}QDW_*=7)&E$X7e*2*=F>O7Bm!ND9|DcyvYW0r_6&*)YTOd) z_tw;V#=iyhq%KVWcHp1L2mSbeR0^SZa6eQf>&tiFRr(alcoR$eA0~xzSpR=i-?`~S zJI8Fa0>e70Up+@T-48`t7GYiE9Y*uN3_;wsxdP$F5h@g58i2BFj3jYkBe zw(f0&`%wBWZ`FU)lbaU$fA5CNnt#;5#s7HB7xoVcXdRufr274>OW=9$Lv{6s7)-?; z-WSVtg|6|C3+pZ|)2t2XH86iu$@1XL>+;`2y~y73ROb+CMNEgeouliQpnjnjE{VT< z{=PSEx@{f|dM@Ut>%5PV_offXMq{J6S(){ zdI*a5^1a!Ew?=mx=Lepf`{u?2Z~rj@SA+AM{><6DbE!?Rq)~wb!7MC?8b+lZhVu zPb=>t`k!Uih1UP1$BPf0DcXap1Kv<2gbd3~E~sB%&zBcM??&s~-$p04Ve|gf$p+|O ztL;}E5fQj7BI!$H0#-atih3^s9}cEKpL*`ag0IM+53Q`via9U6!H2sKIG6%`koL`} z_0vJ0$ayGl3gUyTg}jYjj)=FrM;ljYkZolf5V6@rI+y+3-MKmB8yG`_656S&iPTwF?Qy$L-ouJ z8T?BI-NM_pn|h>+U}s8!Cr_XugT1|7nELIR=hSWJ2JmyV^GBaC`G3@wR z4{NxlyLrJ5+uTMIun|?{ul7BtIWCV{eIpc}k!7Rgg&AFyAg+RAmx5jbc25Ruz3tu! zPR^!Zf1TAv!r1F+Ua{T8CcOuqCT%h7a3sr}@yO=(1`2>~L;~HyEObaEc<2+@G8u=@ z)o`Cpfw56Pxzd95WAL26@U-IaQx0+dK~RGU4w9I-$Jtn$+Zatk8(M}H>BFnghE|?p zL6iS^+pT@MM*+b13*(qgmV){b>ls~yV$)|f`J7&Y4=DzuOFlpi= zbI0)}hgXc^)fKE+?X2Wnxj@$RSC@71I8vZ4EiBi-2B~|cz4nEvq}}dwF<$i;WUH2= z1bcaAX%_>J2gQ{#0(5LfU#@7`sUKxy**I@e;Y-oVsSB&EBOj=RzFtK$Q!DWKk5G>| z9Q$Tcqn@p43)x=j=kkI#=D?~j;XZ5{5__ULEsDTo{D()DHxH&0Ly)8@wGed z5-oI0WfATI7W0N5l@ifA5Ycz+hyCN0dAQArd-SzBzBPv*2#2IR(K@NBN^3Dw={A_r zWIs62*B@zEEdJwqmqgEC_z`U6PCsm!H4j=d-sr*{6C>xp`_TllRYRE_i?WG7d+3+3J)T~#^ zus_c;WeE58Uvc?kM(DXsqSfb&pl|l(+P(`(cXjjnfy%XJ<1vi85KE1C$&h)#OzdQH zw}VVM7%PF|)^Giz)x0;(A)g_AMwX)OeWpX6^w|C{;pJ@$`~HH|*yfxOn7c%1^UI}8 z^a$EJBRimk_Qd>9$lP{l9qV(l;C#a%IbMJo3M9}+@NR&{*6&LpeUZ@5ISYxtW6K{B zn}}?z)Rcu`J_k7@oB4rT zGCJ?g=XwN|nn-;l#zLszs0!-{^*oOFm2_;yi>KMOG@(^OK~>tZC@%t7u3ST_c!EyS zspcPz;hvm<%_+tpIy>WwN&l+Qg)_dKA!@oo+UF^%WpXbPO4#U7!7tEG8j2Vb zd1Z$XE!h)CZz-34muW+#KGgPO|HTyYjhJjKZ@PoV%8s{=UPvvEE{>-S_1tOT7a!eJ z?mR=>L2j>wD;>tz_WKEKrNQH5@&)rz2bpXczWSl=$)BUWOm_jV1w*CiC|etpaKxe} z8mq~lv%Z`|6QO}H#sdOQf7dAW261c?W9y5<7%st<>A#aImN8OSBsnb5RvL@KX83-_ zMDZ*2Jd=Kd{~c99jNN!RszRWzlyT$_?WMsbt@jvAr<%q}<#~g>v8MC)U5kh<+{>Bp zS==!zvSvPU71E^hsb2c;v$hXty;H3ZX9MjOB?9A_zLNO{dC6$s94_f_RaiTFjHzxV zVly}O_Nz7`yz9OHqt^CKlw6u&4TjWXQEZL#J|K$BCHAYPpf8qwH#+|3je8>Wp5x9~ z%zP5KE3Md)57IM+KHtD;ouIsT9po$A)V~S^cNOdT$zW&qc34^CLuveA<-vuvV7z75@*|*%PY|LJe^*vSmks*_&h4i*CJVXF zOJ<9J;`^$o=GWk_k+0t}5k_3myj_#WTVX!Ea+hr@@m5+h+HR#O3ke{$IpK6_?nbte z-N1h4_2tTl^EZ(rz1EkcYsSg7l`HtO;*9T%+A`mnngy8p(QS)LE;XORjGBx(WfZ7Y z@L@-UIp=kZvJRs~aG|z-l1q155hBc`STVVmnpjmu9AcV#osD3ICMjAXrgM$!_toJS zX7ZFB3E9TCcEkVg)->mou%2S=IOE#uI_R?U4Yrb;>&CQV)_}j6wS{iS{aO<3Cpiin7_7UmJU- zh<*#bG;SC--@^QqaF?P-<8*lHho3?wd8)0;o19*cJxF{ojx}d-5BvL5ubqshyA#21 zZ6j9eD0}a42-1A5)4Yz0R-Y zB!_6f^_feUi0Zi4v|*<><(Y{r_x+}@^m@5n$E9ysamqCs#|(%M&t)dub>MMXd*Cz{ zh6@{Oki}4A?bB)_zT3y?>gP(>G(>*r5e#$2CrgR6cPy!RnLdnDAvsw5ZFjf4O2~$V z6_Zq9pkrgg$vUW$M<8lWKO>M$x>w)v=j2pqwOabIK&T5hqxMC7o}YRnMs;C138Qu> za?$uFE1Ui585DVM-9qnC&76jc5n`Cg`qQ#3>3sg|+G>HR=4Rfa+VhapvxTyS z{`7SI^EW;*wFGn5qi!vnBdO@;U$;Z_U47vC#TM;cZkI{(@wGd)-+VpTK3hi3wKr|5 z<}4aiuV}LoXEPxGalNTSOsbMvQt9=2->L|GmS;(DMruEauX&bWqS5xOo*}c5!0q4; zPlv#_BF;CdZsJb_-^h|cM$lvNl9SnE8ZVJVIkT zh^h2N#61$P*=%YVW`}}z&EArXV0WiETIyOR#f&~nQ+7uA$QNuDN|?G!P=Kz0dI_8N z6He(%@NzIgL-2v~^p30E7T(M@UW0Jc&t1DO>U@cX7YKPO#nG-`UM&Y})(0;r;bbnZ z;PpGB6l1biEwEN040%P_yP*s@pfnTc{o$_tscW%--7?E`!khOq?m%2-PW<(cY0R5g z^*^Y2KQWhseH~D5;ey{>DG3AzWbBBu`WS*ix_C1O(d_lX#q87H15Cd~npC{-GE8L%PZDp&jc>~~0r zmyNzdqhN3+X+>StZqe(wEBX2W{}s1a44?UQ5%5}z1st321zRidC~#Q5YMUYzI@PhJ zI`-RkqfAG-3w-}Tcd2#t zhaT`}!GTY34TY}P@RrO#!W90-aG+)6K;;LD&e`tYze7wp1|{{ZgjVmAnflG@q@d}X zg$A)+OZ-T>r8XS!C9YxdZIXBKYkInL=l-hg_OQVJdi7Q6|MmZk`CKgK?cvkiqg9rh zp28~TB(BTVS8qn8R=(+wB^wT`0G^}YGr*g1kCU9L&}4~6(wU(DK=&i5IxJ-#63fwq zm6;Yx(qY#WDH6y9v0AG`sm*9W>O6`Nd!7n1l9z(mFJD&z)9G@MdeIOzb>CO~U1=eU zDAKPM&Qdl<@1)WgU_UW1&M5w|n3I%h^kBsWHs07fLYkul-hBYE2J54as9x@TKx4v6 z+V|=%;*~R_8s!ky2+C6MXL72uyDmb4nxa>D*TcAflP{DctHLg{onJ~Y97sJ~eMMuV zT?uLe!W^+{`&k9ZS)O?Yzb1LFTVlgosjQ}JrjDfQX7W{2;LASnJB}gj|7$i8qXqKa zZM$<9w9ytM+5|}YJT4%oj`?)J?>$wTs&IYx1-GV%ytM~eXQIV#0bK8VeuAq~mSPz| z=aPeTcp#~7{Ty^{gsyjt?|vk4chd`kNMl$X0i=KLYd{b0LGVOz<>31IEE^z?6POm2 znX-bDhQX}XE>n68Hria%#2pwq6Y;Ng!9c;V8N|Z+F$w}f*dc&e<}m_>18?ZPI)JCt zGGiCeF|29hu0UaLN>8^8gZV*Io%kdf^a39zvq$aDj8*PYKmuG@WwGy@PAl9qu& zawP@GA*rXEAF#As8-c=lm3a>tNoe4WLnRpO{Ep>!5Q0OWu1`4c( zla0W`?v5s}jkZoZPd&)u$?PfsEu7kC0xnz$2Ov0?qFSI`Y;FoX)Vwc-01&6G!Qc$( zx}*d+7am@LJmEGD0#7`ZqmYPBX9WQ1OcMZXuOy%Uz<~V&l^JnOQFA9r190n_1cfiC zT@J9D`;zJai|y|mNh^bys|FmKu5tPEdy=JayAH?gLDfFuBW^K_I2bu zgo8N63?#0xKB|kLTo~p5T`2)YeCt0z7CMa&$%3MwWS;UYf*_;IuR+ASL9bt!0Et?W z3@2#gCj@jLybJ>7cr?(BW~ER_{AVt3Ad2gcmXKq_0jG{6?%;D*a2?JAS)}&gLz$8I z^#f40m1__xYtsE3)aF*lo|Yg6f{{{Lbi!n>9DLZtG@xck+Ivo3_sjwVi{1O`bJhb@4f92=%Dz5ve-lI}TI4l(n&hBIN7+uO z$Oc$QI7n0zrqed@=xH`{^DoL6Kh#<^`@hL$ozN+)S+JI@@#GDn#tD8 zH7I^_JAD7v%-qcU^XL6@uh#SP_2hZ}O`&_|Oy|twbT0GZLBGu~8!??>EcQ~Ps&%x( zqo>mU8$?D&q6F5YV-H(!S_}|drv&{<;%eX$K%a4vPHYcP6neY5+pafAahKCkyhDTR zVlaaJ?J|gw(yivmu{wEV>~5Hni3n-tC~8Obqnk;lF^dP@T}__QGYwL-J}n_Zy_3Y` z&1H7a3fWXDu?riC9~3CW=AQC+?EXe1em3nYeUIavZ~VDyvGmzd{eC?i=E9F=pi6NP z;d-`m8QH8BQ20#UZgi%Uj={4i^SL!gUDvOd$hfgTvu9bxKSyLYqW3*n3DeZoxP+ZI z%jc7C=+5*EqkFMmC7W|0tv#pEF!U})zAtZLA_`a8rj>2|HP^JD85jGlLfEH0|4+kN zb9V5y9$3dU@n5nj10`&WEhwJ8DW9f^b3w<%k9J9Tg?aqSaBLqP-^Js{n;@GJTeTMU zS8TJDIz|pImOUTNyjcq0B!s`uH0%iSE|(w{AE67=-Yzlce@5h}#lJmGwT@Z0J}_YDpkRd+~PD*snzfJWG9<}RmNb0&mbuCKe9tKU$3VKo*N36QhS~>IL@JsnXLRq z7Q(AVn|4f#`z4!FVeL;EA~Hw(+e4<;G|*1))=@5*Fieqz)t_vzxCs|Jbvav!I!-v3 zB#Qo5vYCf-Z0;tk3=_C3vO~`I=ki6rOkRI(rkDq8hmQ7Tj43H-)cfbmSRucxg9)BV2#xr(92%

)Ff9hMD8<)x9vMvTs{BV(TR)0Ur}2s)?6E^0%uDU|LFRY`QES6q=`LX@ zBfYvlRd2aCqShF}aC>H)Rh!bU7jE$qU}hb=VxC}dr5;lY06g5iY`!IVW#cq6O? zx7DMna~N+9tMh5ZE|GC!fE$6mOMvZVGK-CODs+e$klDt^(`fzZ9uDVlI3n%kd?Dayt%_2->- z@4ZWqLs@|a+O=*%oVag1)M0#KVGY~-9ytfU2hvYZ6$&OyehJ8I76vxkhj5X0%5>soi~U%(SN4V09CYQBiFt z92QszM$?&OTQAhma0m!|d*<^gWlXu;sPng`K7Gi%r_5miC&!x_{&3zTWQNvB)tdy) z5#jO}!-*qz5%JO&u|8!?KZMNd!W9srf!@IT%dJZTICj_A2qqttH4aE2 zInXIGtAEkT;I*txx2~??!Qj<<$s=I|r{{}Y^)NVVGsbai`y9uzZrL%Ok;JVPWusOM3qtt#2_ZIPoC7M4ltX zj^|lqC_|AG(}~EZr}5MFGOjm+OM(RWDW`N2*Qkx~`@#Ki<7m9xEI9Z<`dDPvyErOg zM92+&Z2X$>p95XxD(S?sER%ztAYWNEu93+a9DAYly;SFY+tGPq9YZbBN4McsF9>s$ z?(1Xc|3;B&&v^gQ^9p&@gXPcu$eqYP;e}SDuf{F>Y3P4GL3@ty`PnTB>1P-EpF9XZ zn6r-9a`lr*J`d4jnMa?&yd%7A71l!#4LKK$u@?!zscCX>hv$gx8id1tAwL5~f zx_RS@!A<(h$yiD)TMm@UxY!tYT6d}HE{Z7nOSIleEuELxJbj1Rc>$D~IzU>#?U^!y9ZRSNM>_z}?`UAw)9L3u4k z%a31$@Hqu0{IysV*>BjN;|LZR_;?$ief?cQw3`E)0VY0+-)hB+;3v^P-HJY67YSriH{dV3rpGXqkE!E9G~YdoM~8P zD)cxd&Xt#_@BTT~S90>JSN;xZquB4@MDu*meI`ejp2N8pS<)9gy1Wq7#Qs@PjZTHJ znt9MrUK0WzcZ@@OD!p*P)f4_?6)tZ$pNfpx*~`B-){D>f{q21gPwTCSfo+AX_XhU>lm^;hqv7B0j!% z``N4qi$(L=ijFIn=!{h)<_Q-wArGy0L&K1NdS+1iFcmGqZge;DvS;*W>MPA@bu~gIAJ*PcW=@bxL(d1fT4xh4Wtu#87&|=XKRtiTz!u^5!BISNfOW~XS zX}lBBaXI!}N@?B(yB8&bgDj==0Qqxj@QV$Kr4F((^LYX}q6)u~bG~VL^Kd>iA+d#)&-_pI>vIb zV*KD#MI_G9Dqt)dRm3G1s)ci+5Vzz7JBkSF&cdzZvv@H#(PR|Y$# zf?mk(`7);hE?XtIO$QN5;tDY2UiHH~on4E~)cM9ZOE#AG^MpKq3xCS0;(DSk?7KAe zaKTol;_v02dH*0rCC9DItTFiYs>3DzsB;pbymR=G{MyLY#>09v2g-Kwf^RBa9Ypex zy0k>{>2M#r`Bf|*ZX^r4fA}$;SHBYreWSeTHgafAC2B66>u9Dy@^DKvuvq4f$^5wZ z#iE#ycvUqi4*Sa(ygjq@V@vh&@kdI(5519PTAL&F;Bn$=NXV$s>9S8ozeghAsCt60 zVg^Vi>VCPyH}-;tM*UtQ*lCymF6_fgYjG3?Y)c>_ zc8~fB^pUG8pEv~hVm=C!1>&mJkKajTC36BFi_y?zupj|>B^4N>ve%9S9P8IubTl}I zVzD1&c~Ju-B|ZO+O`$P6G*&W)$VkZ8`im_UEq2`9Ghvg=FR`beo^v=?ix0OkTXO}X zT(bElQE`>TqURz7;XBcjq)z9?R=!B@wbAPBF2|~7GWqomo(6?KtyxP~V#~yt{&oWR z-n9K~KqT~<_YoZp$nU6`vg|h{Ek0egSfr$6%RQeW(V(nkAaR(*K{=6IAb%K=wMno| zeKbWV8jah11Vtr4X!S*iXNmpLD~yz9`d(6UZyp^{^*I>(jC@f71?dT`K#heh+Lt!q z=#i6L%Pq82HeJpaKI)k-k`=0w(OVb_@8t4Y!`Cz+kd<8H4nl-L^s>a6Q!^gpV0+-& za}fU@zP>R$t}oiVNyA2soisKZv$1VAZfs*3+qUhbNgCU>ZQHt&=Kns=`{mwz$gJ6W zt>4nd%sP9{iGL^d+^Ngo)wxyVY-GRd%fQdv_@`KBEq5dMy#+F3!rI{-#meOy;yVlv zI|%VVUa!3W8l=Y0W8Ybg(I?NR--$imY~WWoAg&JKaw1UAgDE6j#y&7-g@=I2es_FP z!S0;Rpua*qk%3UUQ6#{ZK$VwN;rJ(@$Y-@}MIeJgWN^J#=_OE~efIOJIPMAf0HT$~$%G~KhupcR>RV}ToI2j z(cL>#&GeoB#t1bqd&11f#Dw^GghX~T4Brsn`=m_2|Ff=N%rsTl@jVPMGgQB}+40k> zh(o5`OtyvILsIpK71n$V3?sEtTV~Xp2N25eP&6{o9Y~;>e*QoxGK~~|-2^hF=4<~T z!oNRnCQ-{<6(_=fN9DT_!(v|tcKS}=*qKh=yQ zpygVJH+~=9uN6n2d;bGYSG+^}k5c9i{nzAK5dY!BLyP*@2bh|J65HJ=)b&RmMg`6Bs};JvcyN&i2gu@?U=m}LB*!OVE+t~FFzp%`DeHy@SF69KymG7 zk`G-I>YfxI!762`MfngYp`io+CopaD0$j%4hj!4hN3a4jZ~`!@`J9bTzmHy&lU4bT ztX(Wh{KrXG||jE!2|#2-9o+x~Etlc(N~*>-F8m$$Mf2e^X4Gfqy%;o;74Y~wGYeAxXq zjRst1ThnMdYx`A!O_dJP+J6Z`EVj2Cg6pR$vVfn8l#PD|4E529cw-*BcK4NwEUFTZ z^wEm)Q*Yh?_g4-^ygYD(_YVV|m}e8Bb-*pU+F#87edk=k1mnDV-`C#@vbukJQ+|Bk zm0Z8WZGJDvVmNZty8j5at;A3CDQUrpuM4y~cQV*g577dbNpKmh-_DB0AV!ya(liF1 zjyXmbh|Y|LJdREQR%4|EysPbGC8bIGj-#=7YkpeWAtPm4GZ+ribn6Us%2Wm;=XZu& zqhc?(%- z^{7VekUjRgf!iTNM)ecAnOG3YmTd?st6Y7OWp3;rRpQ}u7e&w1*b0fbz2+XOCVoB7 zMA$>kqO~t<*FK4j+AKabV0iHDp9%TB(lYd8Xxo)!5%z z{5-6{a;#lwcd1Q#;4L)eur>wgQZ30s$nXE%FgM*$eq8k<7$p)yD3#)n51 zFq5Q&aCK+rUpLF*SXgG3#!Z_~p*eKn@rRcN# z9fHTK@)HY(o?nK9e*P3DUoW#jY>>`+4mmziW94RDMb<9Ee)dA5f7Ooe?JiQ^th4OQ zuIC=ttVb1ipQ`RCulUB_xpmM;&hgl?g<45u{#RkZqG&nT2~X%^hQxXYu!PDZ6KZ*! z_qXVU-y2KwhrESY>nGvm-~1K|tr*7|2w5zodrjxNj7uS(vB zK<1N3P!Qln8uIB^5wFBAEO`7Ul+cYk^rmAm?YuxCTyQ<3`|Gc!Z{&RQ@f@*>bR_43 zteL4`{vkoxOW;toFeLlMU4>y1>s4P) z$@z-DJ#X-5s0UOhCwsXF-qvrZBV>?!hA(|+r{>$*`Zu~A+vYO{rzRiG(tTEe)+s*E z$RVrW&km3es@ktPk${758MKQ!)X$*UiSRHk7QT^Vl5rCFv@wY+kfGMP&0SIK^9`e} zjk(WgPTc5X!PnlCh`w^OtU#FW_j%M+JI>aeziIzLQ!k$bc=Z5LF}8_I2_CoR+mRF9 z8&iLMLxP8LQR3uTEwBvhKgU|Fdl#K^pC!+r4$l#MF)FgVJr5~^>Vw|nZkL_o?3`p> z)DynBHRwy0dP=UXP0C>%lH;tERQZ$^zFG3i^t7gkkUj4W>oVeB0roSyL>qp`y(cq3VYK|I|nxGQ6$fFlXw+B3S5$(hDTuuNIo+9kr6N9QpzcC8d z_buSh;M2H96tEx*DL+wZ_RHBdPYv9NThuaZW5-d9h}dbudYG0SE_&@J+8>EW0+(ce zt7-|_fNdeHRl|g3hye|z=VGl(FybeAm_-sR0nn7KU8n?2{X_q;q{LuSj7<$mz19Sc zABJ7=6BULK`?Sb`PxJP_S;i~iAof{FWhp*;p)()5K0363xGsV%_O-S_jw4?mL4Ur^ zhPIDv0{w9|RdEM5u0cAknt$r@yV?ejC+>Zl^kWKhA0H)_vw^aQ!xjTwPR`OSZiXu- z`m!jpqO4lgC`rtda$7}7Ews9Wce8s^`m3ko6kxjx$`p#BNVLXej+f4DKSYR@ zSVgR8acO(ZE>S_1nkAc728>6DO;C}5UI{$Awj&5vVM$O$9$2RXPlHc%tZ)@Ia=oAb z6=>%OIPpB)Csrf1`WwbXmF_2@yGiQ|p4G*FZT9JRCn4UEv!@<>9g4cH$_`fOU9|tb z*{$pnauR(Ix$ZR*s8yXx3VSmZa>{2Q);q$q*=1E0nTJ^_#B)2mTMc`gnSbUg7;pTo zKxIILw3?8JMfv)xrTT8@Mw(rMq`L^|ZsoY;s_)A269sf9t~9df{G|Za?CNkis!&DMxh0Bo&5dU-Kxuq zQJ{ut9bdX7zQoCK$|jYisM2K`I%fdyN3AR|R2LkNTD@rH5pYve|CN^{*V0hN-3r%t z?Ma>|FQ4xU@cVYviYY@#N7xN{r6t%EHMs(5as7#k?I38TCV~}X?C~uqpZAwk!c724 zdkJ7hE_BWU^-j4lD0a|9vCbEQu@4)!T=6bMFewu!Cc=NWa_^2i%^{f4Rr?53h{lU5 z-_3E-mqBN$*KO-uczf6d?3D5L8&Zz@GesE2$Y9v#g_sQID-=)rUofgqisxTee|d9; znubZr*N^3{rDrJHYJVN^lZ*>KRGakWK)F1a<(`4PtXf4jup^K;cd~!$mK113NG*C>@t?46n?ktu~y= z6k=}8Jfgs)D(4TY6jP+;1J|R#cyZ2lnJZBwBRbWf$SO2-(fFn48}7O;yQvc2lq{It zq#Cnbl(#b;7j>I(np}Gv2&B*OaGNXIXOvuQ)H!lT=SDdyK^QWUylG#d80z&+7}k>M zaR-P~wE~Oi+vm7Hf%iA7W_?YAubg+xoC!{v)PNAP!ldRj53KE~ z9>$HgIHAutre9gs6)59o8eSA&pT!%jy_MCj4!CqdK<&rtJdw*AUlxderKrA@sj3AC z6ZZ{^Dg?xyZ&MlV2*{gu?~`-*QpL(t$7<;YPp+2yY3wZY;y=tWE~UImESKgOU>LCB zT0AB~tJN2TnQB<9I`Ahz#5FFX$3J1-6--w=;sN=K@cPzkvI%HOh&NbVp4v<`moKb& zoa?vG3%{Wl`2uny8P6Z49e=%L8-uTMZgA)xV7(+aizsi1OE8mkILXx>Ue$Q@t7a(N z2G>*HMF|lnf%>N~NU-BIUQLE`v}bhub@6qs%1Z^uz&2Jx(Hc&6o4>|W$@rp<(5zUY zs_SpVy!Jj0k&EhzWIvUszmEDvwO1pjyNXjK&gEZ@VpU8WljMpT1ge!F z;O@YPJS?&nUnyc-_=&M#1x<-IW@>Re)^jQD%i&~F8C^83nBrA&O|a+iVEmN(mJSb1 zd*`H!ljQA6sr5D8{_;*MW9#6*<&z{`iMR=HYgw4(V=$vO!23Nos%MjHd8IqgXNZ=b zLE8tIdRM0MR<*LCR2+0`2g16dkfi^D>E`&AsEz4#hNQlu|ued^gHRo#3P}Mr{uF4p4IRYK+N+gCLtyu((8D z-Dj}PWU_4^69vu6m~M0HURZd>otvkCyqeQdSb&=(XW03MQ6Ghhc7V56oje*Oh*y+LD zLOPr!=4EVX0!wJViLo$jbVB;i+gopwI{`lA@sb+_{Fcn6^cvIKdeZ96s@#j6CFdIK zUm4KW*n$XBO# zu%(DLW3FZLH`i7T`#2YIfBS1%J<6PdoczhCY~t#>-FCzvJsIAsz~^$S9Z5HieMtw&f0KLSMy00zyp}Bdf>P6v537X3r6RX# zXxB6T=Crc7Yg&ZoaV+c@*)a`k+%b1y+)m}2ZgPU78AnQ6t6hKiYyQf8Sp{V4j95fN$t0#~!ViS+A`F^8 zzO%zQg;`&JO^-??{f?1X7n!rcIA40FSbXN{qo>(p`JNoZ9=iB;MSLUFa4}6Y>p@Jl{3iG1kkOrKYCSe!7;F;c%(LW zI*`5xZE?HJyAxDn{j;Xv8pLYAI}fI@xgfQs;PyBuO?cPr;$}NMpasC)H&wgveV=9Q z)7h$BA`#evJ^dQ+dBn5)bKPb{Ug_|&T1VMc%uu0QD*_r=5qFcqeQtdWDRu(cEAw18 z(}ic{Klg^p_Yccu>8seLTYVRm)Nq1*K`+L$RsV9PLRG-c^yzusz%gLu8o78vT{R$Qql790Y+xJ$Ecx$T=Mo_+3`O_**aEO`RlH zEB#^(3y#D!IJKzyYIFPIk0VfDtS$!i2{n(ClPpz%OxCZkWV1QKglTB~hNaC$vy^f) z#FefW&Lw5SW#lb+6|5*Q!k`y_%RI}YLp|XG3YJ~ZnzQiNp!1kEu%rpra4o`4!p+XF{#d}RogY{-_5G? zNA*Sf?Lt7>M$akkQ5}WTmtvA=>iMU@hiu}|PtQ!i!a_a|+Di-Cd+VbA)2oJqA%wH&D%n@Xk9fw~A}D+Trp;SrCO zu7U!>NwIZGs!*Y@9rF>9{g+MXVUoXU@{|JslanNNy8*5oNNEG4HH%~#=0}I+Y#fWq zE>qS8flwAicm3=e=`1{@k;rXzw5}jumW{{2CWabdJQ;VLMB))yk z`64baOo}TNe^?E&!$h~FVUe*KQ-i8OXD{3&P&;vd_zOTjssdv!#8V!C*~G$!u9_uC z6A`Adg6_zUJ?cHhqZ?`*q!lDVL?A)j~;gPtB80)+!jY zu^s(9dWfH7%-@sixYVDLQ(p}!j}7j7@amIqy3TU%;_-a()N#_rH-I(eDyZI zg+b_bjGAnSDUc?F9+6|tab+23a%vGn%!M9>2_gSknZS@zo1XsEC0ZfnT53PoP)^i4 z9g)59T5j18ZBms+kCU=U=|MQNp)NnyC4Cg`Y6!fp8aN!@lg)6NYcbq9U^Ri6w}&Dc)vQoYpd|mOvv&HNJ;p&-p42G6iq` zS1qN9!ylp&bSg#a%v}!ZOm%scwYs64?L@QA!5Z$bun%&IX5?s)%`i8JPdl%PWssUG zF$1+fBo1vGOGcPL*pjl-Y2>yq1%mp#Yi~W=8i?^L0wvV7lO@xC`jTc-cfC^U@nqGq zN!|%3eCcYG>ASfFFCXa54_dR8N???8^!GN~#}cEBXhdR@((}k$7pEpb2ODM1gsDa| zMXXwOJODEq+n(%ld^IfLT#6pFWz50T)5=IxDH}Mx)wbu@`#Vz^N4o-iB7CE^`KLfE z4s*IciI6!u_B{6wW2pgC{!xVqZ1MsFOgJAMYCIG!GpHye71UMoZ=w#&$=3$6OSA>4xGaTI5W8o zNemhw81v;An$*f$muD|-?Ad-wB}3g|bY=J0K>8>3TXlP=D2+BO`wz*04GvoH8V-zS4lJNa+f1^#C$xA5uN5?Mal|? z+Xhkz^j4NH{gw9x=c%5 zp6L3s`fFTV2T%n8e-rV%U)LvQ>NdJv zLqcSUu51KfaNUAMn1Ao$k8rVrQ2ICTp1B~Qo$cNt{~w$$aPU??(H`7+`W zw0jGlb^6P^rCM3@PuBW2jnZP;_B$<4ghYX{cI4W-hm>SbT&gzZA^ewtV43f zS)OBewns~EPl}fivUxw?sqR#=)Ie?H$vbnMV8VE)y4ha6LTvgaM66ACxYwZ- zYqYl?#kciDAhdi1SbQwGQ5Skc%(sLPNn2DV_I>z6x2`lpyMm5!5j5yl1KWdPbv0dK z4L;d1!q17qf;!b)3$Y!?9~g1tLvynsbyfoJ-EbTq1_irkxNe;-De{fz>?$1?8xIAzkra#{ zDNcg56x(vUcbOx%N)Ubck~4PdpK*hlaNlvStp-g<__@njb8(ZfY1=UJ(PL5aGYGj= zxK3ht)LP>wB$)~qAuK46dvXmY^JcUxQ#!llgX_xqlw_M+(XOggKJ>T{%|Ea87J{up zpf#egx|f>IOy@Gb7=1d{4DfeXgr`gQC~(JU7&sX+G@BpJq~>)@u`R$QqS%BVuN`?T=7OUlKDwr+=4uLC1aGW*S~z8en&O1##)6Ll@y{p{0p^m0m7l5}qPK_35cAsSj(Y;ZxIdVC- zf8miH+BHY0w)+TKHldRJ+GiGg5r8h>O#vt5d_Qns5>#;}4W>M$PuLrg#yE``=tRkE zapXqsi+@mEmY-8lAxsN9jK~|;!;iS`oXHw3YdZg>j1=*(VC{s7UudH42Vv&4FUNri zMpJv5MU{bMQHMnkn^GTwRtJUx?mj$ZQR6RfkBe#-_Uly1??O!rT0zNm;gx=U2q@6Fn){|5+noW|O!1a(|7t61d8WBDbG;p5^y8Hw zEJ60E6#YW3Tb)OFmUExUF)mVH?IE@38A0@tmFMdm?QnALAU*ZC4zx7tB^;|`4?_p4b%J29xq?Cgs(Tl zg*8U1kjbRwzMTgwJ(`$LI{Q^9FFrOl%?&*cYtQ#n(i_{ncrOUU&O~kG#%E^rcwQyd z)zEmafGv4|Hv}21{HQ)VCuTJ&#YTQnAf2=KMS5M$ZgLMBQfyUGioKUP|#TjQ->E8xt4L8Du(iPV+yQ$F)1X_!h2HI zZ5i6jdg;L=^1C}Zz@PYqyo6ab-tU#&3_<>!@4~-MO>Uk$FI(~A*yOZq_E(kt4-RW+j(BQRx&ievOYhnYpj>vYLv~E{z;z32%QmOg+cvO+ou1g1= zkr+K)5`>_g{}k7*8v&ky)KiQOa2{Fx6b0!Ej15M%u4R6f+XAV#(IoJW9u;5d?a*03z$2lZ5i8h8N-HkSismf$d&?_WiY=p z@C^lnNh(qAV=NKWlP)|&9{ri=OIrGkN+(|#Y_T2-R5r%}_H=+`0y>0c3J?ah0_Id5 z8Qu-+K9_ynlhPa%=N97JMS501>~`rS|FY89PsXo|%iYtkTnG1U*r}cSSEp`-o>-dQ z3m)R5SJx^+IiyOGHOc0^FS(4l75%c6B-?`380A2fcbn$o1l^MLz1x)k6L!zRn|RMj z%|`4+@#Sl~;<7Qz@>5^Qpd_SbvZ+O1;zDtC^?Yy_nM7^8)2pe{1A<=9hSguVJJ|x$ zSc_g=*kq>`-rT>Y%&24@YOgy^MdDTv8GT0N0}rOZ%bL&9$|)J9Zc3@o-ag4nKthQr zjL*tPe)=T&8wB|NGZ@MzC@82;6WaWepZ>o;EFdi&dYiOuv zXTZWl_xT^vJ3HuqGXFag$^VIDZlY(ZYiVafYiBj>;qntjXw^|gN-D2`fARpw_mddZ z*HbXrAK=hnqD(maUoSRczgi0XP&^d~`rV7|A$JjfqlzYX;Ti@BMHu`oFxZ@n^*2;C zUMB6sVNv;EdeU|K>60h$DbC3Uk26<_FU2J#rjO2^Qz4J&aGAc-->2JtPb_`YYg)2B z=AnEGUJA?)Y{nCobvMEoAz}R`_*P%8bw5i#xkEN+b5XCoQ(={W*P1tI^{p94X{WBl zb_rF-YOciSu&hWNc+kKd6nW{Hx-Wd0g?K|Fe^85b@S^5eXS3^5hK|>CyQdXNfImtbZ{l^qfZaI;p6gzvzep!0pzNxR{gLAqj57xtQZ$ zNbAw@xJaOSjehm<=x9rX(!hs5CJX0$90-^*US$x4>%hVqt&&6sV7Rlvj-bpc zS}07{MJ?9JElF=y)NWkcAYaTWJ@>p~KOudkDGEjy!zNnNS>yg;r{o!$C8BxXwmS^~ zu-X-*-yF8v%RM9%J+mn-a8kZmc42;wdJFb}2h?+nn_^)=vOjW7>`yT?E0G0VmT;6L zP+A8JRw!S)p#VS>o&z5lj%gS`71aIf_vj{W6N(*+eH^L=0YVR93MXoLmrdktafqHx zMXwW(Z9d6>A@)bI0k*7Lm58j_K`UvyzE`;&8I^|v({X&@5HET}FWJiOn}<+(lT~U< zKikSVJ{$8lZNnlHnTCJHlD!c*p8KKnhM@%T8U#$9SG-XulzH-`qLMbGdIX@w}0gOY;3CaE0iB@lsHQW7rzTUNU3->l{{N1 zauW5O^pd}v$7ekkd(Iw>sm>ti6F#G1zFygTAHGrUu!_u8^ltP9y4otf2oPOH2$}4O z&1BdFSM&ksx-?P*-ndI2%Q&)MPm9w{YuQGXA7qYR$E=T=6g`K?pWNci0V_8n7~EC% z!bJ>?mCob)&?JT=G2+Gv39+aMhpZO6q0yUFTlsNpiM))i&&^eZKac-RV*9xaEKhWy zRIL4}sxeL&W}(I8bUNNoGK>+HNhJbqDTBQUq3Mi{y~mRidEddLVsTa~3hgx)=Bu%V z6B5?w^^ffpIh)*%?~8K!WYRfYCsV5okzxHpX<@oZ!)elP@!84KxRs}`GfQ@Jz-?`98||^xIQ0MScTQ-9ijnLLV#um9T6CHVDE}G`AAZHJHL;)T zd@EcZRwMat6oiKyMoCMNqRnA<`_}IE;4G(U?~duX2~Zd@R~iAxi{F;pK4#z#SL$D# z#kVS&i|0F>TxOt0o<5>(!(pdsusOF!zL|gvKp^1DPXp{v&po>y@9?=e>dyi}K0m%$ z9pNxizX4Po+ao=R{3AwB04{GGJvnv(H)nUe6~)%)ZFoZ-9d04WG;4U<2Hqw=OJUH26_`#z}1EE|`jA{MEt>{XQ95=!|~g!z_MpNW|6k zV#oAp>+l!~AN*nn1Glh$*shMQLJpOn#os1G7VnJg@XHApCQqh__UjVq8bp=I{ba1o zYasm)8RR3LKStfuk*LgJDeZFbN4mz?@eo>{OMWG6f&{rYJ_1z-bIWL~cTQNXp+A`c z1a{#wt{vyiS4sUJYa0(acAP~DpR##^?%_!Z-uyH+T&5HDaznpL=r4x&oNTN*Z1f&u z>z|*DO$SLu1YT)a$ega5+j#72gN6WV_%8)2Mt1$S$$Yoz;0I*j2Xru_*O-Xg7>V1o zL|+#ppKl2sjs!04_%Acy2hPx<+q8CaPN<0iPNJUsH@9Aq&kzI;GXxJ=bDqq=|9ci> z?|?lrKtTU(Y}}UT*hus5#Jn`bytKr;*Uxk$#BEZdp01*v1(DCkkD2QG0B$Gb&rDXES3`@xj$tf?Ef|@Kbzg~n8VI>HRZjq zn5U-Wl}F!}R5E}eSjFCw&a>GE%t<`aRoYOkTj%}3_X`tncCPw^|2xbGKb_=+Q&;~l zJ|5ADhVB+x`$pEJ_807WD)_so+ptQTeS|&HCRi3rd>rY7Ta@{~Le^~3iQs15HG;w& z$=X}pMuL1x3gD<~sMMUOZrm-qY2Hd5m!zPYa!Q_;$&04f0qb}6_geh-R%u^Q6q~iq zXQM)3`cJ(hWJaR=kSh}W?gBf(QI|~HgdciZq(db2r56Id4O<|HCxvih1`dQLl9kbe!hZGAdZE<5*3VosU9)sqp znDtbV#rK;^ha7Az>3G$SbGl((@}?5Ra}lWns8uM4b(*=D@p*jjS!kF>)C07lEo9Tw zHdU~vQh#BwtWw3hh9KmwQrJQp+Bq*ArW!4o*HXRMqr%Xx&|AP_X#P2XU_&TZS-kL5 zQS~CiJNOJnIS5ZJ-7xrhxfp=P6{B;ZEj607xENe-SE78Jgsk#6*brJ>u7}r@$_-4; zxrP|s{)D4IwM&^>LebszFErzyG!@Ot{0S_E9GF?+a+DNAaMU(f zI#pB!*$a`0;+ul*zrZgE!{bA|n@~#6+)g6eCuG$Qgj;9X=duOosCrvEp!MXTf&5Zw z{0$Q@6ODemY<`EFe(=w3>5puFt)|x*D9LN0Xs&s3e|BdM{3KG5>P2Wa_DClvm&z;<@Hco<~cx~HYBdZD`- z*c|NP(nI8ruGCC~c74sK2d|@Dna@U5UZ|Inn97U{KsOWZnO!dSM(yjCtYDK@yfE|Z zxmYevo+Gi%&D@MkbVYqogEI>cOjRNzXoZ<%*t#qqXu8F9^30k}_YOu7njj&^67O_H znoZ9RF6$C<+f2PJ4dxr*6^t>ZLI`Z3Ds^V9HysbQ8sbD#az9}yY$>e$rSwT^V1?jQ zf!n1il|r|Zx2a0%Q8iM$dCX|E1?TgMNvZ07MwB0FtxEzzbQmR`;zhaYS4TLy!g;Di z=8B&)m(lu$wfy`&NFzU5yYzt);Ea^fqMHehsiDyj8SLfj;d?*6;vYoJ*U6i6a+6^%4=Oh;-7Cp9-~ZuT?RZ20vQtbicEaX@L-UTDHg` zT%@B|SfR|Gfm|A;w2{NimT!(UOr@D-jB+)t06}zh->Gs<_-$Fo&~FEzw0cavqEdLc zukOcM)7~P=1UbMb$Vw@TzD4gC7v#@4@@6@8QuF zc*iEoi1MrRd-VrY!WR|XRT|Smmkm}Fq%F*?UQDJT&wZlSDa+8lZ_w*MZ`yqq}dI0QBY|zNieG(Urc|#w~1uW@qyXxAucXBSnuiA74kBPYsR2 z4_NLS?)4ulpy>RC3!c4>aO+{2j(TuAO>bW0eC+3mmO4OOjis)L=OI{Fn4j?u#xf3W z`(B0gMAiBQhRPE!>#qK%QeQ_{_s;{X{uORp`BTf)Vm@KS(HN2Lfkz|oT(hW=)Z^Gd z^Qi&phVjxIM28&ts1=dy5W`lk>UkAS z_#JG5tE{Ya1Q`suy)F$9c6@CF!3+ch@MVxX+I3!h%S-YQB63$A%?&wHA=&C9_^I)m zIj3fx>2C(j={#~y&G}Gd$Q}@-g9TAU$~!gv1SOX)_m#!4Ryr#e4*9LDt>yN~33K-& z=O8S?xXMv70wSuSJTSO=1P{xYkPD-17|0Cp{OF>~I$vR=tz|tlq0(s!$k46-xMI9LL2&qmq)(6U3sa_~#5sO?T#eum-LU^s7?T5%AYW zc(k-_tbMuI(t8lB{o6&0wi2gnay5>uyNUftS20-p$W%KXacE@QnAH!`Sq#l=ZPw@e zAbvtGkO*E327)$$Gk|$|3)F3`Re=4*dGqF`oU}SI#2(zC70MlUI;(TPXu}A8yb7CY zJ_Jh8mZhd13Of7&YbC%YT@rQI z{$jYwl8LRGl8!+bq}6R{bTsrgj-ZX+n;MaXk!HMsAnnvs$kJH(`bAHdD` zO!SQ<4{>aDfcx{pFyq8nuE{#T=Ft{fXQO^?ts3FWqm2#bw>tD7T20zIA-yK}x_jIE zALhJYH5lweO916%X>@f*-4w%+dMTvRndS`NR6;DG<~_gFUG>yuv8{P1n@@G$YE_+l ztAp&hC9HZ;GY{zocF;Abo7Z$ZCeLdVzjLaZtAv~|RcVpc4fWiry}wq3oETNT@M&7R zQvoG+B$Dq5pVtxOq|N7ED4s)3gx-+2s<_GPcmpkx+4>ChT3STk6`5A~#q+Ic5VOL6 z?{8+C{G%JHCWhkybBaFtm{oTR232MASx~l_?XA6`a{xg`Z zZg};W0-@Gv>i$Rn%vSel^m%DRp@eP@r_7L^wWjko1&b5Yoi~<6UKT^COn~{LX*_z0 zhaEi~i!mlX24^hVY{Up6d$ys6zQW_+uIA)V=QJ)QtK|KFo9tDkiNg_*mWL{jN}ni) zYm0B=AP$E;S8uj*XCQJ`bhUu`oYf`SGpt!w7B}X@7PaXmeYMbi9;Cni(-9|8WZc(q zMN*E$kFQ#CYmN*&#!V;3A&$3U=6lqOZI+x@X-(5?;cydp46PC?TZs{#X91pL5x4?Z zhj_v+&6h$Ac-hN6!Yf-2Qu7nG_dCGgvp!&uMZmnGdRH(*alAQ1F-()aAu9n4UJ(d$ zB4l`A*iIsbWso1(c^*~-J?mt6b^(ntuV7Ibn=ug%grj6{mQhy1+c|5M>Ff8RBT@T# zDMf5pL*rIn@q)J+=}T5@>8e(tI;Lg-#g}G?Epz7GosmsvBRUxP(2*?sKBK*%u0vSJ z*qWZkYN1$8ENxo+olEo@H1Ogx<3zqzm;Zo2qkKbni$_q z7cwe?_Ohw)MMGF*E`m9L<=j=vy{H5*Vg4e+Yqd1kb;3P3I~M4v>?mMp))G34VfvEd z$>QKwENZ4%GP7BnA$OweQ`}mOO`*wKGC3B0{k=Kt&?N>hL_q1~(M_OY=^zZp| zPgq*nX%@0+33&5j#yv-J&k<9WL zQx_wmX8D9Y@15T{O+SmKrSrC(C?!|i#B50dJd?L|+}c<>Uk;Z}HcaKj0txw@?!8uk zy+JA2f1G4QxbLJcYZIrpZ5a4?zPOm;EHcENA3K{5&(4ppcM8vUbCE%a{RWpXj>V4c zd8W+&#_Xdr-9@@fW>OU(_Y$- zjCqV)Fl7V5Dx|>?BHW!=fpP!*35EEGF9~zru8aV?N{1<1+q*EbmI{nbkSWmtBgg=M z!iO5&_0knvsKlH50#&Ype;TtnlP((n%UTBvouDl*6uOkaB|#NYhc=1mE!t-a=L=R* zJkYFdM(_Mkl#H7;6wDh-8f3R@Y+|Gt$QECu;|J2SbA0j`7bI~i)?>j% z`IoR$DPzKV2%x27#JIl0OD7C8P55Inx`2kIQp7a%h*-x<#)ojjYm>!T5vh^JthA@W zSix!M?@ze&=uMpq6FGlIPJ-*h?7)@@X)$42g<74)V6O>Ve^w+G4_gO4{?$bxY)vo< zi6zbC9r7*Nf~^CJc9c&q8Bx=FFwC`(`|q{Ny(X!@uyqegaCj04&k-Fe=8b93oRIa7 zUXt5)+p)krST%{!mC60iaraces`u9sOw z_hwZRM9Of_^E^uSpXZ7^_toEj9;@vz@~4_F_|$y>677g1wKi^hkW4kA}BEB1L(40vu_bKhQtoyLwi1i zj~a!J&)l@iKs>u59S zWZVTNhOF-~a_{2(n%uV^;UOcB_d1)~vA!4f?u?Ed#C$f(EWHK#+cOEh@%L%-S^mUB zohCgYY`Im{!?*WM<5D)&hbtE~^v6h|R(zaa-!OUw2pg2mi?=QmnGz+HzvPg<;xUy$ zyQpE1Z8rUm7v@1rQJCG@kKNq{YYh&ZLGWV?O#4kT^oS-x9%7HIj8o;2e8w%&q0 zfTj#mWnDnx%tKLaL#eM7j<+wCzrbcweLl?VOwbX{>#w@iaV*3FW5!seoaOcyDdWo= zqDsVI{uHgynJhy6g(@SLBsfQ?v}C;J^MFvNx>#u*o2Z{bXeDLP41BGocsz_5O_VNJ zN5}SspzoV%{T38F$r3U_eqCb+maym7S>XwZ{Tjqv-Do!R?niJMY%yD3C85%|M7SK$ zs>(X#kesn{(w)vlsZuT+f3pE~UEFW8RE2i1E?TNH-B^CFI5O~1CBoC72qfFFmC|2J zNJ_(mO&P%ycqUMyA5`}yYc__w-kXcE z6x8&lm!Z+`7-d%0bVHi&T=}x5vOIGZkmY1WB$XVvB~o^qC>@tuQAw(BL~-1uWl&sc zBvV-$1qSR&D^;21EMl)e)&oswxhN^IPn$o!GK`=Y+ATiXw2z7)UNPH6ZPIZYg zcU754xgw~yYSNq;?0$Y-ZmBXkjEu3!0^iyw^`~*;v6z+4MgFp|^U9!S!ct1p6)(i< zBqsEbb;k*xc5TwnDVvHb>JjWWSV`2SpQjs9p6(#jh)PX?mtgjb2vdBO1j=xLSBnSPn~xZS-C;_Z#7v(l4Fsz&YNol&bo{?JskKVSSk?gKT+N@IV= z1@b&4{ts1O0hQJB{4I!*(%p@KfRfVPB}hmcNOw0P-3`($4N5l%f^>&;cXz|PSH8dh zIqx}mckj$+VrORW!>-G7$>C`E-#0!pWw|W;QTBM;&1qgzKu+}eSJkg^?lNJBg_13; zD@Yy+gn@5U1YinD&lbrypBH`oQb{1WicUaXlmWAieB#EDFo)u0JC3$7P})WKAr$c) z%g690ngK*pn--U6cTIHlJ{*kiV;>h%{PE#ndG8)RWb4Cj!W^d8BBC#R@J(A!?P-zL z!oH7oDZ}G&!J)Wln_rqlKRkqM(^i8j1>Wlf@OV;@h%+g|7ik#v7~3TL;Cxy%@Urcm z+}5X(=Dm);S{lVULLtL@;T|0J4aU|f(jRf}8{S;y{BVFTTFhgUx~D0646}{n6rMrA z^!pI&`pfd0@H0F$`4&Py2hMDoRvwHWiC+k08GYViBy+!z=QNSOLU=7D~ZS^|gcgNpOanJVMf_~P2(`Z|4gr8;p5!)*x z#Dq8KiBK4&5&iO-B~v>YyY%z8?&xGv73R2$0f&g*dB$a{OQJ@;k*pq%?mMD{F``eD zY0Nm|xCV`0srW)<7-~4>iNEw49uS%D{C?p&Gudq|0NH49{0GHK`iZA#%61Q z0q&m56P7G@AJw)OaQsjGM_#q^P`Hp@bA4sT9j7-4ZU2TZJ+Z9JZ^ZAL#Tukm`TH_p z4EL@ibBxJa;$vgrTw~n$Kr46P=dAu$?2O2UG`J-@-pfWGaQkJ8oI-vf+KJ%y%N1QO ze8ANC=4*?!ZQ=AhcJ&Ibc<8-C4w}K@&F`%*9tjH7`im&-E~Na{B(u@Jw%FS+Azy8- zOmX{_i}+tN*cyLiOwN6WmQlJsbga23*Ukgu$u&e#Y*q5n{jn(wleup>P9fTvJBH3U z(mJD>=!KRD8MfNzLBcPZaYOOGm7GSmB(`QxZr{Dz_Evke+u%!zGd?10$}^=b>|NY` zh^%@1Q?k%F?nf0|vGc~|v{A;7g0JJd8}TwcqVJ}?aTO50Iu6(SRPq|Rd(AZ_SzwHN zrJv$TbT*#Ieo%!k7Jf}=N^edTrZ-qewo00A?qg4Bl+$|cZI}K-;Yl&)w@+vz(t~X_ z+idT`2eo`Y+Y~;XBg;}mWDL_v$Xi9cO8uc+6YG6=gnjG(W4IR7f#u`SF5ExiTKA#u zPJUGwYN*v$3sQoL!9HW&T2xjloWt8bWByvEEi+>KIBGD}4w(a-BNILxF)mn-VSAzMMXI+q>n!x66KZxu3^8IElF zs#?JB+;JnU3ZcIooeOtHMiIF%N=rRMZ!XJxI&k?Qm{fWxHU>lC#@>xIF&WXx#&R$NugNPk;@4c4d;*z%stO z@HNu*qw2cM&;A?KA5?9(1&IAk>NMYR%(!5UbDa=;NLj$OpnTGt#p`Pyq*dLb7n;m1 z5n@l$v4FvC+l!Ap5&rAb3Gc6v;Gc8w$FFZi-_gGsfA*Sz&N#V-Rx$jigZCx!?u()w zeAC7Ts|?@P?!cc_k9g((AQwu8R0^eLk34C`jLw*wf3)Xb@`_nq7d>qa_b^gu`4#V< zc00^AN?qNOknqR}#=|3*&tKVlot%FuQ-;=D;Jx&rZJ(iMPzY=$kTCA;G176PN4-@E z)c>jGzco*HXpm@^L@UXxQp$u6yI;mcMv2wDLTCHKBbTtg=NmwBlC)B{!)!f|`Ye}CY*|*T1s3&Z{L;l7$_OAQI1TC$8-qe(PY&x~3mV z?i;$DK}NNZb6?tDR}D=I+FQ5n`(^KlEof-Q@r${j$1AN@jDOpG>y5{iN&nG?2klqy zX_N5l>sr<2>8$I^;I$j{*#ZBB&Uy#wCJzM@zFg*#+jr7IZ+F_1Jo@3`xt{dg-fHI` zRsu75+@+G|#}QwmP%o~Xi2mkpoPxIs@nR2!xkn{7H@1RryVg3^7f;0Z&2Bs$`8}P5 z5j$<%Wx``A5IpV5zS(12-RdV$4pEwH_Jpqc(SWjmhbt?_Puy_Vk@+Z9UtMc2T1M_8?w+!6ppdrV%R(3 z1$XUS)fYzG4>}Ys7h5JS7V=RAh%RgeYIsVUkuR9ZZY1G7VJ=>gHN?KX*IlR?A_!d1 zyS4n@Aubt@#TkH=$aqs$S3}yS!(kYPCi!eJvTy8B{h#>(c|uQ`y0rV@WR|RJ=ki*@ z{QINxmhFvYFvMn8%#N?F8R)tk-UMSXgGP^)q`4vKZau zZg`xTpjsSD93E>Sb07{Bg8KTtc_rJDi@Lfl(x(AxX~T{qiR|ROTyEJ?{QUUanj7Bi zfa|7-MoXw6nV=-cToouV_RcrS!UDvrx#eG?WNzJ2;MFi1?-E+L#7eKvP%5)6(bn^F zc1sCNrf%Et?p})a;m+KYAd~gH@otD^nR)p(w9iei#{D~?^0ND)EbExmyDj8+gM!Bw z0W1xyZ%csEu@tso^d%fUDIB;uSO!wJ~67fZcJyC&LqlPYwDw?5$EDpM$||25$^Av zXi1U_!U(4s)^>JBv<;?nygwWo@ZCr9O5v^B6-s;|KwF>fFCx{CPXs$mc=)q}#vFkn zM@E@jD(Uwh+V~1?pOes=2C{6$_CLAIn|g38*??nTZ;?Nucs zN^GSa#UnIjhhIkQ*-NAOM$__UZwtHh0l(>rt);ew3LK=9+N6_+hqcHT6V#;sIAtr6 z44;!%+Dh;HN8i~=J%dYS|4p-tOqWsqQd5Y*Q5xeGPAI~{EZBeFMmzM;y>&d<&}Szn zN-0L6sl_PDIyt5?Pnb=~c0>X%Q z4uXFLsIO&FN>yxQQNmz&bMAZAt*2<+)<4GrPcJa@H#NYckr3kkWW`4Q~kFa{PdpFhO3niT@HE|-@ zrCyjSNWk4mGn*;|ZJxH)ym&KDE)mR#y{+IcyiSDrODe4}V%DiD`7o$}9&1RWQlcm3 zoi$SP7iTfJw5qJFu$a?!;QlsjHq<2M%Sa--{hGi(Kh9Q-wKtx`)IqUvuDi8Hwx<7vm(-SG5!N+JJ|vix)ia>77pGj zR^e=aLzTbt&%Ni8wmvuW?u$>{Q}$+R3FA!u_`_Fugn#ILaCW!r*I&3jxuPQ|Rbr_G zGW1+pL8l_XY|xO+E2fMLWs54Cu-?W%Kk3@Z0=kXb?3p4=hJy}zv*Y+ttL&KeZ z1*{b@Nxnb^w}=jmql$;YXJi8*uP!zwX}4KXwpJqmu%-UjO#ULZ*6i*>U6lPBX;WUB zo(RRjX_`vh*|`y5bsdgR3cPC&-qWO$tcm zZWjs2rad)_3xFoLfdp&d+3@@Vu2^J4sa}ufQ|#_@i2|<(OVW{2a{{PfvjY%5w8=$) z)wAgZs@yR5L0pBRAmtPUfIgYC@)U?YjlSlm=OU7s0|I9Fm)!u0;R94~MpYaE3O4-- zh?$A<77(b^4+Yjfb@MgXm|#r9KK* zAdn<^C*_bcV=@;lfOX>B&8XFsZ?@r0G<{ya0Pio(Ex#*Jk~D+8k0IP0Gl%! z4qSC<@qoK$gtZ+&7gwh;AQg1J1sWS=9e~C&Qf_DjsLGH(Db&;8s-vF{bdW^`0+72L z6xynIzC8dEI0^%dw5U>G^*Z?t(1aQ#2VEnZ08};F8WNC?gS0X^j{;5mUDJRx76A$H zisS*|KPy+6U}Rt`Bqk;)B?dVz3e??dP!6DRMQs8b#;h$sP_Ppl=E&P)+ElPqXnc+Vy5$<%7dUMbgsk}uv^-vlN4d1QV>hn~w+GRY9khH z*2vig!meHS5^73LGEhLR_vi8gL)*ghodB`}>++8myg^0))SQ0LPk@>Xem0 zVTER&Llqj-v;m@|YL^Ds6Uy4tj6hN}3F3fnqXdNoOR@_1)I3lkl{FMVU&SRCU`IA> zff60bc~E^t$)u+M%3KW14!)^=08KJ#0wCm#N&sTYJO;I^C9)5dD}nnsVB^>&0e1DE z32=vDW4~A%@Z}+^4n(`VAR{y+kg62B9Ds5hSqI|v@q3_z&6sZG-^q0Mk)|61#r#q% zAaOe%Tq*%9eDD$?NlZZ13FkfwtmJM81O1$Xg3}=MXDIT()g9+VsH`P;h5%pQ4w^1W zn-Tz}n|TeaOpAC9fC;vvIt9&?31eswmc!6AoXb3iW(Df4CAg^?CIgvr4d;ZWAw0Hs8m&>N=!)}-z?xLR(w0Ewn7 zRp9(sXF?WW2PAWYA%+bN042N%icnOdo`U|huK_f+e-WBAcJT$i85%(k>s|XjLjGs; z=in_LNuj~U1i7FzRl55`K!tz?EVh?GSsM421Gao@0C={Jd~&D*8GbwLg3nn3Q@@}l zhqvAoZX1tc{sZF=pPFb`k=R^Ll=Ifl;q2Gv5_*<8YimDP{j$!hFmCGS#77_dj|ru( zxN~4SvnudUaIaA2@mkAtveh!|9;)C=lFxVK|4FX-i$q_%z*cvJ+_tzB(VZlW96Cp^ zXfqnx$`=~rAFt->iu3*r<5HtVBZkX1ya=n6O6FQo$x7nNe4<@O>VC0oR&^Al=qYpF9Xny zG5jyFvuAv5dKWvs@+D3e1%PcPt-T({#p_JX8?PKcy#52qF#o;3S#?b2SkMA{?6vTs zH?+X!G3~d97T9f-K3Axof)l1U?He9@Bgq4q*Un7Bv!D5Q_t*Cc|EOAE3sxpZuY(1U z=G4~Q!QVRK3xd2uoS|E};pAsSw?)G?`y_WBcLj%^hHl-mxoh^qme$j%65rR_b00(} z=NUFCl5{IN_SI6ma2FY9v`Ey za|iviZYm~h_LV&aMcJEZ>(UYukE?-mUx{7go5SP1NP=~t#hoa|?q9n6%W0Zqtf~eY zYQ|wzC8;SbGr%SJ>E*;xey~`sOnScb4O&{O zV^v}oy$+rZOgy>ao+%mrtvImgP(JQq0?Vxf!$L3Uu#f=@~j zEUde~Z?QY&$`;u^J=O*bYhuLGqQ67U?nRYTHTmjz0z)c&^JaQA)`^LRkKGp)G&lK& z@JM668+x(u$ul;Ro%^aAr(Ezh9q3gIUz_SV!Dmm^{KSXZwEaW4kN}p&OFF9wWn~RW+cKD)MU&2zGl4wm{E#dp>tLucE!}YA|{Ly6opDGO(JyGIIN1C-{kdeQ3iYuKJDby1A#IqUp``hDVj@!)n?) z&b1mWrpX%eCoeG%@RuJ@C(*Xyg-R+O+hs9UVS%@=J7pcVBd5 z9W}cIi)tRxXErm>N|B@GI5=IeS}%SHac7qt__Fk?P%XOXT};W@KiWU_#nUhF@EpR^ zrL&1X8}mJhx+6T$gVx8MFvRC8RMwT*_b@kn(6U;dB8PO*yO8EqWWg2!=sme1h3H%` zoDO-8QkEhmpjQ2$d(P>oN zW(JF%gTcX=;&rOxYvOzomBu5io2o+O%_Zvy0a2Ow`G1RPrlTfK%v!PFhIMgDtcuR- zekuJ7TxUU|z@jnAee=jpTBf6tFfoBa%Kdq&$bGN$fy02`!ni)fPal6=Ctb?&M=nKy zR?$pCbrNpc%Taqs6x^R)kY(pAeae>w@8Dk9Xp|Lpk#XZ&jpFo)K@9@kCS}7JpboCp`DGPdeB$-d%L} z8nDC~XPfX@SpHIKiZxCzD|(RAq6cVXioOfsu!4VSix>qEe$79_Dr!5gFRS8 zt85_@7*^SP4zFPz>^oj!==k~5`BB{}TvG{A^2YWwChoWha4|@z5D(yc-{| zh-Uc}slerhJC$Jd#*6OM_7a0+a$ph9W!N&WCE5Tis|8Ya4=jz=WqLAT6`Cb`dq!N+mJ9P)CLV|Y${iq~dY zn|`%PQ6NUvPvOcW{#BQw&^fHJG`n)FCR{~~YoqK71l}t? z8_BAS6-2J;sjgy+|1G1BC(gE#UdbBzb+r>2(L3&=VhBtbTc6@YN(rEM^7K$fn)2qM zc0~XAt(|MRzS&D>Z?F_?pFLyBZfy8k+P2Z5owdbvRtr4HY)mG8JPeFZ9hy%?_lAkP9qF}KgSLZUT7 zF-cGtMTNt#^#!Vx&v=nO+62c;@I!y!Voya`D$%8>Qsfd&N)1nSNrS z*jiI!j-c2gGH`t>a^J)|2&8LV3!?ZYwuW#xiT-bZwPj*!3gXPvE1@|)GurmyodMC9 zN3ZEA!l6b|B+RTW#?mcV@fFuTrWPta0N)}k*BnRL85(p zBDD@~{Y%39N8vGTjtgrK(XW674=n<;1T>)J+|vuiM^wau^bVbc3xW!cE=;s=15WrW z+!cO^P+3jB=jAhVQ``K+7!oPHps3U!2FgaC;p#((=6Mt0(Z|4jx?x60GT{_mj20Nd zJYqPBKt#v+26KeC5`hSi+JuU9fRVTo@RAckjDv$Ha3E2B%4Qm|j}U7K7<B+7TEcJ>3*UG?>vJD9}MX*RtP!J~QBFM=JFP1w}QG z_0w6)lmCkvUR3ITz4(a#(bOZf5+%notkEm)M^iUzKNkW^)}}|4)D=olIXu zgn9pC&~bUzf1-`Xw{Z_j+>NIH*E1HDeHeoqPd?2HAtk1ufqGw?M*ow=t*d{KFnGd0{6MqiD4uxwpqXM!?Cj9UfjsrPBlmpvPr{GWESOCeN|1BnH12vF z6nP03XRTx%NH}Rj-rU*)61MohJ-vi70vQRkFb}qsgMxs}Px+skSWXN7V~BQaKUGZ9 z&kp&(wdv#VdIAdhd{pyt<2UHzVPER-Tn3ug7CHV?|9k9wntqr*d+Ck;>t(Y|{YT40 zt9+RMGxCoA>&f0zJlLI4#Q5Em0x5=$q(H6SAScN~#?gi{Q6J(scEa;v?BA1>NOKYf z(?*WC?Iz4(2YfJtSZGighGBdH#z-UC{)GIrzBMAv+IM`Ip?nI3*7uYhV9~jc%9L9JSAB%5#T}C*XX!(kYw6!*a&Zp20jt` ztY0C1Od@Ad@A%WX9Si5&$SO=|@U`JReWZjo_%&cH``fm7J3V5AMN-bIZJ)?g;2O6o zQZTY#aACK?su#FvY%9euZeGvWw5B_mPg)W2Ch>@hcJFm%f%FE!S3 z-b#}Zgj<;sQvTt-;IB7eX5kukgCtLJEJHJbmiD1#+6`6TbHjzZ*H9(5|LR@uVFM(me)T<>(N z6)-kqv_x5PDLysg484u5+fvujuOA_97**uF#A3|MwX#XJp=QO?Qz?VDdbLhLD3DQT znt(oJkN#FRTMulSH3hazo46_K@DVuweRiplm*9Bua^LD(gzUsN{hyf~ID2+InSj4| zH+)qy@$Ub2&0M|`>gKlHc48FroFUKRYODLHWSkeMEjL2DW}1J4*v9>{&T`X=6YGA@ z4^W2+V$2ROC6-gwr5U#TYT(`3U#ALPX5b1+TTYDL2D@gMa4|l-lJR4!EsBnz1A%*n z*=sXovjg%A3mv13cOInU7x7>lEdOESEJ=*x7weYI0=$ih;rR7v#!bag^6-WS^Aq^$ zF@~Gl-q8zNaM+}Tn+zN_fqh+LdLG@JrpOWI`dI1a<~ujP`|EDS5&ce9vAsO7O;`JF z89DQspqM*c?7ST1=b9xrnu7E@|xKk=^Ac(&T2Z2pN`<1K3rmf??*Rq9A?dQc+0kiY3w&1 zILOlf-DLLS=7ojc$io(ziTn;a*z*$!PGNnHgvea~<&6WXW1Dc@K5@xfPX5Tkg!ac2 zwr}twqb|qJPM@FCE>sVX)>%#Al_@Rtf*&JZQy-0yhrli5UMWZ!M{F;EBU-q7GJhMbTh!$|loVs5#(O%&EKClVC z8$C@AZ{pMI9N#7FO|Xr2k%?>aWp-oVFrM6Euu;k`r!IOI1=8I$bP=-Q;b+pHGISf0TUcA(H9w#kx*xu02o5rl&JO&t<3O}N zp7?{d0^VN@_Ux{uCz7qfK@&Pb(Z02uI}cjZo30HHHIx2paL_6#BhHuV&cnf!xH=Q; z*=2C+xV`QUXG)LxWp9140b?d{auw_~kK4F+BnOU!;PorXPR}NoOt~*0H%H_f^eE{$ zDSjthsUgzEyQ2qZQmUG)v}HN6k=z#hnZ~5PtstXWJ7WPN>qCbz8F1-i9|%_*`qr3s%5 zyDu#Z#M^ly7}rxXjV5kQ=nOAYWH&~g;7jQRhL>s&>xoKz6Uh{aaH@KZ*g2l9E-Dom z<)hc5uov+Omb(Q!bn-0i@_U&u=!2}jTDk``p*?#6c?lmPRZEAFlB<+9+*xR(?4z%9R*d?HDDEMXK4C@ z$txqX_sC~gqT+m`pK@mx3Ty61Ss>HJa%agjq0?s-EX2 zb%ED*paYFQ6ztHs^UN*Af8CdBb353#xx|=tjc;ovb2F5Pt5&BYv8?~Rg2W=vVN&gl z8kt^$J$T~jGxSr%2u|@?BQlkoODMZNMmAj35KLNir@zfBry2DXR*5UrjWBW@ywH=_ z;}lN01!*TW^-at_zH+78N`E@65X>5@&oeJ9BCkDG!Ww*{#w_+M=o}s4?Yl36CB)Xw zNk+M-QdM~DHo+N{n~bEt`Ja5kN5i&Wl#*j^K7}jmw~p*w2>W+Lg}ZHYx{K#nHznc4 z+xldMC^XK#Cy6JT&=y-3Wr~X=mbF}TrS>&~eU<)fz0Plp*dy!7Z?9ppr7vrUG1%Jm z%9#q@DA29{sWa>$+fEJEJ1)WNwAlR8*Y(52YrOlVrrF!i8*ZQ8rF?9Y3LDx9_&Bqp zzU_QhdAB%rRiRj1D^ZRch`OAvSA2V8+9z#i%D?>96faBT=SREEowwVcGb)=l#xRh4px)~!j(zTWnwZt=j?C_~tIY>?8f`gZrArlo^v%GOx7?e-|4*|#@y z8R0`a4()a6sN$n;{+@l?jfsCQ#?0a!-t{HQ~lG7bt!w zcr|wO&9e`|vX1`bxFTI*DNl@OU#(g5onMvxR`tgd*+Y0A~kNjKe$30CP zx%1zO$}u`vMX=G6K5A@c+t~j6pkE=2(=+wxMNlw~V|TkP;-X0 zZJ!vDNf5B4*m9H0{3T_5*t?O9E~r+bh_h-@nveoLYB_p%QEyYU~^29 zzDO;2@XIfUoe&-m5$&)oT8T^3oDQiiT{+UYTq<%7zFY;a}zwUq`u+7qZ> zU%PK%By(0$oQjQ7(DF0q9X2=?e7jz;so-L6Uo5q`F1~cGo0rI(zeCvaAPV$IYPW9= z6+7hDKA)C4nLfdvwWP9cJ*|A1l1k`1GDiP>E1yxxu0G#&YpPI{Dp4m7lf|x(O-5{6 zD_rW(VQ<93o>#iazR%!!f0}(^M2c@E%XPDItBZ7FzlfP%zDM^3D!+=KLy7u~?jGJw z*#Y?v`?o9KU6)VHI1J8 zP~rAuf!J<7+b@%=@O{5;!kCof-f7KAKq$^9?0qNNWAt+TnoozBabz-BeZ{cdZw{Xo zQoDToAp3%I>7-4=Gs-IZH-293hlwj1KKajU|CxfoJ|ve@VuWYqL|{8C7`b43T0~2%Sez zVAjk%3ZAuowDTd;Bx_Pw++w0pp`IPBPcX|!v~FV3S)-a7=Q~d}_w2Tv*D_&|gC4`U z#SmYz%173I9Cul@to1@1p6Qg3SpJhYTHYBB8p)(4rY}dU+BY+*p0;D8FQZg);PY1_ zu^m(QPN!ff)pimHRDTk?At()VrU^o=IC<4fWQiWv6PJT|Ev9vS65zBSJXDwSH5}RL z>*Jo~96F-cz7(o2o)yBTylOC(GSqkT8mdJNCCECGowdl@$gf`%wriu1b!_wA@Do6+ zBO(>Eex99d5%Jx8o8X+>Wz|5dbQO)avCJcqEtpiIbo6h5`gqnxh1e`(cA*P z`Y~cIo|KfL?5l8ka;fG%eQw4`(j2j>FX>jO{8rl_d+8jbOUv3gvedcL#LulVJO97sJ=C5ZWXstM}efSNkPdYlDUq#XoIKP2%IL7=NhL^T*r0i zE!vp2P`XJZxlC0Xqvx4tx^jOvv_G2}YHbxZGHV~yw1dk}s&-PNh0Vh@O#enFcSE|` zC|Ag6NC8IYty9=50)W{$tXF8aV4usq2yNJ|Bk4D z+QiPo&*1QLk^JwUS-;LH9x}PsVwxgJd*b%=!S`0vXXCyrl3E0eMh>`1E=P3k2KWes zf+!rdSnP8p`B?0CIJS>#PwOl1LL&~#8$Egg*ExC8(85D&w+{tYhm6*U8-3Et`P=U9 zU5@dXJ7HOo8c8z;AOByI()IkLg-#u5Kv*mT{;ccKJvrcBqe-0yh@gT0HLjDyc3Jr1 zhNXtCwBa@IhMhS8z}GKGl8YdmUZ;L^DIM>zhXv9mf-WNBRagF?U%Oa7q65Q*AxEI#( zO+G(JB%XzJ8Ou6cwW%{iF-lr2h$cm!Ek=qj02| zA6&9BH;yhK|H%6J7NyAwD-x)S4ADt@f6&gV@1FQ8zLPHNNZi1U-h!$JFX0d;1$N_` z1q_Zavz~s3`dZJ7EbIp$q3XQwLTLlw8ZbZX9@4uVm&2S=vfX`*B}NBMvZ!_``9HTK zy`p4m`m7|>*coE!uH`Zx#yeUgUkseP3$)%6H{e_O|Nq^*muv8dBoOo=Yjgx*Yi$19Rpy5wqM^o>xWUbYM;xTa-ZuwA zuvDIa2&PFvstj>!l{S(iu4jR7D3Nh|HEfkR=q#%IX%lc6dtNJT z@F}S6f(XNj0DP(xD|D3$nt5(F=QFbc1lVoDiF}!vl{sAj)SLJKNaJ$HE&$FrbziW^ z`eb%Eo^Stj^ebI#o_(n}fNEfKo&pS=P6rmG6h|t-zZTd$f@!~<0f(;Z5Cq0I`!C=( zcJcxKIfZE>uod61C!TTarkt_?6np)KtWb0v0c=io3&47J=>sepO(DPvgqWQG21401 zU{G}pNCWj`;>r!6J~%cPffm!QG2jcCC@%2Dt)T|nDr?Xg(Rmi2qdSFx8bylVpg#g) z1*(g>4N{rZdkj<(9|eG+tVfkh>#V^`k*Fo0l7@N!h%k1F0g-tTi*o=j)(-|? zODa7VFs>*oh#}4cEZztx?*NJGE?7V+rBVcJH~z^@K$7el$Opc9er1P@Jsq9^DhDF+ zfv=vaGrIsFzk&l~ENS()?1AN;Y%gFyFZ$Ic15!$}Ff$Nx#!1))ILEHXkWhF72&` z!;xT2mMghyP_pGQfx$cYO~@ddehl#MSsj$d7y-y*a`zt4e|1ui3$Ue<+d1{XIE8uA z9x(fk=lN`?$h!4Oot>y8C`uQ}x(tv$O7~X~x$C6djteOzcX(tIh$?3Fu>$YslGi?i zBIolC>w_{aTSwUjpv4=0C;)0WLP7wbmXhHRrr~kufE~aXPQ4ldm|D9x--&$t>xVZJ zAg|K|7Jzr8cJ>gFC4E4@4vd!a$^*J}9chCw`=WhuP$N5C0qGGS85{@+n4xk~J+THP zJy}7hw(&KiS3xkWDL(j{ed>|4Vb_!5-Jo7-~#E>h*P|$-&+E)oc zVtr_&7)mRaJeWt9uv0?-7Q7(@w6J7+0^p{QxfL){oD)(&nisj>0yju?Z2(nhEN==% zGA}^{&DJOfXtt)R45=2! za{}S#avujU*G*0!xt}|>I|~9MqzR^!r*JL6q79t^Z0UDV$lYftP{r_VhSHc4

>uf4D)d#0{h}otsXO?2g)owcEqhFe9#I_6q<#V&PVK9;OG@*lDY_0b?9%QK1jbLV zE$?JR@($(jBI9HGWt*ckpC-q9_)^#|#YS9m<3(}_?)zFF*j69P3>~>U z89&({j$OWDgtH(}=I-a$-`B5AK2z9yElY6=?G2mfK5i)e(O|(Omgi(F)dAi#tuKBu zDyMUL%X}0wl8h4lDl@1B>Qfu9wWT?I$McHx^!i?OT zi!XIftVbxfl;vi9$*XP2t1s7=GFimKYCj-u8O=qb|74NH9Bnc~6}1b#XB2)``gqY} zB|w$ry1=3*|A65{mt^>L2|JZlqxyYrBMVGv0nfyoYg(+Au#|(8loWzAJ|?*j0euiU zEldI{tb%{^ivAaB_;L^fAX@2i72r^`uN_E zU~>SudPL!yR@<&N0!qg$%b3F+^=;Ck11S|siM!}d1DA+E04Gy`SISqnd`p!Wirrp{ z-Y_fPzgpNaL4{)u{p7cg7ai_GU&6QT^2M;gcIOx*c)}*KI=;KQD+B}h%N`OPD z8siyr7>~GHvf^#@spXyNUwv})v+c17uORg;{GvlDC5i)z$c~#fIX9E7H~wFG68cj* z#_kA*FsfdSMF-6m>ShJ=<(@%)bltnqK|wOzGf}G5i}og8OTwR_4Pxoi6y#-o*Z8o1 z(VxZ`OTAI}G zuC55^2H|vrIsUJv%Kb^^Z?7IK(s9cZ&z3R(T)@xRnTtAqc$&9QOl|g)1pUFwM zDR=yGI?RK$wr~87G06m^BrQ9R2q(Wj^a>~l?PxvIKU-F^$$W!ZP!Pa&k$DiduG zk9A<`|Ej+DT|bc^VapB&oXh4*12SrIhta33u6g(`V$sp%*1o>i#ZwDnr_0;A^?y~_ zB*yGr`qRq`r+1Uars*=W`lbG|$xImDaVwk5sW*+y&7FL{M}}A!o7we~v3qjVYqOj> zefCh;oU3m`Wu7@PTUe4k9#*x=jkXnLrTYwH>Yogc4%36i!_GzSOGH@WFBL_@`y`w1 z1Yg|Fr>B(+3Vzs>{Q5*Ucd+^WX1Je6k_gMh>2^l5Tt@SsVN3tJdZb&^xI2aoGW89? zA1CK=-5!S}p@()$xzgdGeG#iS^9aW@Pb3@`mtK{5o1=izg4uNRpAN)a^Rwbz4~yhK z%{Aezj<{1?bnp>pf>+Fqxhy{{Opi6sNi1S&B_bp;M(~N>>0x@rV{;nC_En4fY zw)i*0w%r*$TKGjt6JAeh{wi(*9MZ0384<%ujK@zrs@y6S zUt))9#<6(y&Y>g5oU3}AvgqdTDr9*P?pV{y!l!x+`tb!S1^%J2{2vmO`9Bw#wbUp# zniPdxJIkEnrfOakrw4sMLC&~O5MjwZu@t=zf?7S{a2=OsU4_k3Q9*@___tT@%{o|= zHdbQ<5U)6W0i7{JP!XaVY&7Q#_R!yoyzD%@Mz}T)iCBr7p{fc0Qg9&kC~!rT(GLlT-e3O6+$tYseLho$zoGbOV)`I|1QO@6pGw4?Rt3hVwN`q`Bq z@`=}@Tf!H1GlPfX{(gt`gNh|be!0U#>r1Kqh^ncbD)lEL8S~1kh%za%dhoa6s;N#V z^}tATV>ecisgBFdhWaA-GlJ(kwwuk!w?wL`k8ZkhJc(Uq-rJ1ng&-VKh@LVFm75Q` zkab?=m%>KWDpm+H>AtCa!t*qp&HPO`o{FItC(H>GQAHc_R<+RjDA_gG`fQV$R|W!tl)cbDB(}&kbTmw8In!C-K-N$Z;2>2+Ei zi_eHh-OT%S47P^X zF^y-qEr${0&Di7@1N>HUIN97rrYr3Cro(P#rUF$rg9V3^%og2^NPn!=hwP(}>^3rL z=xUfzDh7CR<>A|j&bKf*e~fcrab$(aHZr8=SGjkhR^6MAH3ex0CZkQ|J8I-Rs`k(< z?@P5|k(I<5cAT5n{Gf=ZYNo@p-X8w6oMlqmU3g-8)Pn!#Q%a>rUkp8KOU?0XOyTy- zG|cPg*4Yt!g8B}uUL}WL^`G~zv1+M>7@i#ko3JxIW?>mc{=Fak`9v7E7`$LXZyfpO z`)-VI7A>0$C%4I{p5MzoaoRMbdQ~gNONXCjQyHPI?-V)yc<@=Pzkl$d&xZ+xY5zWE zvZ{9i3xNiW(?>9h?2vROB#qS3-6jH}i48=yOkY!B|cK5w^2_QLOgf>ZF78$!Fb@Ws{S3%-eLl+af~u zc(LYH@#Z{Zy7ERQ!@!%=z;9-U=G^_fLM)DI>Mf@NNoqSq(%=x||(> zM}2oYpL3;lo4(L8aWtbDF-Ik$!4ej9|48uYOUwD*U7En2-COb~z>XcqDC?E!s?@3n zZxd6xq-S_x)j>_noe%Q4%?G(0xH)Psk>md7fhnC?8k}!Mn%LN0?y}2{?HjuI5$FmU z)^_-7h>;q7=B43rjf3Y`32joyTz49Bma%L1R$xcq)(l+nCYfP&KkuD%GpDrGG4@By zSL2!qwZLckZc#%tdvNw~%a4-xHKwY@s+z9P?N5z6CFK{D{;-J&%Ab1AOcf#$F`K_< zR?g(-xaxb2v0?mXyB#j4UO}ptnY7K5iO-Zlmi^aE#J`DU7LOHJ^;hMpFR*Jf^Nha< z9G&}re0_CTluy*QiYSsIB`u9~cZzgNcjppPOS1w3(hah7_afb(bVzr1cjvP2BER>$ zzJI=tiwo|ZIp>};XU@zs9G+($(qREAPQ_Oo_Ob&8_h4yv9ALb_g4=2NapC*^Fwtmv zm6AYk*sEbIe(_bIqypRSH(&U<=JLXzi8*2My%k5%<(30gz51Bam$P}kB-#Ewh{`6o zGqRNIq5IVcdI?&l%sspvANzYqet;5gl6dW(_x=2!Ax`bB7rS00b-~Rk4GEF!_80Wi z?QC(bq3%_)S=sz_h&b)T0v_RNIkhD>u;UuzL8x?d$JxT?#{+*O__*bKxQA3nk_3 zX+gt~a`v+f>#=FA+_w#!KrZCk9<}`x4QFYH@s>Ty+n*{oTZYNHolM&}g;qI!x-M}a zG|EFC!f8;k){Bh%bUEdsiUaH6whSpm;OqCaz_1yNRt<6MLwt2R860sC>O&R)E^Kf! zuNKUu9C19a<&E_2UydwYOGb!8j1><=Wml}kFVE4HDM{2#hcuzMLv$4u;?bz*Mp)g{eo4Aqxh7DrW$y^lQH3PiZ}z-v;XK^VJnzW%G-t zju~&Aj!TtW6w-%SAA*ME?vn%`@_tNl(jNHdjhzXiOSwl91B1?1^i6n}NbExImzCf} zB~q=yq)oAKY5Eb;bpsHb!Z?>tUngUS8eXaUwYtIu3r?*NMe6AM2t>OVLOw0PhgxkX z`Ah`z=-${1l>d;*Ise($9TPZz-frsvLVX`xZeVz+|35T}^75%@WGnpHKjbYf?C`Qj z4c^rLduSNu2aTjsk-;f@qUVnBZya%S3WPactkYr9)740UT%P1?f`v4ris2(aeR7-Q z^@NbU<%OO|UJ52*JgH_Iq`^_Jh2#t$H0TCSyiHf45A%MKE0Korkiv=A>1yl;w_VEtc_*bw%Ulva9}>)!iE z$LZL=)SG01JLk;_MHX)$yfd;ptMxSPkCSMp&W4`-u?Of-|7f^n@Ua}bAQ%1TON;GL z#rsHLKDmbQ zmQnnvvAuJI|4{R7(0_>V;>%OB+&kToFaC|qLZ0jYB8UMm@)L9ZL#*->i|2Wwq_3{o zWNx#!rJt z(LnZOsB*LJQweBS^VP=ZM@QM8(~@8Y!IlhzCQ3R`T_T>=NC}M%YV&Y zRz2vxd1AS`rJ;HKO!bPcrGJ;mR@|^3Xyg6V>T1wq90{yFu=1ooBCoYbldlr&aKBT8OW_Y% z!GqE!jN3<4B)A!Zq z5vg_Enentg5=(dWIHs(@M@6&RL5_FO@sYTwyoG3s_i=exnAVSAPlXdFTj{DrIQ>H= z8AoZIkHe_D7PP^$^hn~~6}$1|R+Dgyz9&y~<7=`XnLW~FUi*&dB*95^Ovlx}{qsb^ zdmZ|xaqkb4{a+N${~w}xANil0I-$MBlg1=L-Go=vV`F^TfuzL7kF)a6@43OHm1s#Q zIBc=}sr`#Cs%fL%$M_@+=kGSw8H7hds;K}ME};`#V_$XcsBS6Q$d97!S`PmCk))G{ zfO&WDQNvaO%472m3~vHG+moo~jXc~bi9NL}kF(sC^_co(1OHK>yUv~HpQ=rAx&0Gj zuw4$XOlEuZVk;*6^7*(DwZEr-l1gL+2|S_Na-S!(FK066_7ssbUE*s`4%;H&4uAbG z6jJR4cu1Z?7e{onf%DM-?+Lg6X!ecUAH%K|bDFAa1nbF*o?)>xPkv(J{_1}!^0-3X zfgR3XJ~c8GF8Nf)~T{#R|=734Mo%!9YrxX=T?YQeh>%x5k8Z+)r7EPVm(f}6i! zlA?k5Zw0w)anQl}=a2oME)%t?EwZ&k#uBJg{P`I$-(}f7y_Wr-AiMe(y{lqL8eh~Y_46~YNd-G)AZ#V0APbR!s zOZ`tUKkU!bDjEJ!x-rr^>2?b!nqgelM9Y6SUT5vvtu&J-LRR3x%y!f6JE;CuRql*7FueNpa zH2k+*MJsE-SF?H@hS6}w3H169L5G8{x{&#A258MmpmjJWpqFlCfm}luQe_^z7q9Ek zJW7pT;nayJt4p-LzUtxcVhY7})pmqirl;kWZLjsXsR$ib-GDC(9u;gN|27p=FKr-P zFQ&f5{yAuSeYGX-fQd*dQL-K_9Ible_JW*L!ylds&T{ED!KyO?;jWIvZOJK;2rweZ z(=%Ta)|e;6L%l53od&M%!F!p$_f@5$GdHxzugngdM@nQs?z!@-tuza7)9yU0*}fa%t%KwUG*tx#ZaEK-AYez^kz5 z3|qANg_+!TBI1Q=FI6enCxT{JCr3+>F@IrNFu812!+a7Cf!_hoVR{ z>dAl)3P0W9sV@Y`4AMSP>idr0gP%szG3_j{jO0ppKJ)jUjUe7o1Wm6+4&jk>lLuXjN2?Y6Aj?uF*zvJ}4nSLL&V zqN67EA3D(8%;7J<^^FGp<|Oo$|C8|H6)++8p??L)_vY;2EB`VW=U&$qfvD0?qrD%- zc|M(q1h{*_>qFzonzm!RE%nA4^?7vl&dYgXcv@DG=wr}XIKofCM3G36uKm)N_scBi zCpBiQ4dvPI%r8w|Fd{#Xo?#7mS4V|PJHW&o=kGoA%)AzJTQZ3C&gDgm^ZQB++`jV2 z<}{YdAS4dPm!Hie>0*9|8;Mu}6{1s+2jBm;i4&e_dIDe(1ur7L!C(n|aDze3_4 zY!u)*S*#Z%q_1+M4dYU18^pe`G=fDmNV;rdz6tY&%>X2O-Pbmr|9uD(ndTzw*$2E# zc{KT?Vaab3o|q*;_zh|Q$&a7W9K`AZEZ2Pn`}^vZItw>m|IMbEy-{ZFhJVGGe_ z7jdEtr~gC;qH2-Y<4~hi2w{j`BP&v6rq5K)Q0 zB|B~rdQ)V1a7}(bZGFDC!DjFpzW)n&7)od%x{bxY1!>-DZ@YdxpGkneKcAvIchm!M zonO(P59!UZX{b;Mr> zIxJhHY%K_Pj*x4e@Qu=t;DMR+6L(Q#&OPCLIt0D^4AUq=*)Rt#i9GrG;@9&Ctv{E? zr;5H0MaLDciSSHlkbYRoY>O6C&_b-t1;U17l~;zUum%%9FRMmL6ntdG#U;nvc}fK&3NAgbU8sO=b3Zr{Vsj4 zEI%0JFz^Pm*GA7h6`EIf<+$yWcvXAIX_3EFTIXJScJbVujMGryt zxvny_Q4*gyp(voZtrq|_&Al`iv>e<#^=LI`<-l`tPd0Eu=Fl+0JqOf?IZ-6qp8}Zt zH_@4dx2NXO2fQ0P3C}D^0?mcZMO$B)mSg_lwTspS`)IIxQI6|!E~uv;e9_@=2+-xu zN&<1rWrXU%^Rol5k>twtxVGu=q;zA=YM)i%9sR8o_+acFqEGn|`&h@!lY5uD&ve+hrLM0}#~DL4gje@3rOQ7mww>o_C8Z zY3u~cRmy_ioolFj_*L}hE+IlO=mbxu_eTAxRF6$_X|ORG&#%N_M!7V|WsT=UqLFjb z@LZ3Z6qIIosQ7dolm#UdQ~P^?s7&ZwgTW#C4flm}8d}3Nigk^M!#BH1Q4M#|Muy>l zXM*PbcISSV+8K?{JeJ`0A`060`n-N?=Te`w_D#Q5g!DPb(yN0jzd#*I@Mv&`((DI= zl#JyJg$F8&fzICsc5B{b?E_foGS8jM&`ty76e=_j&YR$9-@X4-_Log~1?-v6c23kb zTJ^uH_~bWFlxq`s;x(#U`&#_B4*XeWJd_6b=ez}6p*KyOs2T{M)bOi-D?Stu#qs2i zc|mC=K9cIQANcx2efoDi%WhIp2FP#ki7|*&5UsvW4cD`@WzY=p=&%oxYsiDch6Gph zbkS)w<++SwE5wGLZ&$Gl3-P}B3PqYPz6(T~UnS7D$P6QOR})dOEt9;oaNosx2od;^ zQZ`dKq+K|qkRaQoDBX?)W7A5*cgP?0Lm_nJZ7a$RmDISi2`fz~ZsKb-7vgX$aSAo4 zY$34s?^yd(!n$Yf6BU{`{wt3`Ia~L{bnBMkGYx-jK>Ktc!}{NHeU)}D^A$-Iag>!w zvj@szhr`Sc|G1ybImGHXz#l^fZ;`He^*-SD!(Ti>noJ9Bx81?Y$gs$WtZCtZ^4)Xo z(4Gifzx+XegXnz1?*{RBG5OJ8D~PH%s`*_tJChD~gFdbiR9!LlzL&xd(*ZvgW8Z5O z5B*KQ%l)n<{Qf+@?5{iOlN(zQM&zUYB2Dz|1ZFiQ^?;U7?qwRp*UHKm%_cH%StSes5|yrMn0qtmXhF)<|SyG20o0}_o?Kw-Hej`(<-hQFzY8R7p~t&df4ukMj(!(foH$tkhIa)3CY*UqN)CvMK zmWw#Dah1R?{X`qKNk)eW_=mPhMAk{VuKhn36MD~T{vz4;uY2m`{kBSqR`19D(!U&- z$kn&NmInNIStA=EMoh_KbI?U zXbfw9tv&{wqqJ{Kk=op?FMS>Lxc5+h?W9m!UAVoEovJ;84IR)_U7qJ#c=(y#O8ffn z+eJc{dzP#m-}?CN2%}m-qF+tj+o|uM-<-<4%%Z_Bx!3Bq-@_MOHzouUHV$_ z@t4!tAe%^K_$il8dF_l$Q|zeaE>hagAi*MTA01&Nk!J$Y#$s|;=&X)#wdb9~Bds%5x~;=!SH((K4AAAm_H z|L`Y24WGqiTxqarLvEw3j3*n3y>zvFx<0$@ZV9-avoareQ3JfH?#!=pJ@`>8FMl9c z-!Eemer0Dj$Cjw1V)o$6Vi3m+uHl_b-VMncpKn~C2Ao|1Ls`J6p z6IFQ{jIf&eTKd_su8kj2^}jhv%WCQ4C9tf$9Xm$wZV>&)}a zSp=QTHiINS8W+P~BU0VoeFF=acFr{x5GWd+K4F1pT{HxK;zU-`lGvXB2q;1|YL-MU z`d{svs~Q|uaIc{32{;>0j27vSPfRZsNw}vrc#NszWbe3D`vlCm!x@zD{alXJCuGuvCo;cWcxOKX5t!LbK)AZ@W*Ke%O^?C@Fp=y@S>|HVjnEI zOTHOd`XQwQP&Uja`et;`D%l&&HS0cZAU+9+JStyRPY`<<=WwS2IPNOmC{Qj(w(+rOo}D z8SYQFN=0dog?Y$o@OLwvl4P8c|uboOp)j#ebl_HN=Qk?owKYV>Fr)q|eQnzGe6ImGnOE8EI@-QBv`^q(vQ zCunjHWidv$xH8WsMU+M4^JCf0o}8Rl9DZhCbYwh;xa#m6`}kaY9$!{FLz}UWU$(?W zwyN4mwn}hv;($I^ov2Lu{L+S;OQw)&r`!WIUB$D z2G5L-d3ZGVbTY(RMmYKdQFTOebwugNXHQSMv`gMORDLvXoweS{LruDkvnt+k6?y}{ znTa{yjyRY1Ys#Mw&Gb$Vxk`PfK8(O`80)MPS{#YrMnuPNdafI-J<=~WIY(eH2Vo4Z zb-n1qLvc-@!V+x4Z*U)2wN)=no;!FotWM+6I2yb@N~~vPJsqgvGl|L-DFsB-x&=!e z%QdV2c|jeMjHPGG7L}}`m*1(3C5tenXPG~2&bWXt3rN;+J78R@ixzh_Y+QvjW4(3d zpQ@>*T5H-&zB5_y2D-X*j_5GDau#?TPe%Avz4)c}qd2IpQLa=)8pT3w41J>Lvwcu} z$3iI0-J0zfajsfN2vv<;VA+}*BjbVm1=U(H3+MC#7+jG!lp8^>E=03>==d2=cO)78 z^E7@Yq>sP)E27AOVP%awfBH+^nL3e~_YLZnfwbIWZ(Sw)^O%dvNa_8N#UR5@cT`|P>FgH1! z$%#4h@Di#fliamI_;y44SAPf-v2&*|r<*w;jblswKoZeB84^bNBscfT)`@oTDA3H4c8I)QFw7=2h;p5twTo-$zl zdP}gD)az}>=Qy{&`)@H=EDb4Hj;{?*>gc;dt*ZIwIVx zcP~FX_N$glB#+Yj333kHc?t+l@PYk013Z9RE;bHmLtjb3n22C&UGe%4>dY%F_B3Cr zYJ{yP%NtQtinTfQ8?rfDI0xG6YpSc6lfoLQ&6ak0l7w|DsC~`Zz$c_H(_j0sv%1$!{}XMsueWbJpMS3N7s;7j-!O{qzF0u!jEVfka&q3#hm=c5ZN!HhaSB{2Wk|sKz-45O z>R$yD37wJUF)J77;t-c<;&8s48gA()w#X^{?N}i= zNf4P;u<6Ezcx`@7QTr}i+5n|)GsLn=824Z^|HP7Sa>aiJp>qdsP;+5^6Z}%uw-84b zQ`_9~KE|U6zCS2#BAwGw8uIr0%QG5hJQov_=d0xMXLDzj^$zezG;tMSPy~ z#uGC3BG$~JNv$3{$(8Rg+7TkdkTO~&pmf)kXox1jn{rm|2DgsCG-<_7I>P z9PM!R!KD{iis^T%SVO6|q?;tI#T{<4aMxfzbSY8!+1jjTQSgg^<1Bzg7>yd(7yfLg z%y=pDkKm8&ie#iRxA0WXESKJx=~WW6iKlVJvPSF=8^)N|g_Fv4TF3tc5 zwox_rv}F634E5Azio>6itL>Fc;-Kj0M|u2sT~^xhrf0YOR1ULYXfuT-f_8hd`NNcZ zXAAE+z6`G~sI$>x@P|S&mu*+c1R$9pK_Z{oR=**Sm9N=nXSMo5mZyfkv|2)EuJI>M0IB>k~1{6eo8t!^1sBIHIt@~Z(jL5Ddifo%Edn#?%c#eO5Pe5|BwXL1U4 z50H1kDZAGHO=54-e>>`9X*Flx>wuoOIM)T=BoX--!J!Cl1Fo8!k!`i5JErGOb)dG< zaHEARwY_7{n&x5+n_QCeBpkpb=M6*89HS%`TJ@>n32W5)g9~VK^3tWD8bB}!SvAQt za)6HJ0X(+75PpxqwEf%ASZ!V^3J677JC{cS{1ZS@X zNwSut@yeOYp&0;=o0Img8*|`YdjI8Wbq(vtpRK>EoLj63?P`}jal$K3@&?61Ltd=y zNlC&}aZS$hW35Em$}vRQ6_L{xq1ZI}h55WOa^!pS~Gpo9Ih##(KQ z?j3^GKEVSHl-1N%NUN+8-0Fo@>hu4;PLHf)ZAZif$ zJ;F50zSx^rLNN%iwxjG^8r)F|9POpFi(QiQG_Y?-i?}7uz&+J46C;q$(WNaux&0NE zms%dtfe0LZ^=`pz0Dx&KaPdG~00@19< zS^GEKRV=aD4#L7I8`uMbhI%#g``(A)K-KslG1ssCV+f?Y1{AExPh8e2ReL_RM0dcS zdjuOGVJ{WX327d<=G4#{--#PHr#iC*?@`!k>=aD&%C7E^82(fq8=SVJW8j#@TJnz_Tpvs6r6;K z=7=eP^dkLFBpM~8I+kFP?ta?vE*kjF3Vsq`ri7#{b{;}Z_jEuhg+prUc+;YWkYixH z{$5*D)A+~Kj`&mlEWOL$Nvb|=@!Ttwg+G@DV~XtgiPJiS`TvleFsHGKNP?VBV|c#T z`x;5uJ9hn+M@9*+LF}^m5NwC?=g%ixh%28!ust8~gM7dU-`uvOg8n<$&N`LDuLJEd z!vMga6Ra>d!C-rSlV#fgz(oxpV#FhUWZCcy!Gg#tS$-tRm-h>XgwT%XKJSiA{QDx8 zugQcDoiDz`905H(2AA=lak`6c6nA07KL9j#C}Dr#HYeIln-vSmp74Iba{{Myl$j}g ziR+->sO5aQz3uZ_YIP0x1uM9i-B$G{77f3cU&oyuE@2r4?$S21z96utO=9j7aj?aV z8D~mvfq7~c7)?}oS4!7Tqtf?tE#ObN7$kN19Q2O4Ce*$~b49!P0E{)a`3oM$iz2I3 zz!MsSELtD`tWBENfEKdp-@X%$!@=Q{Ek-n{GFfxM;Wb!GRg7u3^63V+EZegZI#qi7 z@f~e)uKIl7)o1y%+V&F^N2w`}k)$?bGT5YW^>%ul7W&rX{~8 za`4%Hj?0oF#d}E)#LE-cV{6_U9$9h?{>qh#6qZYa!e;)#$ zN3Czz8UF0HuM?oY(d#yOm(Q1N@&UxIXBU;S_5HNct>4I~15h zc+Q*27oWO}g2+P2?NxJ(s(Q~?IA`0P8QejiG92X=1emmhPrQ~Rcnq|@esAuam|E_T z*!C&gc7^1%TV&g(7QQ zUe#f6j!unVcR;#gOntBLI30C(S9P3<3AHzoKbA4rGqo33R`!WVd=&xGCgs!PD~MfS zWVk8xK@Ikm4?EaoL+Hmu=5_&F|Erj5Dh!stZITK>w^Bx#%J6S9vgxy)HiJ}japNRC zb@pJpY?qpm6Rux&O+y7)1~0SK6^#Q@_tudEIz7ZW_n;H13|@Y?+y%2%{#n;(MYONV zgckEo$d$KMC@p3mCsrL6ORMxcrF&p(Y=@S@APcFZF4e|$R*x*f9{n4Zm@PgQ&<;v& zQTt9CCG|nht9L_Rl_=AA4JF}0DP`QZBU31H5?-{5qjB)XGjt6v_=;yS_8RN8_^LmG z2Pp%5F*)L01TialWfxr^AE@`<_!>|~OdYIB=cEsixP^{?ERO!{+LeKI{*FMr>qPRW z@xD9=aZ(uMqB93>7j9nkfoyY-R z=9na7Yf_tujJ@+?wdE!44bT=0TuDFIGvOaaJg3bqU9c*Z5KvHx zjW}9PKe+$4_s+K5S*|$PRbuXh$GobNafir?GlMLrPIM381o-kk^1`{=(LcEA`d42~ zpOv(OCLl{v;MQOa*M0|~opEvwQ*p#d!``z^y}F8W4eC6;FhNM8HLgfaqm7VxdN2Nq zXHsn^5cpduSF*}qtH?R8Sx_!MEz_0&A~Q5T_$AN6O2b-8`dJ~fhC=9)-Op(Hf2*vvB@pYb4rU}$!18>_QXbLHG=`P_&F>@=TWnipXYVT;P;p}DX z-4Ux+1WY^w6t}}$@e9fZ6-_x z@bQEjb5Y{~KrYC$^w6m^#r-bYr|+X*+FVim4)17ssOha0n|I{UVLMxD9(uzE_)EpE zu`Q3TyB5yg373xZ`RL@eQjPU@X?EN9oGY3&z?vccKh=bqxz!+;)tGX6OLWxGMCkW4 z?OEEfq0@;y8LbCutp~>>A8)CfrPz(8HF_HMcA2GJSz%TLXr{$l_D!%|9PJry?6Rhx-HuRjKtu+0}!!#?;@Tzdze~5(<#&%$cN+dpA1=(5|+0c37Le-7dmG z3m>5s)?Ve+uAdgN3?17;$l6J>1h{4;G6Qg=M=W*7XUTr(E0;S*bln0iy|kKeQW9#w zGfpkeRjwbl@y zV$zxXRmD21*=RX2y1hkCE3Ux-iQtRgqJFzB@kfDjP-?l*q*G=1uomWg-Wg+yg2$vY z{)>{Y*?bnSwsO2R|0E}D;U)dqkVvHf8WE4Rl{y|uh4mqEJmc+Ch(1Jjj z_>8ps;&c7pj#KjS39tV-b0vAo)~zk>dF!Y&hNAGz(emu)wPsr*j8hPkan!b8dad+> zxKIyX_j6@-ysVJ~Rb(s`HexrynXS@_PS*Rxde4z~sB#tsN*AMWIj>w4b65hfBaWun z2i7OBnfY2GyOiJfC#A`Pz<~k2-SfreEsA8sYsJ-<1p-hl^Oh)K1`xaM9`meX_EFV6 zwVu z>?6B@y;c}u8PENAeEQ|xcB7or{gmFr*pl@?2;xS*x9F`;x5bbF?1D{r#Lf~H)iPDT zDl8Q(ObsPJL@9OMnX4r>sU?J_?)NL+MV~_>Fw)oV4v*oAG`ISPa~K!)k(bw}V;5ZB zceQ5FhkR3?S%VC3rCX*Gm-h=-&9Z&tLRAJbOJd$P(970cI7iWWGhKV=)m1vZsgHYY z-y&>|{;Ku<41@&Cx^HjXj(mTJ0S>?gl#<08aqp(l66}KAs)LpHK*H(6k<& z&g4T^6x=O>FW=l>?%dtA+*hT$)cytiF*=0>F$*6Q52UVk-kgms`6Nl)>@@gf{spCD z7;N%Cm}Br4oo-Hbw^R}PFkG$F0<%RNmFY;5UI)IG0C=@GjSF%K-6?1nkXI2VEs zKc^~E>{J+370;yNbV0~SeJb@gmvRk0=Ggfg#dBCXi65Md#Tl~G1# zk$0L7#WKl_{huJQC-iHup)tQRSjO8sycGKl(D;-Q^b*FbB>Ni4QQizIIqKQ7p9#;O zDaj(d#D0c^g!F7w|C8La|Lf~L9LtNViZV(oNHE(OIa>kEm~E`=T-?~%m=WN5uaO>w zU;L->|K_3i|M1vY8Cx6KIax6|+3z>MaZ?qamXVc}#TL@H7gCbNLvHuChnAfQ>!lX9vLwfn z(^R3;=)z8*>!x?>9_(T7Q`ul){$b;8VUdcO-j?&i_kYQvYnZ%Oud5yTr-b4GxMHQK){opzu%VHBwyEE=jMTkkMnms z%Ualr5$$gyEh^stK9MHgmV^TNs+=LV4ptH0FA3-HG?*87Sp@}eqdRZOYsad~gVRZ` zEsMOCg_*rkZz+dql7v3ewIF(r`t|)h#2d^}#PwE6P(Qai2&&Fh{qzOZ%_OUt@u6rhmBVCloLvuK0$%ou~9&Oe#$PUS9+7^fdgN~A3F(B zSJezC3QAR|-|X=Rj1Cx4+|u=j`BqRnj6(Z^kO0yVwrS$4_$}Xzd&S}Wy81jp8e6?& z88=p!K&n2U?|haHU|t17#r#v?p4H`C-gsHWg&!aB?_E00m*I^0w- zADt&G8OSkHKHfu!-4cCDDvfxQxljMYl}~z1g7zUFdnuK#GB)Ybadj&<8H#z?Yzmsm z&h(0pHWxFc6Nsb^-0|6f{y5IY2LlymK;)kEC+w;ZALEqMNL$f5@d!8Fe47z)4y*>> z9BU|Q7$`b<{qZ3=<8Aq|MV)G zuFszO49sihk6mWbS)f(fH82Xn=d@6rsY=4?>l&hVn%z$_>57*p;B--U*Sb;7Qtqor z6W_?Thye4}mQ*+%jw`ElS?y|bsSvVT|Lt&~S~FMpn9fzKaZ?vkUdhoAu zpFdcnV3x{}^dNku3DjBw(XUkPtmP@dxaYDRQ5W7>cP7Eii?m>(bTe#4mG^htwx_rT3_)HbVyjvW}%z`ev&PUizN6egB)bLI@)xrSU>O44XkF&5K4QZ;G z0gaHHtx~W!&FLUez3@S7P&G8Hl8K^;S|h0g9ydIr+zOd3IdM17_9w z=ilAvGK7lZSeWiMK~?2NsXv6fYv2WuSPpj)wsBm3SWbphGK9se!ETfSH6pX$sDS~3 zdb74hu0eudW-}D_5gIjTx4~GUMy`omF$zuSz_hByKO}GX^=5ml$?2RK)MpWY<+o4f zgqP5${}F-`+6bh|>wef%1j>ilPhHOj!h#s?tiLV@2iJa`+9EDwRpikqp(8sD5zjrZ zz4#+8EIt@qtmWKcbFwW?Gw;8P!8A*(!!Y7p>8sSrmaeqA>c&G_b22_Fhg5M3)J zP3J`r?b#a0$`Ud=nh6UaWT`v6S&G_HiQ8(!Dj(PVNR_!!K2t4CKH4X0Z{eFQ15L)+#fh5GR)JMo2e^2Bx85Q3e>R8T2~9T zISg~lY^}Ucn#`J0IJ-i?@z|W}v#X=G@oI6<3VjH;0H>IQCq!MIl&!!gqOz)G^7Fh1 z$t%GRe7GZuTnfL8C!DbBOEkRX$1`w>^)tSTRJ^40y z1WZ}9jSFzqK8=g1p~T^%8`tx*#m0iz}N%g*7vV;X?(H!>A|}CHUFkXtaxdO0c-w zCm=)}4r9%W$W&6V(tdoMck`Eky7$;52Y= z_Ldjhpw*GS;nQ;$#E#1q?1P%D!U-E6QW~=IaIDW?oV~81Xp#J(ZM}@n)j^I9}wgdOAp-#wTBECqCeMUQ1n(2P7G2?3eL^kWCrm9xC8o zOpRu8QnjSqig8BMTknciS@PB`pvmF>4!iMmqrS3$fKfL`ky%11oy6tY#L=>x%SG$4 z^kG6cYY5L#PL*IoN|s*H9gP3c4&SuiURw_s?{oVjA3?R0QA29;o_RN{-IYCW-SXX{w^V@d{N&g zs%eLP{RO^ep5shRJcy`t3Y`(Qwp8Hwju!^&xspCx9r?+?Sva#*lDUqaazQ&nIUvWm z``U>K>9?6Xs#Y2`uQ`bM7^gsJDI8Z3VO?X163wn4jYjE2&^)Q7)JA?d>Wd%pE>Rr6 zw}Wz_9Eiel7sy}oTsBuGTHj3HJmhMq=rreLqD3zT?a;kC?NAfAv&H3SOzrjL>S<9K zZlZ0AyrvM&b;@^p4u2+OJ1+k>*6wP{#Ui4~3=j@Hbxvi~hA(PpGk)b9Tg*O~XOh7~ z^|ikf`-(6)wY*Fayp<3H^+rJB>l*Q)+l-nQ57eP|9K&T)x5}}HD(9}j`rZ*eRwccw z3e@p-PFt&)xh{5q=9Q5v zqhU|;+velv{-rIjDlCbdKaKwqQLk(2%ZC{dl<`bGpu&+4NWnVpwpX_{Eh?i~3r^!c zxKJuS+PDI7%{siixNukP+gYsZ6vPE& zo}+l}+LqBk*vcM6oQv<8l+=Fs?F!PK6DdEYBm-h?T9r_+A z{frmF&cnDNme#`K#?I5}hH@Y`X47Neq)g#r6y5dXPvFq;E8DPELp8m2A56PcPVFXD zM9#z;?@$vrw(Hie$z0$Q`iTIW=_658_n)$jjwUie!w{l&Lq)F^#$sQhc6_m{ba3~gj>Ba7;nfD4AQ z36oc)MIP_DHSQ!PDE+>-%A9PJDRd#?g=X)z9hJ;$dG^xAc=+<~<<%>WPM~d&Vt83~ zjl((jt0$Lt(35dMz`vm{X^!{4OKES+JAWNI^lMTvb!Tu(EgevCjfZW58KSz@<_40e z+>*EUv*QRz;Yv48JV1ngtH#z?#(kktSA5cCK11U1Ib$XI%hiB1fT!xft>9LNAoOr9 z2FaoSrl<>g!sdFAmAZdwZw|t+G4S1MO8IH6gz8QTRwpfDr9+`P$;?ZSKO5KGzG_x0 zF2dKGr3<1vD1Z3r*kd3@T^`P!`R8i?VIL%gM!5_!( zZ#7Sk8q|+=?JR(A1%9ZHa9AX1X-#DKp_SgDt^VQZ(FS)qFID^&cuk@7Hk`yE>{oh9AOw#boYF z+C=>siWMJ*+bUZ8&tzo+lZ=p2dyWhW;?IdvgbfV~n{ZM4j`&3aJ#f(Q=OyWP_fyvG^03~q#SRUGXPS&Gn)WO-kA-Dl#N#ZfV|$}^Me?SR{KGOM_fqs78>#vq^F$W z+5n4&w2VEehP;%rG6Ok{rbI226o}-u$Fc?;Gb0OdG|}4zb;kLklVktHh#O;cS^!TL z$e${kbmOCUcy<$bZwNfE^KhS^;uxV%RhylV*4PA|nyuzqyWToy3k5H2R(nMP-V9yU z9eq7N?O<}$-<#>NKekzI7EE@}v_R3TJq6H0m}dlg2Wc9aXT$<%xIl^BsjX9MeM?&o zn=0<*rkxc)z70kTi@rtzcV>rmPvfJno1Uw9;;6?t7-#FcYgWley@cC4DMvftqn(7K z9sO15p{wgtL0&;B4yjLq?IO+XV!$GD#oK3!0`aT~ecO3#4X0ObDVj#E`4z+&Y$Q`{ zi6?xD3ci0UB59h3*Y>QEpwKpi2f`I&#VrzboI4M%0Cj&4+3? z0)#=7Dzicwnk71#YEfZD{g!;Ep;wW%p%2iXJ{9-oHB`?xU`Okd1-;eos`s`Wc4gTO z0&<fpBI^(<&T=}TnyxB0>U4W!?%=?liadxOF=s(f@%S2?l)T`O`ojfNU`CE)K`0|VT20ndBgCAZ@2hP*{AI7Xh~K+emvJrJi?DY!k_6@nV(aM zIjV>JX3r7YYr(5Ueydz6x@JoA#n{|}w1*!$ z)n0ab2RFYFbr4pb*KFmv?>o%9*pLd@+i@lJ#wxMT)wj;$ZpCOouJlQISb7Z=*ug~+ zl0d42mU=I3(~o_$L+QLw+By6!sI~rnS$g|Ox>xdln0xD}s)O%QRJyyn8wBYN=@O;8 zLmC7L=?3Xm5D)o%7>)k)!S}ta0&+gg#bB=rVIp)A;2JM$M83aZL57!ms>9l&9yGQV^qFN08i6t2eWvHp1Kf z0Zx=3{0)01e4i#7yOAQ}a9AeIpn->vDeq2Y=4o@K{-tm&dg(ysH%H!M*`>os>Tefh zgLE;O0RpI~{ZMCLVtP+$lY0vH;dsqIbqS`guHNitSGrriQ~NcfJiw7gbmidGaZ8M0 z;3un9U(zmW@GdIusv3vK1p|#6`Yk0#yem6 z{`!+XO>Q{RHm@9ffRltF9RP0<*@a5r+262D^BX7sM;lU zbn@D-0u^@)cb~6*-lj|1J0bW?4sSiXte4AbIKB8FYBaV*>O);E__kB^@Y?y);A6&iHaPg*h(?#?#4)Wv)s@V7H|p-iuy znq{@Wv07CV)aK_+z1y{GUZY#|sR%*%DkL=dBA>SuVYR1-jWqpKs5bD39)XoKyvJ))C)}&GXJ;vPgkPQil12hfEqXBk4=-=SRX8~R9>fpC&1TXEe$VW3~3{JC0ePv z_9HxRJh_IYR~mQAV7%e{Agonhk5e)r*IUL2Q4FoJpIdc*MiePiOUyc6Np zAKNSisDnmWZnA3;BNrsCr6XP03I($KhUT>+gs3us9$4^+GViy=-@3f9&W${an`c7H z;*Ug@k)x5FN2rb;ea$kMP5V?+nXVtF=X8om8_hs45{5A~J-gXJniCnHCE9_SoNYA9 zq|V1Z;FmxHYTb8aDW+^SA9=s~-qKa22w3sv8&}h#yGm@aa(=QZBr?#l zpzPeZhO)oJ;;engK>L$UuNjzaq=V2GjZ}0NM|w!QK)9EJbdz30gL@=Kd7vsR;#y#IA|^~ zH}=P-a&&HgI<$B1A4%+TM~hBw827=G+&WN6TVdmeNlPi zq7AbB+w5!I6k8(}BeOzkPt<5YdncnkG-6NDx3xt2TL_4sWGCyAIl5z6B&mXqQ zm|^1NjX>h~^^^aPWO|2w(()TOA|kzZSOJTls+?8t`;7HF9F9zR>d}0Em5U{m8dQAN z8J-AgkmxL0wOZF~Zlp8|Bb3N#pGX(jR(w~zjgiA{E8VHLD!gwZHW?cQvr5B#{e<^p zRM0Bde1fSP9}&fSUBaO06LV605))Jtia2Mf>tGpH3$X-e^?GzOLdCCio2jdB$6aCT z5~2i;5dXN)u+Xdp*C1&S_Ta}m>yk>QJ+p%$vg+`duXWx<42!N4u4S8{QDzn93bZQg%)RTW&0u*In#!oJo= z^k4CzUTA3}lreuG5Lx<5%tB==cyb%{Z@y)-%3pm}2yM~5{I9vjtG=AKXQf&_Xvq+9;A~v7T*VbftK(Pv#d1q2R_?zN6+Ey;IR*W#Y|Hqa*6En@Ypd4}bpSnK=EeN%g5G6FUVs}c8RJ~CG8tl?P8#!NFgg(tA z7fvnSsX4QV%7I>-Lhvl(!~gy6D8f8?eG%RG--=>4abJT9%uW{tgDv%$XaxCa)&WgX z;2-}BXM&S1kLIOj+WS(57GZ z+s+g0ghRa&U~ZdggL6SWXQXknX;4U`+LD}2Dhf- zD$~8VUe1Mhv+6iHJ6f&RhA+uXLhUaEWNHjdRRvBjdU5TyVc(MKP`o+V*pBZzhblvN zIkkB8#W?d` zIQ1nf>D__@;F~CNiZ`x$1p69jmJgtO6N13lv^jZs`8Ac^D(BSl`2tII*yD zgSv!R=fS1}hkih@VuGa)zjF`T)<*5NJe0m4POd9;%Ud)Qy7C6!6JFh1nHi)VL%#ii&6OsA=BqiNfR`_G?d z9dEmF-;yp;I5~=~?e(PXA7)Al#2&YpYY5h#YfS%z%aYejZo7gO_U_P1-~p;exxRg~ z&g$fGN7cl(-mSBH_^&nNHpP)@Q#I_&<+NPQn?c82u>R$6UE^9-9Qf1)e)hiDp^N$V zuU9d=SMgm{`M_zWM(I0NnTnHwVSL25zH4yi_PGpc4F&B8e0&{i-O!gL8p?iAD!(oB z>SSb1LYUXrx<4>p2ve`0bZcAlhj>#GF`%Vx$3QEG6Hk&mMsGb~iv1NGr9A?-U|lA) z+JPCDFZJCq)}7dc(^WaK0+$VH$RiM&eib8mtH4|CIT7|H_R$*@1@KLZapCz5Qbeh1 zai>L0q;IuFYrN76x%uF8sn&@pbC}kcNoxC*MDY=QOZ17N=HX#i2<%}!8K~2xgzK@b zzHb~EKM9M|3h;l+%uyLAR>j$Ml1!n$o_c|?{Q2$d%qMKFx2B(-zlT;Unl*$c9Dn7E zHXs<@D$jL8O;2fRt^ZO{Lq|u@z*{yVG$C} zh2vg`#UG`A5|5UpZuGa&^K-pM*j^vg7C* zK06$xrVd4v7TM02xL8@qH+r7|=05fS9qqptbs=WY$b$9$nhfCOTOr1LQ*m?A7=IQm za5x4kHo<3V4$hg#2Uc+Wgw6-S|4tZC#PAk}uJ93ts!gu1pP(-y8BBhF5sNSkNe%6m zyr`XDoyT4rLR(%=9;1-F(s{k&7<_gT*Kt8zpCw|*Q*pRV);jbI#c_hL`dW(Q{TMr} z?1eP~y5R?9^t~-zlqRA2EF%1^i$mXiI0WzwB8YoiO{~{lhrYL_&W8zc(mon^xE_#Smqza}ot@V1Db z4WZIml=?!AjwY+_z^BdLDdBsLYu=fzwrhbSp~=O6^S# zHGVJ+b2X8?&Ck>@s@6RoeCrMA`4{EkCHn1qv$Q<_Vhx-3((#el{hqG>vyGf)B7IeB zpHTcYaFj!;X3r)bAE2S(A4NpgG|=b_p!zlX&snjJ#u7MRWlOh{6afi5I?A{qCgDzV zoYL`ML;I9#_pGoE>cZ!Gad{l;-$7OHu#IXFIMWbs zEuaYQ)+k`D(u~7*y8RBW-UabGH-aHA8z;EgkN1ehUn{hE;{ENr9-gBL#=hi9NhpU*LjA9wAFDyL7 zB)P_?bpY}Jexpcz76R*F{GqSm(957h@7H2?Kb`6k(bvMPm|sXB#vG4vszq;>MhhGl zEw!eGo^kc8+94fm{ZQgzBLyKQfFee=I7Ag0q%~%8{fXvd{dp4y9s z#P_!_bC{3z)0P^alc}7?XO+sUgt$ZX_sZ|;pP4KFX7N8j2`FN^v0lDIg^UKv9%2+x zV4}DD{rR$uLM#WyjPxdUF(1Sj-`J5m(GWrXyDH$(p80f=OFs?iiZyJm}| z_1n2(biCHl6u+(He_`j=o?87-e%Bpap_U*McuINWIZSVVMAN_`KS8`GzMH*Hlu?^VD7@nvhXvZbNpPp}s4?O}C;49Eye?<57uv%8r zL*Q13pfH5K{xJ!)_iPHI1ol>G$N#IxFoqG@_0V@1U6WLbMzr&uNhq|JTVZ~Pq+)Cr z6JlMrIca}bd0Jsq%ub*uGcCwqM{?GvqI^a#`$EUkX7{s)`zX>DS>3 z36xK?_kEeTVueGE7ocvN7?`G{T*f8-u7w_sX9nf#me%qNsfBIxUGFAB<)Rk-9sl{J z{~U_%NtFpP_LKO8-`Ey04KB+Bv)7+_*|;xmn)$*^6p`r%sxBl3gyzTkQ zW0c*91=1hx>E;3T8XF-k8d0Iy`N2sXWfeeqF1aG{)^*Ncoo39Tl$Y zAi~#3HCoUWr!^5ijAp^sH~%fYFjUj%Kt)92b?6kwdMPI+^xQXlyabA`(`-8S_|M}VE7g{ww(NeLW~b2jmA?MD6OdzAHiACYnQ8W?D$bymqJcexsb4!!iPxw>An>ih`YZaUQ=R+NB`@p>_z#;az= z_S2KFi_zTJUC;43=jBUdXt@52E;6BljIO`Bn^la=)0TFogY_Ajr|~M3AO0!?f0dRM zjKfNxqo%BrTy1muy@Qz7>6P)b=^C?~Z?2lRf8bvV@ss28I|RNtp(&5j3;q4iG1Bok z;!dktBv#acPYF8QT)v)uIhH+>as89^YHzy-F`sHT$|2H85Yz}^*AoJM3SCOKTbUlX z+nw?uT2ZBc9r?X{?q)rGIZJdjgXlg1TOb+nWr@i#9pxLYmeesbKl^7VsmQ9)3k}44 z>i(RiJXGq@_0EIsBFq=5IR2wpQn#2}F9ieT#KP#95OLp>)GD@ zKarTFdgqQ})nwCzt3R+tDh_DV-iQ)vvX~bfv(4jJQnP}A=*KK@A`+A|fxuphE5b`@AOe$joL{)xZc8kVWxZj2eEyAicD3O(!qC;>MiVQ$_;uU4d#ics~lNC4IZAopgc~s zy&G73xT}=}$k6>$$}HTaFTWw@#fZ<}{!;smDD{>>PWY1n&GlPYQ)>#MNFs2ils4a} zpMIsmtPG;z;P0sVj-?<=dF=|@3U(l9S6>kGXfVD0DI6dSTP?-@1cKLW)0oHt4#%(% z#s1g8|EB&Uz{|?(&=G__I_oPXf~b%hw8lynaQ;r=6WHt8k0^JAU2Ru$PKgo!Gj?%VO2RrG@)KyF zTgyI8&NLcXKzNc&1c@LtxCQJoOYn~oN3@Ot!ACj2D=tirw2c@n`;}-XG)BC=x0vBq zHVvlpuI)A?RKqt}6W(>Zf(ULkt~FPOY(>}+5@~>ll|pW7PT!KzkY?7C?}WrSbx?y` zY6sW}j`dOMR0WVPbXNrT(Jh6pm{(^A5l~^`M`>0GG#QDBrZ@Ypw?F!)d7siO0|JQ< zk?E9yka2mXM=3)@5V&FA$N1`-&Fqp~wtb{Gy~Y{c(|-UX{f^Lt(g9%E_TXk*=>lZZ zLQc7+0ipMAc+rUtnebhq-qU|!Uqed!mjV$ITS>d-4<^t2|5C4g29sC)^zld85J>of zbf*a*Gez_YjiQ0bXA+X?d|7wj$#mU0)f7mFx#?PvK-%4-3HD?G1(t91OmZ4W`P^ zQ+z-n+;Le22~{HAa`2H)%%RdNUBI9;dhfLfV4%3G4Vc%rN`cSxVwRMm7Xpf1W4imn zQsaIwJIk8|1X&FqYyg4KZjL$-wU}IYoeT)OR!1Qcv)(F{0~s)G_Gy3*#WT{=ToB(l zZtjq!pT*Eu;1}oMhEz+y!D?3>h$OX89tF0ZBkaUE0AQ+}@h^aCRBrtnXfXcln#2ku zU!%#;SKx^wP)7rglus!q@gPw^5e>q;_)|Q9U3V`kRs+da|9l|yO&m0Bz#mJ~2V6j{ z;qyaOpeuh?7BE!`b}0@r;4URY2JSm6phbMSf&L)ed@>1 z2T-f7)l+~Bvh_w^koshvBw1jUdgLn#RQu(0Y5;%+7qk$d)}h5c@Mr)s+)}ziCxOH2LkK>uUo4)T0% z`BV+mH$@z>gQ(ARFfs~sGVyj*1Sp{=b9&%xooSXvA<%elM+j8rWDO03af)meu*no! z#Svmmtx`V70M4dg$v}eI`QPurzaLsy^nhxwn9lwJML)C|*+4My?s6eG)rVYwi!;lV z3j}khyhjxTQJhhR88~ffQPwUX&qkC5GSGQT#{h!9^EClr+I-L1CM3cM#1=siR|;2E zf<2at16^QfX`0c}ETG`=_O%6yP97_N2VU^-KX3%*x4-i(mXM|7J>1qG0AUj5v7--g z$X9$^AUH{>TfovIexnpyfQoY+0olx4y@IH9geo=zWa)Y8lR$uL26OirvNYTYWD#8K z*#irv2PqsOs`p)sLy!zNtcXDnqGgUu0vtZik}62ztR~JuQYGxJ^gB@c>RiYkh@Kwu zvj*qj?vd^WaO(TQsv)UDX|y;9C^62zLZIILMvhj1yNNY;IXO@AgQ$~rwEYikk#6kG zL2>}@U}+H$l$<9)pyNI9IY2&%z#EVR-hHVRkR-tELU{_JY3XQd7D55z*VF*i5Icq( z=Mh)zwlR?4NXqbB8!THeh5LoV#+C}=2Ux*tG+Bu9zQYCo7w|N{5WfE_4*3h7b-@LL zNu_gWWC4t^#4<9)Bp@<$sE;5!Nd@1~J@NyzQcTlw^Iju)bY3Al!ZdLji8NAEB&^GL zQ6vkBzL3})q!-?!>*Wu-=ySwQx*Y05IOEbx>w_7^Oo-0UE@E73;az=}XoQxFN2L}R zZz7J_*d-I^PF*JNz2NO4!1BV=o7rEo+ef_loe-!7-I-hXa$-7cq+Uok4GVe@J`*78 zAGc!5)$kU#(a^)-{TejO)|jnx6rC}?#Qp_=y0aaja(vk%`R{k$vPISxp7qSfK1UL4 zm52f&WTbVXhLz0$Puc^ss>`kfMGJnT>mX{%Nub5D;WDraS3k?F8D%Z5t6fD!Y>^=K zRmxFRf4^(*IWXb#X+pRF-(o<6O%oo}gN}^pg(f2de6QVCzE}1hI~(I``WRLo`tfvr zza%Z?_xOdnS#Y^Lt*bLG2L7WSJJc#021-0kKl$B*&$zHiqiVXIU)7GaE}9)D&>+xf-lY6WV`D_{NTm>2@f24a`x{O=(u$Ork|pc=L~6irCU-a!?L}US@Brdo%j#>2g&s^ z5a=f*)2+3_aL>ayVEYVM|7E8J(=cf@DQciBGpA3#hI8@xR(XojkJ^LS$fhxX!X6qt zmH+MN>XqF2ggVdQU}&(Ivc?*e;}ep$Xk2KRTsL6W=q@)sxmHKK_QbhEC=1V`vTy_s@7UMgbX$F;~tY=4FV;W5!Lz}R!s|2jqSDiHzVPa+c9wU&#kjt+> z#!Zg>0a^G&$Q0z%7#my6kz8W+S+9t`! z9`Zs0P3h|@DkORYEx(m=u~lSI;WskZXU*Vm<$+S-kb2Nz;;^q_`Jqwk)kS(o%gzdi zuXYOYfEM3ocZn|w1rCswKfKC{bdWEssEiUD_OHCPbqQ36tRr0jn=>SZ1g|}kt8*yr z^v(~-Vs3K`e^CPT&KC2(p2`Q1@>Ck^sI@uh$a(xyiB1`yTB-B-mUw`IB(|pJbFvf1 z@o%>8X$ap&^a_sX1dcbAiHP1pb0*cwyxqipj%2G(dFfgOq$GqBAVvzUrFN;hEF=jk zKuf6C6p)Hf6CA1IZjdui-W1djq*SyJ!nPv}%xtPPpHmvq8~+Ih*ZgQ5tm-kNZ>fg!YKV#cyqg^8yMNmR;%w5#wVpmnPAu zz4mvt`DyQ%!-?F^^ zJR}T`CPe&axrru+D!e&eh!!l(v<};uizs1HX)FT?Vt0hynyjV_Sl*C zPl-p%JEWiXTjb;W{7UeAh0H&73%)`&fxZ2%6_{Ho2XPkR?XV>@Z$Afd znBC*HEI40IzR$PlSFtwV&cs{UU-(8Z%W}G_XTcQ~DHBu3Jx^a|dXhfu_*0$>TAoa4 zltTR10{s9AZSsfQXOtoii7BuNo8X0rlI*8E3yeHQT5i6CpjqN1LW0}JTuDmLxln6{ zl3ElIxVgCjofFwZubJ!5^ld}*QZ^wOe-c6AD6vq!3NcqV9e3Qk^6M7Qpf*fdZel!F~z5ao~jn{ zqFRO-MCWUBg_TH;PMvyeu%JcjDq$E6^;}-dte<+R7ZsO-gjO0M4A%~N zLa37V{SD1~C)=hMu6NyC@E=iF%X6#YlTIi76MCi8M?YnnYoz0aL4Wzn?R2oHPlux#gu_ragolSm@swq*=w=xlb1n z!(yo`zUz~JT&|#Fi)E7Ub5$66HdTr-Qh~14waNiHJk{n`IW)j90U2IA3}Dr&tkK8O z8irUSEIQA|^JSudey8;liX_@GCJjl*dljfs%C@_W&%n zTFCnS&pEjGurIJjT-QYbe?rAgM2o z3?+k1P&LJ6N?rrKxVJE~-61%*ys1&55VmDRf_ASUkbkHdRkVPeEP}QEy<8Py8i+Qo zNuAvg(u~7VLlP38P)<4PTss6}Fzt;VALgIgb|juO?!wReCE@9|04WAlLG9-)C*i0+ zf(FAb{N$4K!!8xc*zK}Cqo5pb|u{^(8-GeUBhk)Qoqw8iw$D?+vqd-M}qyMT|#Ocvp8<)yr{4a|3`>OHMtls+! zCdP1|&7LHGE|st6S)QC|owiAWKGYUCu`tS<#ONG7ulbv4aY_bq-g^2+2-gQ^GWf=3 ztW3$w&aE3Mz8XdU;`YXRwkG_pq`F5af$_R*9)97cnJ6>#-TRuS)h=V$`nMu-eg^+u z(PN>>ew5-SwZNu|<%~!H^W3PGCShbAZ7Jqc#k3EsDwq<}OtZZ>QkZT?1ufK^m~JQl zIsO9c*9U)2R%(5#Dwwxz6cKxrc~&G zF{Q)^S3UM8?1uT0Buoi^?9WJt@jtipcQuQjnE_O6J1n9M$mD;}v}~UJcTxr8KE~?B zXF!|0pI1HGI50q=1cY{Ra?HGSCXiaH=KtQBi0H}l{ohb^f~ppiJ{Wxg zt%Q}*4Jc(G_#LHgFU%L-FPqTE{sm!}LDe@WZKG>qeF9{j6@%~L#E zvP0CigV|I3RD9kCI0NnY$q42B&>%tnnXen>6yDQ+k*$}A5o5Td)tc`1_{q(mR5Atf z&#^nyP2YcwENSb3x#ODp@e`jw)aT@%RgxqC6{r#mi)RI=!m9#E3Iqbm!~jAa6o;^_ zW`PN?)9$fTCDbLds31@-3nziU1U~5XJjo>If4}uHU0H(9+RUpIVh_mJUJf8&5$61^ z_Kt35Rn7`ys?w?by7c}%Z+hIoMUrWCMb-9-% zm@F(_Le5CnCHZ;20zgKcIo&u-sW8G5kDoMb8iotz2~!&O!mNT}QHA{T)C-0eF4c{D z2EUN&$0n6M{r!c-`8J@SkDn|Uk$-kvBFtWgy3AzHJu}-bXZRgEm4vWOq4N6czqRcw zZo94#48GmYk^f3{6V8G@h5%@+7FK`aAOQCrNS1az7bpMhCm@18OAS0zlG-Jq3+w6c zyZe!!F_IEvSfw5h!2}D?^!Rm3XhC-1)A^3UF<#E>dMJGbzS{a({;LRRc4w_E%qcwU=#?VBMPL{O#YecpSbWQTsMp>LR;p)RS?6ca@I*8!amnc&mDcB1;RqO zW$xEAr5;MyfD>pIwFBYxuDJi5DP$ydd6{1T;$7Tvu&nz7IgF>j!_P%?^-jQpfs;|L z2&Bibnl>BJ$^B%e+?*AHJY+n5T*nU&yw=soU}g=9sB`so#Hj_~dWjfHQM?1O$k9CSLAFos ze6yb*FwF4wafx^t9Jfz@-``kd=f@G^Ogac>i4KN14RP1q#~_qGG3 zMy)B}sR+T^*!2XDK`0PO1VXG2>}`n@1MWo|b-dYlMGp_G@Ui<02%Ek0mxjKrKY#@P z#Xay^>i*aJz$4DcRqvC7868yV`ty6eVOsu2xQKZ%M!h`xZ0#(Wnn~r9Fk1Dd4 zcB^;8Ks3|RW&zv+$doT_i{&2B4ve`Tr90FbG`-g)|6Zr!FqPE>LBH9Bc@&O*_2L1& zsW0uT1i3NrW>eSkBjMG(C6EO1S5AKL3Pma2qdquQ(hrn($z*X4o3hhLk8Fut@+I$? zQCQfIQDJa^gScyXKl(6hGRONJhXC=hQMu6L?#^_ID=?)W?~-pA#Y!_Ee=i@Ln&KjfHN7Wnj%ac#3$q`(w`RATWRMwAG2S z&VwTayxsBdg}-}R()U2=*ta11aJcBgT?qG-i}7bi50pmqeB1785Vi!qB@ZSYFjwyo zIDy!|LB9Qfar^|#8c3Gbf*#xhb2kcj97TMJt)(G(*hCoW553=HU%r@mP^00z+wMW8 zsJAcggF<4BRF4E=evhO+ly|}pup3=N_Ko|)GR~xb$cV7RqK8Cy$He{^r)}%-Hy!i9 zdlZ9wj|oR|;R`~gRBdqL8s#BoMAPbYAB>CL_)p40H$5gqYM(1fEjW46kFk%jrgpCU znAh-4kLj#+OaKYoNtH{|+w2FYl&o4kW+mHvB6tWwf`?@&{vljXJTV?bH^%*kYveiU z1ITc|_K^_#Hur&-QK$Q3U5imlj3Net(P4{UF7 z?{pu6Sgh?Y@552*d1gLR#$Y_!J9j?tsJ3*Y!~?$LR^6kSeb*lz@sqt~A0oV|V! zh4L#Wdr0xF>#;|Yusog-6Y%u$>(%jk2*Du_#Rv0zlg=Q4lrZH(Ce}g0einKJdDWc0Up7 zmAW&w9w(k z;wICsjSf(_`e9tOOI$4PN2pncf=1C?gt#51wcos>ol2t6a!^!#L0C#B5r|@DG~Gf- zGqgT7jd8`5!i{*%Ef}=o&6ifjHgI<{y`)20zD@x~n@fQ~lRe;PXV}+|keLvbzT2== zPXr0Ff}4SoY^P(|rf^Ov)^H4)!rz*c7}MQ-md^X(TGEU76yvHS@ndr>rR-fr`26^w zQ&i%yQtTj|y{>nD zedsHr^GUY#s-@{VDIBYsr6P-g^*U?iX1AK(qY-UwOAlNQ6et5^ZXR4w4k_|p71>BG zmU@b7Tjk>{8w0%AA$=4-&;xkIHkiM1Q*T+2{a5j|m|wM%aAep~8#XSaIrTUZ4V|2_ z3(_`dgkprfs8ZYE2@14$%ga9VLfJRhJ*_IBM%>uZq8P~G>-z*;4?ML673FrR|K6Pn zOSeQYi{RGD(1a^`_qSOLDeKHO!sa>?V;xq>&aYg~BOdF$x#ybvdwxntPiJCo=t(i? z>0~RF+j+X`_CtCe6#Ow53P)}R;N~06;t$_%Ja_b+Z~gfVABn#!6bk-Nw4! zRL-9v>7-8Z&$0kra}+chYiWCEc!*8ueR{icGoOTYi)9;H}7N(&aaV z4Ldq{=uN$lA5hKllroFC{!@Jjw{jCz#h>1KRZ9bI2I?fQJV#r1TCY6kR+lGS3B?#9 z5h{iX>}Qlo>~XJ=mkk=VUIY?eJZ;ZU_S@Hh+2@4Y*dJ1pZbA()Ae& zeJ2bl`HM8~K&}Yxkogy<5!OJrC?(^?AIzGx(ei-QkmiY`7_z@TClCw@1aCDr=bI)N$)ZkoO{M4&&Ryn=vmDMM;{EL_HrkiqN+xH!Jw%*d(Gy!C zo8SQV8}IT2^x;m%x*8^s!~bUVMJSVJzlvY~vs4@V)BHLKXIyZSLlmms!om2Y!l8Kq zmhP+6$L{=ls;wGM+FE(QClP_e+wcVP^`r)3YJdR&vT4i2s_QU%-=N z=9F)fm^Dt^$DkeHkVg@pwNK=QOPKtSD=Q&rnV5-2+hCfo2#?g{bHVcp=68X-Al#@0 zFH=FrQ!c(#qec8XX+t9I+EY!ic}zhG!-f;5-@)}U`L3 zO{W;IS5vxWJsiLi_?)5ZT3kNXO=Ot%ZAuhXu-w6 zjo62cbLn0f`tGc?+nB($GpQ!_LK!l__lN7g;EI5Jcybm_tcO14ABo`l<#v}*`1#_LC<(p??iFpm1N4GTvH^1Kz?VgCb<7W!EDxIn;(?`#PrnbQeeRD#HFMfArk(0%lj_M@3j} zrL69LMOWU04CfjbMbHGn+~$SIl*NP`$_xdStY`uGk9fVeNJF<~*a0xQ!%Hc|Hv)?x z&=I(pP5Dm@<*aBpUUnGcs(#Zve-(%(O;3|pd|dM9b#fE;=j%ME4R$m}KWp&|#RI-R z#}p4j`XlVG3f>~4Y}Jb1YbT6HW113T)xA?T1PZ)3=Jny^R0lUG8N~?$$c!_^{s{w| z4Mhn|iph4G$rYw!nJFnYTNPV3#lgjTCId2s7%v6N@!LMZlyfDw7LO^PlY2wiB(QN5 z4O(wwk!)FgPohUo3w?D;+F$$Hrc1s!r~NoCg_KUE!_ppSb+ zn2_{BuNy9-q|z%CWv}7-Ag8qW$RlS4P9}Qui25KL_VQV4X>p#R@Mc02cZZ4c2fF1O)&par-We^4o=wz7luBTJyj ztEnyfDWCDZ^#=yy?xjCuC@vdUHgLojnIwHm(*MOV!*Q_?jqwsWpZQXTcHV-(M=f8S zIV=8~E=ia=g^aQGH)iL^8hm~pGuoL33v0#QQ3njhJvZCS8F6*dbk*B%^y^Jcp$!AK zUOpJrM(aG`Jk`zRRE(6qO71d?QG=w4N~N?ujamJVys1U)x`TU8S{-J4Qera^-=J|c zcxW#PqkqQb&qd7M3@TJ`aE!EuN)0^QV%zd``!eG8Wg{RWg^zYN#;f$bdo|926@xC` zhu0dCUsPudJW4aR{WD%07=L+-79lKGkr-Qnvyw~5H8R*NB}9U~C!5i@IkqQduq$PB zm-X)l9DhuX(pi7;I+1+J(olPqo#J5I~y_{(RxeO27~jpsGUvCu}?`~0mTuraIg zS9klFANOaHe+Jvf%nRzgy<70RyE(tRy?Q2e)e~Zfh;jqJr0=C8f`=FFEo zZDP{!8aKa}+jcJ*f5?Zd>b~42)NKbJjru&?1RwGv5ygN2cQ(eci757S&J1Lv=-NgP zwzQcJe~Nfh>=Y6uZ{CIUdU3Vr(1%!`ebUVQ1`U?INf#@i&}1xAArBL-$b@c?TWzqD zwi|xVZa%7PzipQt=MKZ+(n*H4J#2?Oc8UUhB-g}(az z{k$VQRAWe^pk~kdX9!(G65n;uU#zk(FiRI#@#OUla z9#qB|6+5i0CK(lV`&698iEh=BwA%Tx35dmNyOo;5jf00yi|;driO2_ap7R5k7NOP8 z7o|pKpIQVve1n|fcW}MP)=(#z;Gbe4f`uAmi*bf2GaX^E8mkNv02F1z2EBbhp&AJA zT{m+7v`Au2l!O!)_yz(5_l9Sj!ZI4ZIit;C?=WQ zYL7odNOf_&*`ffaRpeFLXWIGNBoINx8Q6euQUbzeM_o4@V+VImdJg=Kgy~eESqs6U zdT3aXa&ZoOeYV3NU~U4%5F^Nm1eX=R=EkzdIy&)3NJ*k>1%Us{p~HRYDI9mqe`rG_*9ta<`2~YI1r+l| zf;vHrNUVLz{+b5_+29iAm!cBOS`G7C70AIyyM(?sALduj9sKM(_)>*hd~F+=JLc*C z^|I6W3NN3^mHT7)gZ^Qf=uRk$!zrZ8TM~+qt>D1u>4h!kDW)13m z#?Or|5=%%*97ZmOiXJVgLJJ?(dGQ1oMM}Jd6nwwGSP{}2t>H6gqvZB)q~<|h>MdrfLs_FuT& zzRY$e_HzVCC&8W8pBT7btO*0i781};?DeNku_v!Tl?MwzNu{>ryKZ4b2h9_Z5Qj~I zlQV9G3+mKyafR^}c;hibCQit{JjE@`NR0Dr+npDKy>%pl$dlGVFPQG_8v*>$SXN|X zS5Zpio%%VIYr7}ul4e%Zj9J-!LzhZR@gL8%ec@J_SKA1y!38tlHMWuYOz6jRxHE@9 zN331D6C?SV&{y7c8%vBN4zCWAlQ5{?!u?Ye$$-zE{yR{__k4Arf|#GjAv>W8H{Jyn zXO8NKIn9IMeO9leU=@1aLGu@yX;Pg)SL!=ZcL>Jq}wJVA-pF`y`>|^Q(_1(Dgc#28R+qPXpb%pXOuMZM#28 z@(H4vqcqYc$sV0SRoat~;uy6YtU3BX&%9V;@4t@X{d@Fza7;BL-!mhpZvrERX`78LQloJtT$2!NDGO0CmT&sL z0=#YTNYP>--jCK*o>>9Hp&|_0tBBEHNu!(vSmdQ!v*m&-tIGj*+zRxCr!%FfuBvA+ zAw&ePQkdAHS^iXZ_7SHt_1R+a%h}Wa{mUnbO+_5Ls)th)G3g+ z|LGTdSQwv>FFcb|G^xuXdydbdU$ zDZZ(EZr{t3aB4yM;*6w1n117X4R)_Sx}bLLb0jsbkUyT9XL_ou z>&-GDP5j%;G#MN|*75?_rn< zNw%BU*6OaSM${dOkp%EX2*M<%ZPWv$l9GwPM7yda72lK+&-QZb)R`b2B$QTTL$#ck zCK_v+hg%!tMkEHAB<#gAwIjUT(&&wFf;{KHx5j+b39(_F*N`fjmgtNQ_fofFY>Yc- zj3aE6o)5QDIoDSXbry*!nyBe0Lp=hmgR$;Dt*-2s`?X5F%!JP^ALU=?^OcH9Y8mHN z_n<6NGc|K)93-n0d<}%Mq%5=&CPUFDz zqDS6w!4kgF(KTwO1pDKV?t{pEb~sbpUNe2mjalYw@vnd>L&UW@#{v-pj!6AZHE#5Z zqbeUHJDmmXr4Kt{ySL?Wr-@9a_C{41!^zuMoXhwuyfL;$4&DUBhJiL7=sh*8w~j4u zlkZj2nsRaw-QDJ;jj+tYBRg|YN8+>04db3yr{|*Y40Ez?+Gu#>lt(s)Nx0a?GJegLiF)wQb_{aC#NHIY;r1(~~8OJevwRW{tr?Imx z*y^G|t4fv=fGKrVrpYLYW4E!$(Y!)K|CTt~R6C%}SPSP9epbe4o1%`omc8urqmO?T zmn{M9?2vv#VZIilvyn7%WO)^H1SaPp^<{vw)hz4a&?ODDFkNYlD5~EVS;`6! zHE7eg7vEqJ^)!MTUY)5d*%dKJ@&2hqjRKW97H&WH?Yx+lVOcXBw3J|7xT#Z;&9E({ zoTKDc{M7!4mT-X(R42DV;+7Kw(pT{PBQUhm^e

i%6GlZ%+?l62T5m7WSFcwFUi0 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≫sp&pf!U9wh^cDuZGj1jpSy8w7FGH=z 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 + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + lib/ + netneutrality.MusicBot + + + + + + From 598ca5217c598a7d3bac0c49e4ac8838ad848a49 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sat, 18 Sep 2021 16:27:42 -0400 Subject: [PATCH 027/155] Add build step to build jar with dependencies --- pom.xml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pom.xml b/pom.xml index 6a0e4ef..7445ab5 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,32 @@ + + + maven-assembly-plugin + 3.0.0 + + + + netneutrality.MusicBot + true + true + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + From a3eb2d4400a62be9bcfd96491cd4e314bc9782fb Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 19 Sep 2021 15:23:34 -0400 Subject: [PATCH 028/155] Update CI config --- .gitlab-ci.yml | 7 +++++-- pom.xml | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7edde83..61731dd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: maven:latest +image: maven:3-jdk-11 variables: MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode" @@ -12,7 +12,10 @@ cache: build: stage: build script: - - "mvn --batch-mode compile" + - "mvn --batch-mode package" + artifacts: + paths: + - target/netneutrality-jar-with-dependencies.jar test: stage: test diff --git a/pom.xml b/pom.xml index 7445ab5..99ea899 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ maven-assembly-plugin - 3.0.0 + 3.3.0 @@ -51,6 +51,7 @@ jar-with-dependencies + netneutrality From df731d467b1e5486aa401212c4737d18d8cc96af Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 00:41:28 -0400 Subject: [PATCH 029/155] Modified settings class --- src/main/java/netneutrality/db/DBController.java | 3 ++- src/main/java/netneutrality/utils/Settings.java | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 7217f7f..6be429e 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; import netneutrality.MusicBot; import netneutrality.ThreadManager; +import netneutrality.utils.Settings; import org.jetbrains.annotations.NotNull; import org.reflections.Reflections; import org.slf4j.Logger; @@ -26,7 +27,7 @@ public class DBController { private final static HashMap controllers = new HashMap<>(); private final static Logger logger = LoggerFactory.getLogger(DBController.class); - private static final MysqlDatabase database = new MysqlDatabase("netneutrality"); + private static final MysqlDatabase database = new MysqlDatabase(Settings.getInstance().get("mysql.database", "netneutrality")); /** * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 68c6c30..61cbc10 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -4,8 +4,6 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.User; import netneutrality.MusicBot; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBSettings; import java.io.*; import java.util.Properties; @@ -38,7 +36,15 @@ public class Settings { public String get(String key) { return prop.getProperty(key); + } + public String get(String key, String def) { + String property = prop.getProperty(key); + + if (property == null) + return def; + + return property; } public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; From da82ed94911aa466bc64b9a7f981b40e26b8a14a Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 01:40:16 -0400 Subject: [PATCH 030/155] Reverted to MySQL connector for ease of use --- .gitlab-ci.yml | 22 ++++++++++++++----- pom.xml | 8 +++---- .../java/netneutrality/db/MysqlConnector.java | 9 ++++---- .../java/netneutrality/db/MysqlDatabase.java | 20 ++++++----------- src/main/resources/log4j2.xml | 4 ++-- 5 files changed, 34 insertions(+), 29 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61731dd..e0c71e7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,15 +9,25 @@ cache: - .m2/repository/ - target/ -build: - stage: build +stages: + - compile + - test + - package + +compile: + stage: compile script: - - "mvn --batch-mode package" - artifacts: - paths: - - target/netneutrality-jar-with-dependencies.jar + - "mvn --batch-mode compile" test: stage: test script: - "mvn --batch-mode test" + +package: + stage: package + script: + - "mvn --batch-mode package" + artifacts: + paths: + - target/netneutrality-jar-with-dependencies.jar \ No newline at end of file diff --git a/pom.xml b/pom.xml index 99ea899..ead73f4 100644 --- a/pom.xml +++ b/pom.xml @@ -108,9 +108,9 @@ - org.mariadb.jdbc - mariadb-java-client - 2.7.4 + mysql + mysql-connector-java + 8.0.26 org.apache.logging.log4j @@ -130,7 +130,7 @@ commons-logging commons-logging - 1.1.1 + 1.2 diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index b892f41..1f6034a 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -1,7 +1,6 @@ package netneutrality.db; - -import org.mariadb.jdbc.MariaDbPoolDataSource; +import com.mysql.cj.jdbc.MysqlDataSource; import java.sql.Connection; import java.sql.SQLException; @@ -27,14 +26,16 @@ public class MysqlConnector { * @return {@link MysqlConnector} */ public MysqlConnector connect() throws SQLException { - - MariaDbPoolDataSource dataSource = new MariaDbPoolDataSource(); + MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setUser(dbUser); dataSource.setPassword(dbPass); dataSource.setServerName(dbHost); dataSource.setPort(3306); dataSource.setDatabaseName(dbName); + dataSource.setAutoReconnect(true); + dataSource.setAutoReconnectForPools(true); c = dataSource.getConnection(); + return this; } diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 39a8484..bb0f00a 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -8,9 +8,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.sql.Types; -import java.util.ArrayList; import java.util.Calendar; -import java.util.List; import netneutrality.MusicBot; import netneutrality.db.entities.EntityInterface; @@ -24,13 +22,13 @@ import org.slf4j.LoggerFactory; public class MysqlDatabase { private final static Logger logger = LoggerFactory.getLogger(MysqlDatabase.class); - private Connection connection; + protected Connection connection; private final String dbName; protected enum CommandType { SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"); - private String type; + private final String type; CommandType(String type) { this.type = type; @@ -49,10 +47,10 @@ public class MysqlDatabase { String dbHost = Settings.getInstance().get("mysql.host"); try { - logger.info("Connecting to database..."); + logger.info(String.format("Connecting to database '%1$s' at %2$s:3306", dbName, dbHost)); connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); } catch (SQLException e) { - logger.error("Error connecting to database. Shutting down.."); + logger.error("Error connecting to database. Shutting down..", e); MusicBot.shutdown(); } } @@ -114,13 +112,9 @@ public class MysqlDatabase { return executeUpdate(sql, params); } - public synchronized boolean exists(String table, String key, String value) { - ResultSet rs = prepareAndExecute("SELECT 1 FROM " + table + " WHERE " + key + " = ?", value); - try { - return rs.next(); - } catch (SQLException e) { - return false; - } + public boolean exists(String table, String key, String value) { + return prepareAndExecuteAsync("SELECT 1 FROM " + table + " WHERE " + key + " = ?", value).blocking().isEmpty(); + } private synchronized int executeUpdate(String sql, Object[] params) { diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 9bc2e7f..c27bace 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -2,11 +2,11 @@ - + - + From 8f5c6b8cd5b4aeb18ea6ecb74b23f4ba8e62d375 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 11:39:21 -0400 Subject: [PATCH 031/155] Modified settings class --- .gitignore | 3 +++ bot.config.example | 11 +++++++++++ src/main/java/netneutrality/db/MysqlConnector.java | 2 +- src/main/java/netneutrality/db/MysqlDatabase.java | 6 +++--- src/main/java/netneutrality/utils/Settings.java | 10 ++++++---- src/main/resources/bot.config | 5 ----- 6 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 bot.config.example delete mode 100644 src/main/resources/bot.config diff --git a/.gitignore b/.gitignore index d8fc794..6d10652 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ # BlueJ files *.ctxt +# Config file +bot.config + # Mobile Tools for Java (J2ME) .mtj.tmp/ diff --git a/bot.config.example b/bot.config.example new file mode 100644 index 0000000..76fa6b1 --- /dev/null +++ b/bot.config.example @@ -0,0 +1,11 @@ +bot.token= +bot.prefix= +bot.owner= +bot.ownerguild= +bot.errorchannel= + +mysql.host=localhost +mysql.user=root +mysql.password= +mysql.database= +mysql.port=3306 \ No newline at end of file diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index 1f6034a..9a33dc2 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -33,7 +33,7 @@ public class MysqlConnector { dataSource.setPort(3306); dataSource.setDatabaseName(dbName); dataSource.setAutoReconnect(true); - dataSource.setAutoReconnectForPools(true); + dataSource.setConnectTimeout(5000); c = dataSource.getConnection(); return this; diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index bb0f00a..6f1f67c 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -42,9 +42,9 @@ public class MysqlDatabase { protected MysqlDatabase(String dbName) { this.dbName = dbName; - String dbUser = Settings.getInstance().get("mysql.user"); - String dbPass = Settings.getInstance().get("mysql.password"); - String dbHost = Settings.getInstance().get("mysql.host"); + String dbUser = Settings.getInstance().get("mysql.user", "root"); + String dbPass = Settings.getInstance().get("mysql.password", ""); + String dbHost = Settings.getInstance().get("mysql.host", "localhost"); try { logger.info(String.format("Connecting to database '%1$s' at %2$s:3306", dbName, dbHost)); diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 61cbc10..3f1b730 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -14,12 +14,14 @@ public class Settings { private final Properties prop = new Properties(); public Settings() { - String configFile = "bot.config"; + File file = new File("bot.config"); try { - InputStream is = Settings.class.getClassLoader().getResourceAsStream(configFile); - prop.load(is); - is.close(); + file.createNewFile(); + + FileInputStream fis = new FileInputStream(file); + prop.load(fis); + fis.close(); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/resources/bot.config b/src/main/resources/bot.config deleted file mode 100644 index 2d0eb74..0000000 --- a/src/main/resources/bot.config +++ /dev/null @@ -1,5 +0,0 @@ -bot.token= -bot.prefix=$ -bot.owner= -bot.ownerguild= -bot.errorchannel= \ No newline at end of file From 8652c72cfac0439eaccb67c45235ce5181724a57 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 12:18:49 -0400 Subject: [PATCH 032/155] Temporary shutdown http endpoint --- src/main/java/netneutrality/MusicBot.java | 5 +-- .../http/server/ActionHandler.java | 35 +++++++++++++++++++ .../netneutrality/http/server/WebApi.java | 15 +++++--- 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 src/main/java/netneutrality/http/server/ActionHandler.java diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index a2d0318..db95900 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -25,6 +25,7 @@ public class MusicBot { public static void main(String[] args) { System.setProperty("log4j.skipJansi", "false"); + DBController.init(); try { @@ -41,7 +42,7 @@ public class MusicBot { jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new NewCommandListener(), new EditHandler()); - // WebApi webserver = new WebApi(); + WebApi webserver = new WebApi(); jda.getPresence().setActivity(Activity.watching("you")); @@ -71,7 +72,7 @@ public class MusicBot { return jda; } - public static void disconnect() { + private static void disconnect() { if (jda != null) { jda.shutdownNow(); } diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java new file mode 100644 index 0000000..c410479 --- /dev/null +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -0,0 +1,35 @@ +package netneutrality.http.server;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import netneutrality.MusicBot; +import org.apache.logging.log4j.LogManager; + +import java.io.IOException; +import java.io.OutputStream; + +public class ActionHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + String path = exchange.getRequestURI().getRawPath(); + + if (path.equals("/actions/shutdown")) { + LogManager.getLogger().info("Request to shutdown received"); + exchange.sendResponseHeaders(200, "Shutting down..".length()); + OutputStream os = exchange.getResponseBody(); + os.write("Shutting down..".getBytes()); + os.close(); + MusicBot.shutdown(); + } + + exchange.sendResponseHeaders(200, path.length()); + OutputStream os = exchange.getResponseBody(); + os.write(path.getBytes()); + os.close(); + } +} diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index a31130b..118f198 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -7,31 +7,38 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpServer; +import netneutrality.ThreadManager; +import netneutrality.thread.BaseThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class WebApi { private final static Logger logger = LoggerFactory.getLogger(WebApi.class); + private final ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThread("web-api")); - private int port = 9000; + private final int port = 9000; private HttpServer server; public WebApi() { logger.debug("Starting web server..."); try { - server = HttpServer.create(new InetSocketAddress(port), 0); + server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost(), port), 0); } catch (IOException e) { e.printStackTrace(); } server.createContext("/", new RootHandler()); + server.createContext("/actions", new ActionHandler()); server.createContext("/guild", new GuildBrowser()); - server.setExecutor(null); + server.setExecutor(executor); server.start(); - logger.debug("Web server started at [" + server.getAddress().getAddress().toString() + "]"); + logger.info("Web server started at [" + server.getAddress() + "]"); } From 7291ffc0a1c9c04647bcbea322d47e0ea0bfd06a Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 12:36:31 -0400 Subject: [PATCH 033/155] Fix http class --- src/main/java/netneutrality/http/server/WebApi.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 118f198..002cdc1 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -27,9 +27,11 @@ public class WebApi { private HttpServer server; public WebApi() { - logger.debug("Starting web server..."); + logger.info("Starting web server..."); try { - server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost(), port), 0); + InetAddress localHost = InetAddress.getLoopbackAddress(); + InetSocketAddress sockAddr = new InetSocketAddress(localHost, port); + server = HttpServer.create(sockAddr, 0); } catch (IOException e) { e.printStackTrace(); } From 62fe015ffabfbc75e6f3262595341051052e444b Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 13:43:11 -0400 Subject: [PATCH 034/155] debug --- pom.xml | 4 +-- .../http/server/ActionHandler.java | 29 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index ead73f4..3a94aaf 100644 --- a/pom.xml +++ b/pom.xml @@ -67,9 +67,9 @@ - + central - https://repo1.maven.org/maven2/ + https://repo.maven.apache.org/maven2 diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index c410479..83daaec 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -15,21 +15,28 @@ import java.io.OutputStream; public class ActionHandler implements HttpHandler { @Override - public void handle(HttpExchange exchange) throws IOException { - String path = exchange.getRequestURI().getRawPath(); + public void handle(HttpExchange exchange) { - if (path.equals("/actions/shutdown")) { - LogManager.getLogger().info("Request to shutdown received"); - exchange.sendResponseHeaders(200, "Shutting down..".length()); + try { + String path = exchange.getRequestURI().getRawPath(); + + if (path.equals("/actions/shutdown")) { + LogManager.getLogger().info("Request to shutdown received"); + exchange.sendResponseHeaders(200, "Shutting down..".length()); + OutputStream os = exchange.getResponseBody(); + os.write("Shutting down..".getBytes()); + os.close(); + //MusicBot.shutdown(); + return; + } + + exchange.sendResponseHeaders(200, path.length()); OutputStream os = exchange.getResponseBody(); - os.write("Shutting down..".getBytes()); + os.write(path.getBytes()); os.close(); - MusicBot.shutdown(); + } catch (Exception ex) { + ex.printStackTrace(); } - exchange.sendResponseHeaders(200, path.length()); - OutputStream os = exchange.getResponseBody(); - os.write(path.getBytes()); - os.close(); } } From c11af0da512339771e9169dd702c397250d30c7f Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 21 Sep 2021 14:03:50 -0400 Subject: [PATCH 035/155] Updated threadmanager and refactored code --- src/main/java/netneutrality/MusicBot.java | 2 +- .../java/netneutrality/ThreadManager.java | 96 ++++++++++++------- .../netneutrality/db/AsyncMySqlAction.java | 22 ++--- .../java/netneutrality/db/DBController.java | 3 +- .../db/controllers/DBBlacklist.java | 3 +- .../db/controllers/DBLogging.java | 5 +- .../netneutrality/handler/ConsoleHandler.java | 2 + .../http/server/ActionHandler.java | 28 ++---- .../netneutrality/http/server/WebApi.java | 10 +- .../netneutrality/music/MusicManager.java | 8 +- .../netneutrality/utils/ChannelFunction.java | 2 +- 11 files changed, 103 insertions(+), 78 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index db95900..c1559d2 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -42,7 +42,7 @@ public class MusicBot { jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new NewCommandListener(), new EditHandler()); - WebApi webserver = new WebApi(); + new WebApi(); jda.getPresence().setActivity(Activity.watching("you")); diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 1c24f4b..7fb860a 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -1,68 +1,92 @@ package netneutrality; -/* - * Copyright (c) anthorob - * - * This file is closed-source. It should not be distributed or copied in any way or form - */ - import netneutrality.thread.BaseThread; -import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.Map; +import java.util.concurrent.*; public class ThreadManager { - private static ThreadManager INSTANCE; + public enum ExecutorType { + SINGLE, SCHEDULED, FIXED + } + + private static final Map executors = new ConcurrentHashMap<>(); private final static Logger logger = LoggerFactory.getLogger(ThreadManager.class); - public static final ExecutorService executor = Executors.newSingleThreadExecutor(new BaseThread("executor")); - public static final ExecutorService dBExecutor = Executors.newSingleThreadExecutor(new BaseThread("db-action")); - public static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5, new BaseThread("scheduled-action")); - - public ThreadManager() { + public static ExecutorService getExecutor(String name) { + return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); } - public static ThreadManager getInstance() { - if(INSTANCE == null) { - INSTANCE = new ThreadManager(); + public static ExecutorService getExecutor(String name, ExecutorType type) { + ExecutorService executor; + + switch (type) { + case FIXED: + executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(5, new BaseThread(name))); + break; + case SCHEDULED: + executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(5, new BaseThread(name))); + break; + default: + executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); } - return INSTANCE; + return executor; + } + + public static ExecutorService getExecutor(String name, ExecutorType type, Integer poolSize) { + ExecutorService executor; + + switch (type) { + case FIXED: + executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(poolSize, new BaseThread(name))); + break; + case SCHEDULED: + executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(poolSize, new BaseThread(name))); + break; + default: + executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); + } + + return executor; + } + + + public static Future dispatch(ExecutorService executor, Runnable task) { + return executor.submit(task); + } + + public static Future dispatch(ExecutorService executor, Callable task) { + return executor.submit(task); } public static void shutdownExecutor() { - logger.info("[Executor] Shutting down..."); + logger.debug("[Executor] Shutting down..."); try { - executor.shutdown(); - scheduler.shutdown(); - executor.awaitTermination(5, TimeUnit.SECONDS); - scheduler.awaitTermination(5, TimeUnit.SECONDS); + for (ExecutorService ex : executors.values()) { + ex.shutdown(); + ex.awaitTermination(5, TimeUnit.SECONDS); + } } catch (InterruptedException e) { logger.warn("[Executor] Running tasks interrupted"); } finally { - if (!executor.isTerminated()) { - logger.warn("[Executor] Forcing shutdown of running tasks.."); - executor.shutdownNow(); - } - - if (!scheduler.isTerminated()) { - logger.warn("[Executor] Forcing shutdown of running tasks.."); - scheduler.shutdownNow(); - } + executors.forEach((name, ex) -> { + if (!ex.isTerminated()) { + logger.warn("[Executor: " + name + "] Forcing shutdown of running tasks.."); + ex.shutdownNow(); + } + }); } - logger.info("[Executor] Shutdown finished!"); + logger.debug("[Executor] Shutdown finished!"); } diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java index 63b0d99..2e84098 100644 --- a/src/main/java/netneutrality/db/AsyncMySqlAction.java +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -8,17 +8,15 @@ package netneutrality.db; */ import netneutrality.ThreadManager; -import netneutrality.db.entities.EntityInterface; import netneutrality.db.models.MTableModel; import java.sql.ResultSet; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.*; import java.util.function.Consumer; public class AsyncMySqlAction { + private final ExecutorService executor = ThreadManager.getExecutor("db-action", ThreadManager.ExecutorType.SINGLE); private final String sqlString; private final Object[] params; private final MysqlDatabase.CommandType type; @@ -39,24 +37,24 @@ public class AsyncMySqlAction { public void async(Consumer success) { switch (type) { case INSERT: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { db.insert(this.sqlString, this.params); }); break; case UPDATE: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { db.update(this.sqlString, this.params); }); break; case DELETE: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { db.delete(this.sqlString, this.params); }); break; case SELECT: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { ResultSet result = db.prepareAndExecute(this.sqlString, this.params); MTableModel table = MysqlDatabase.convertToTableModel(result); @@ -70,17 +68,17 @@ public class AsyncMySqlAction { try { switch (type) { case INSERT: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { db.insert(this.sqlString, this.params); }).get(); case UPDATE: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { db.update(this.sqlString, this.params); }).get(); case DELETE: - ThreadManager.dBExecutor.submit(() -> { + ThreadManager.dispatch(executor, () -> { db.delete(this.sqlString, this.params); }).get(); @@ -92,7 +90,7 @@ public class AsyncMySqlAction { return table; }; - Future future = ThreadManager.dBExecutor.submit(task); + Future future = ThreadManager.dispatch(executor, task); return future.get(); } } catch (InterruptedException | ExecutionException e) { diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 6be429e..e572608 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -5,6 +5,7 @@ import java.lang.reflect.Modifier; import java.sql.SQLException; import java.util.HashMap; import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import netneutrality.MusicBot; @@ -70,7 +71,7 @@ public class DBController { if (controllers.isEmpty()) loadControllers(); - ThreadManager.scheduler.scheduleWithFixedDelay(() -> { + ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { DBController.get().query("SELECT 1;"); }, 0, 120, TimeUnit.SECONDS); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index f2b9370..352f85d 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -80,7 +80,8 @@ public class DBBlacklist extends AbstractController { @Deprecated public void getBlacklistForWord(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { + + ThreadManager.getExecutor("db-action").submit(() -> { MBlacklist blacklisted = null; if (isAlreadyBlacklisted(word, serverId)) { diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java index efc4c15..41805f4 100644 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ b/src/main/java/netneutrality/db/controllers/DBLogging.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; public class DBLogging extends AbstractController { public void logGuild(Guild g) { - ThreadManager.executor.submit(() -> { + ThreadManager.getExecutor("db-action").submit(() -> { if (!database.exists("guilds", "guild_id", g.getId())) { database.insert("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), g.getName(), g.getOwner().getUser().getName()); } @@ -30,7 +30,8 @@ public class DBLogging extends AbstractController { } public void getLoggingChannel(String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { + + ThreadManager.getExecutor("db-action").submit(() -> { TextChannel txt = null; ResultSet rs = database.prepareAndExecute("SELECT channelId FROM logging WHERE serverId = ?", serverId); diff --git a/src/main/java/netneutrality/handler/ConsoleHandler.java b/src/main/java/netneutrality/handler/ConsoleHandler.java index 3988453..6a489e0 100644 --- a/src/main/java/netneutrality/handler/ConsoleHandler.java +++ b/src/main/java/netneutrality/handler/ConsoleHandler.java @@ -7,8 +7,10 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +//TODO: To be replaced by HTTP API actions public class ConsoleHandler { + private final static Logger logger = LoggerFactory.getLogger(ConsoleHandler.class); public ConsoleHandler() { logger.info("Console input ready!"); diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 83daaec..c36f4dc 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -15,28 +15,18 @@ import java.io.OutputStream; public class ActionHandler implements HttpHandler { @Override - public void handle(HttpExchange exchange) { + public void handle(HttpExchange exchange) throws IOException { - try { - String path = exchange.getRequestURI().getRawPath(); + String path = exchange.getRequestURI().getRawPath(); - if (path.equals("/actions/shutdown")) { - LogManager.getLogger().info("Request to shutdown received"); - exchange.sendResponseHeaders(200, "Shutting down..".length()); - OutputStream os = exchange.getResponseBody(); - os.write("Shutting down..".getBytes()); - os.close(); - //MusicBot.shutdown(); - return; - } - - exchange.sendResponseHeaders(200, path.length()); - OutputStream os = exchange.getResponseBody(); - os.write(path.getBytes()); - os.close(); - } catch (Exception ex) { - ex.printStackTrace(); + if (path.equals("/actions/shutdown")) { + LogManager.getLogger(MusicBot.class).info("Request to shutdown received"); + WebApi.sendStringResponse(exchange, "Shutting down.."); + MusicBot.shutdown(); + return; } + WebApi.sendStringResponse(exchange, path); + } } diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 002cdc1..dd1f128 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -6,13 +6,14 @@ package netneutrality.http.server; * This file is closed-source. It should not be distributed or copied in any way or form */ +import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; -import netneutrality.ThreadManager; import netneutrality.thread.BaseThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; @@ -44,6 +45,13 @@ public class WebApi { } + public static void sendStringResponse(HttpExchange exchange, String str) throws IOException { + exchange.sendResponseHeaders(200, str.length()); + OutputStream os = exchange.getResponseBody(); + os.write(str.getBytes()); + os.close(); + } + } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index a497fb9..4e70f3f 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -26,6 +26,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class MusicManager { @@ -35,12 +36,11 @@ public class MusicManager { private final AudioPlayer player; private final TrackScheduler scheduler; private final static Map managers = new ConcurrentHashMap<>(); - private final long guildId; - private String topic; + private final String guildId; private MusicManager(Guild guild) { - this.guildId = guild.getIdLong(); + this.guildId = guild.getId(); player = playerManager.createPlayer(); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); scheduler = new TrackScheduler(player); @@ -70,7 +70,7 @@ public class MusicManager { Guild guild = MusicBot.getJDA().getGuildById(guildId); guild.getAudioManager().openAudioConnection(vChannel); - ThreadManager.scheduler.scheduleWithFixedDelay(() -> { + ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { if ((getCurrentlyPlaying() == null && scheduler.queue.isEmpty()) || vChannel.getMembers().size() == 0) leave(); }, 120, 120, TimeUnit.SECONDS); diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index e8300d0..27b7e7f 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -17,7 +17,7 @@ public class ChannelFunction { if (toDelete >= 2500) return; - ThreadManager.executor.submit(() -> { + ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED, 5).submit(() -> { int toDeleteFinal = toDelete + 1; int iteration = toDeleteFinal / 100; From 1b24a55ca65c538f825a50beb45d346aa6b25a59 Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 29 Sep 2021 20:09:36 -0400 Subject: [PATCH 036/155] Refactored commands and optimized music manager --- src/main/java/netneutrality/MusicBot.java | 2 +- .../command/AbstractCommand.java | 10 +-- .../netneutrality/command/CommandManager.java | 1 - .../java/netneutrality/command/ICommand.java | 16 +++++ .../command/crypto/BitcoinPriceCommand.java | 4 +- .../command/crypto/EthereumPriceCommand.java | 4 +- .../command/crypto/LitecoinPriceCommand.java | 4 +- .../command/music/StopCommand.java | 1 - .../command/specific/DatabaseCommand.java | 1 + .../music/AudioPlayerSendHandler.java | 14 +--- .../music/LoadResultHandler.java | 36 +++++++++- .../netneutrality/music/MusicManager.java | 68 +++---------------- .../netneutrality/utils/ChannelFunction.java | 2 +- .../netneutrality/utils/MessageFunction.java | 21 +++++- 14 files changed, 91 insertions(+), 93 deletions(-) create mode 100644 src/main/java/netneutrality/command/ICommand.java diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index c1559d2..8c3c02b 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -21,7 +21,7 @@ import javax.security.auth.login.LoginException; public class MusicBot { private static JDA jda; - private final static Logger logger = LoggerFactory.getLogger(MusicBot.class); + public final static Logger logger = LoggerFactory.getLogger(MusicBot.class); public static void main(String[] args) { System.setProperty("log4j.skipJansi", "false"); diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 4395888..6e048da 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -3,9 +3,7 @@ package netneutrality.command; import java.util.Arrays; import java.util.List; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; - -public abstract class AbstractCommand { +public abstract class AbstractCommand implements ICommand { public AbstractCommand() { @@ -41,12 +39,6 @@ public abstract class AbstractCommand { public abstract CommandType getType(); - /** - * @param args the arguments to the command - */ - public abstract String execute(MessageReceivedEvent event, String args); - - public int countArgs(String command) { if (command.isEmpty()) diff --git a/src/main/java/netneutrality/command/CommandManager.java b/src/main/java/netneutrality/command/CommandManager.java index d351f50..bf683bd 100644 --- a/src/main/java/netneutrality/command/CommandManager.java +++ b/src/main/java/netneutrality/command/CommandManager.java @@ -7,7 +7,6 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ -import netneutrality.MusicBot; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java new file mode 100644 index 0000000..6439c06 --- /dev/null +++ b/src/main/java/netneutrality/command/ICommand.java @@ -0,0 +1,16 @@ +package netneutrality.command;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; + +public interface ICommand { + + /** + * @param args the arguments to the command + */ + String execute(MessageReceivedEvent event, String args); +} diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index a61ce0d..ddc51ac 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -15,8 +15,8 @@ import netneutrality.http.WebModule; public class BitcoinPriceCommand extends AbstractCommand { - private String currency = "USD"; - private String currencyUrl = "https://api.coindesk.com/v1/bpi/currentprice/"; + private String currency; + private final String currencyUrl = "https://api.coindesk.com/v1/bpi/currentprice/"; private String price; public BitcoinPriceCommand() { diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 6e1ef17..ef24518 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -14,8 +14,8 @@ import netneutrality.http.WebModule; public class EthereumPriceCommand extends AbstractCommand { - private String currency = "USD"; - private String currencyUrl = "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms="; + private String currency; + private final String currencyUrl = "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms="; private String price = ""; public EthereumPriceCommand() { diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 2c8bb6e..8b9086e 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -14,8 +14,8 @@ import netneutrality.http.WebModule; public class LitecoinPriceCommand extends AbstractCommand { - private String currency = "USD"; - private String currencyUrl = "https://api.coinmarketcap.com/v1/ticker/litecoin/?convert="; + private String currency; + private final String currencyUrl = "https://api.coinmarketcap.com/v1/ticker/litecoin/?convert="; private String price; public LitecoinPriceCommand() { diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index bf45cc0..027b34b 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -65,7 +65,6 @@ public class StopCommand extends AbstractCommand { if (player.isConnected()) { if (player.isConnectedTo(vChannel)) { - player.stopMusic(); player.leave(); } else event.getTextChannel().sendMessage("Not in your voice channel").queue(); diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index f348f59..575658c 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -63,6 +63,7 @@ public class DatabaseCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String args) { //TODO: Clean up the mess + event.getMessage().delete().queue(); if (!event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index df14339..7f76ce5 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -30,23 +30,13 @@ public class AudioPlayerSendHandler implements AudioSendHandler { @Override public boolean canProvide() { - if (lastFrame == null) { - lastFrame = audioPlayer.provide(); - } - + lastFrame = audioPlayer.provide(); return lastFrame != null; } @Override public ByteBuffer provide20MsAudio() { - if (lastFrame == null) { - lastFrame = audioPlayer.provide(); - } - - byte[] data = lastFrame != null ? lastFrame.getData() : null; - lastFrame = null; - - return ByteBuffer.wrap(data); + return ByteBuffer.wrap(lastFrame.getData()); } @Override diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java index 4ab17ce..d89fa67 100644 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -9,26 +9,58 @@ import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.handler.LogHandler; +import netneutrality.utils.MessageFunction; public class LoadResultHandler implements AudioLoadResultHandler { + private final TextChannel channel; + private final Member user; + private final TrackScheduler scheduler; + private final String identifier; + private final boolean silent; + + public LoadResultHandler(String identifier, TextChannel channel, Member user, TrackScheduler scheduler, boolean silent) { + this.identifier = identifier; + this.channel = channel; + this.user = user; + this.scheduler = scheduler; + this.silent = silent; + } + @Override public void trackLoaded(AudioTrack audioTrack) { + if (!silent) { + channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); + } + + scheduler.queue(audioTrack); } @Override public void playlistLoaded(AudioPlaylist audioPlaylist) { + if (identifier.startsWith("ytsearch:")) { + AudioTrack track = audioPlaylist.getTracks().get(0); + channel.sendMessage(MessageFunction.buildAddingTrackMessage(track, user)).queue(); + scheduler.queue(track); + } else { + for (AudioTrack track : audioPlaylist.getTracks()) { + scheduler.queue(track); + } + } } @Override public void noMatches() { - + channel.sendMessage("No matches found").queue(); } @Override public void loadFailed(FriendlyException e) { - + LogHandler.log(e); } } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 4e70f3f..1470208 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -6,19 +6,13 @@ package netneutrality.music; * This file is closed-source. It should not be distributed or copied in any way or form */ -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 net.dv8tion.jda.api.entities.*; -import netneutrality.MusicBot; import netneutrality.ThreadManager; -import netneutrality.handler.LogHandler; -import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,18 +26,18 @@ import java.util.concurrent.TimeUnit; public class MusicManager { private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); + private final Guild guild; private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); private final AudioPlayer player; private final TrackScheduler scheduler; private final static Map managers = new ConcurrentHashMap<>(); - private final String guildId; private MusicManager(Guild guild) { - this.guildId = guild.getId(); - player = playerManager.createPlayer(); + this.guild = guild; + this.player = playerManager.createPlayer(); + this.scheduler = new TrackScheduler(player); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); - scheduler = new TrackScheduler(player); player.addListener(scheduler); player.setVolume(30); @@ -62,12 +56,11 @@ public class MusicManager { } public boolean isConnectedTo(VoiceChannel vChannel) { - return vChannel != null && vChannel.equals(MusicBot.getJDA().getGuildById(guildId).getAudioManager().getConnectedChannel()); + return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); } public synchronized void connect(VoiceChannel vChannel) { if (vChannel != null && !isConnectedTo(vChannel)) { - Guild guild = MusicBot.getJDA().getGuildById(guildId); guild.getAudioManager().openAudioConnection(vChannel); ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { @@ -79,7 +72,6 @@ public class MusicManager { } public boolean isConnected() { - Guild guild = MusicBot.getJDA().getGuildById(guildId); return guild != null && guild.getAudioManager().getConnectedChannel() != null; } @@ -89,24 +81,18 @@ public class MusicManager { public synchronized void leave() { if (isConnected()) { - stopMusic(); + player.destroy(); } scheduler.resetTopic(); - Guild guild = MusicBot.getJDA().getGuildById(guildId); if (guild != null) { guild.getAudioManager().closeAudioConnection(); } } - public synchronized void stopMusic() { - scheduler.resetTopic(); - player.destroy(); - } - - public synchronized static void disconnectPlayers() { + public static void disconnectPlayers() { for (MusicManager mm : managers.values()) { mm.leave(); } @@ -119,43 +105,7 @@ public class MusicManager { scheduler.setTextChannel(channel); if (identifier != null) { - playerManager.loadItem(identifier, new AudioLoadResultHandler() { - @Override - public void trackLoaded(AudioTrack audioTrack) { - - if (!silent) { - channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); - } - - scheduler.queue(audioTrack); - } - - @Override - public void playlistLoaded(AudioPlaylist playlist) { - - if (identifier.startsWith("ytsearch:")) { - AudioTrack track = playlist.getTracks().get(0); - - channel.sendMessage(MessageFunction.buildAddingTrackMessage(track, user)).queue(); - scheduler.queue(track); - } else { - for (AudioTrack track : playlist.getTracks()) { - scheduler.queue(track); - } - } - } - - @Override - public void noMatches() { - channel.sendMessage("No matches found").queue(); - } - - @Override - public void loadFailed(FriendlyException e) { - LogHandler.log(e); - } - }); - + playerManager.loadItem(identifier, new LoadResultHandler(identifier, channel, user, scheduler, silent)); } else { channel.sendMessage("No source found to play the given url").queue(); @@ -167,7 +117,6 @@ public class MusicManager { if (!scheduler.queue.isEmpty()) { scheduler.nextTrack(); } else { - stopMusic(); leave(); } } @@ -183,6 +132,7 @@ public class MusicManager { public List getAllQueuedTrack() { List queuedTracks = new LinkedList<>(); scheduler.queue.forEach((a) -> queuedTracks.add(a.getInfo().title)); + return queuedTracks; } } diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index 27b7e7f..19b67d3 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -41,7 +41,7 @@ public class ChannelFunction { private synchronized static void deleteFromList(List messages, TextChannel channel) { try { channel.deleteMessages(messages).complete(); - logger.debug("Deleted " + messages.size() + " messages"); + logger.debug("Deleted " + messages.size() + " messages from channel ["+ channel.getName() + "] in guild [" + channel.getGuild().getName() + "]"); } catch (IllegalArgumentException e) { messages.forEach(m -> { diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 849801c..cde1de6 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -7,12 +7,15 @@ package netneutrality.utils; */ import java.awt.*; +import java.time.Duration; +import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.util.HashMap; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; @@ -58,10 +61,26 @@ public class MessageFunction { } public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { + Duration d = Duration.ofMillis(track.getDuration()); + EmbedBuilder message = new EmbedBuilder(); message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); - message.addField("Track title :", track.getInfo().title, false); + message.addField("Track title: ", track.getInfo().title, false); + message.addField("Duration: ", d.toMinutesPart() + ":" + d.toSecondsPart(), false); + message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setTimestamp(OffsetDateTime.now()); + + + return message.build(); + } + + public synchronized static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user) { + EmbedBuilder message = new EmbedBuilder(); + message.setTitle("Adding playlist to queue.."); + message.setColor(Color.BLUE); + message.addField("Playlist: ", playlist.getName(), false); + message.addField("Number of tracks: ", String.valueOf(playlist.getTracks().size()), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); From 1312c5fa53153ac70fd4588289e30203ea081ad3 Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 29 Sep 2021 20:14:22 -0400 Subject: [PATCH 037/155] Added DB entities --- .../netneutrality/db/AsyncMySqlAction.java | 6 +- .../java/netneutrality/db/MysqlDatabase.java | 31 +++++++- .../db/controllers/DBBlacklist.java | 18 ++--- .../db/entities/AbstractEntity.java | 48 ++++++++++++ .../db/entities/EntityInterface.java | 9 ++- .../java/netneutrality/db/entities/Guild.java | 16 ---- .../netneutrality/db/entities/OGuild.java | 53 +++++++++++++ .../db/entities/OGuildSetting.java | 74 +++++++++++++++++++ .../db/entities/OPermission.java | 66 +++++++++++++++++ .../netneutrality/db/entities/Permission.java | 53 ------------- .../netneutrality/db/models/MRowModel.java | 12 ++- .../netneutrality/db/models/MRowsModel.java | 7 +- .../netneutrality/db/models/MTableModel.java | 19 ++++- .../handler/ReactionHandler.java | 31 ++++++++ 14 files changed, 351 insertions(+), 92 deletions(-) create mode 100644 src/main/java/netneutrality/db/entities/AbstractEntity.java delete mode 100644 src/main/java/netneutrality/db/entities/Guild.java create mode 100644 src/main/java/netneutrality/db/entities/OGuild.java create mode 100644 src/main/java/netneutrality/db/entities/OGuildSetting.java create mode 100644 src/main/java/netneutrality/db/entities/OPermission.java delete mode 100644 src/main/java/netneutrality/db/entities/Permission.java create mode 100644 src/main/java/netneutrality/handler/ReactionHandler.java diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java index 2e84098..6370575 100644 --- a/src/main/java/netneutrality/db/AsyncMySqlAction.java +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -21,11 +21,13 @@ public class AsyncMySqlAction { private final Object[] params; private final MysqlDatabase.CommandType type; private final MysqlDatabase db; + public final String tableName; public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) { this.db = db; this.sqlString = sql; this.params = params; + this.tableName = sqlString.toUpperCase().split(" ")[1]; type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]); } @@ -56,7 +58,7 @@ public class AsyncMySqlAction { case SELECT: ThreadManager.dispatch(executor, () -> { ResultSet result = db.prepareAndExecute(this.sqlString, this.params); - MTableModel table = MysqlDatabase.convertToTableModel(result); + MTableModel table = MysqlDatabase.convertToTableModel(result, tableName); success.accept(table); }); @@ -85,7 +87,7 @@ public class AsyncMySqlAction { case SELECT: Callable task = () -> { ResultSet result = db.prepareAndExecute(this.sqlString, this.params); - MTableModel table = MysqlDatabase.convertToTableModel(result); + MTableModel table = MysqlDatabase.convertToTableModel(result, tableName); return table; }; diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 6f1f67c..78b49a2 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -248,13 +248,42 @@ public class MysqlDatabase { /** * @param rs The ResultSet returned by the SELECT query * @return a {@link MTableModel} with the appropriate column and rows - * @throws SQLException + */ + public static MTableModel convertToTableModel(ResultSet rs, String tableName) { + MTableModel table = new MTableModel(); + + try { + ResultSetMetaData metadata = rs.getMetaData(); + + for (int i = 1; i < metadata.getColumnCount() + 1; i++) { + table.addColumn(metadata.getColumnName(i)); + } + + while (rs.next()) { + MRowModel row = new MRowModel(rs.getRow() - 1); + for (int i = 0; i < metadata.getColumnCount(); i++) { + row.addColumnToRow(rs.getObject(i + 1)); + } + table.addRow(row); + } + + } catch (SQLException e) { + e.printStackTrace(); + } + + return table; + } + + /** + * @param rs The ResultSet returned by the SELECT query + * @return a {@link MTableModel} with the appropriate column and rows */ public static MTableModel convertToTableModel(ResultSet rs) { MTableModel table = new MTableModel(); try { ResultSetMetaData metadata = rs.getMetaData(); + for (int i = 1; i < metadata.getColumnCount() + 1; i++) { table.addColumn(metadata.getColumnName(i)); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 352f85d..fc6c757 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -1,14 +1,11 @@ package netneutrality.db.controllers; -import java.sql.ResultSet; import java.util.ArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; -import netneutrality.ThreadManager; import netneutrality.db.AbstractController; -import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MBlacklist; import netneutrality.db.models.MTableModel; import org.slf4j.Logger; @@ -81,20 +78,15 @@ public class DBBlacklist extends AbstractController { @Deprecated public void getBlacklistForWord(String word, String serverId, Consumer success) { - ThreadManager.getExecutor("db-action").submit(() -> { + database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async((table -> { MBlacklist blacklisted = null; - if (isAlreadyBlacklisted(word, serverId)) { - ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); - MTableModel table = MysqlDatabase.convertToTableModel(rs); - - if (table.getNbRows() > 0) { - blacklisted = new MBlacklist(table.getRow(0)); - } + if (table.getNbRows() > 0) { + blacklisted = new MBlacklist(table.getRow(0)); } - success.accept(blacklisted); - }); + + })); } diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java new file mode 100644 index 0000000..bcc2873 --- /dev/null +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -0,0 +1,48 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.MusicBot; +import netneutrality.db.DBController; +import netneutrality.db.models.MTableModel; + +public abstract class AbstractEntity implements EntityInterface { + private final String primaryKey; + private final String[] primaryKeys; + protected MTableModel table; + + + public AbstractEntity(String primaryKey, String... primaryKeys) throws ArrayIndexOutOfBoundsException { + this.primaryKey = primaryKey; + this.primaryKeys = primaryKeys; + + fillTableModel(); + + if (!table.isEmpty()) + convertFromTableModel(table); + } + + private void fillTableModel() throws ArrayIndexOutOfBoundsException { + StringBuilder whereClause = new StringBuilder(); + for (String pk : getPrimaryKeys()) { + whereClause.append(pk + " = ?"); + + if (getPrimaryKeys().length > 1) + whereClause.append(" AND "); + } + + + String sql = "SELECT * FROM " + getTableName() + " WHERE " + whereClause; + System.out.println(sql + " - pk: " + primaryKey); + + if (this.primaryKeys.length > 0) + this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey, this.primaryKeys).blocking(); + else + this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey).blocking(); + System.out.println(table); + } + +} diff --git a/src/main/java/netneutrality/db/entities/EntityInterface.java b/src/main/java/netneutrality/db/entities/EntityInterface.java index 65940aa..98cae86 100644 --- a/src/main/java/netneutrality/db/entities/EntityInterface.java +++ b/src/main/java/netneutrality/db/entities/EntityInterface.java @@ -7,8 +7,13 @@ package netneutrality.db.entities;/* import netneutrality.db.models.MTableModel; -public interface EntityInterface { +public interface EntityInterface { - public E ConvertFromTableModel(MTableModel table); + String getTableName(); + String[] getPrimaryKeys(); + boolean exists(); + + + void convertFromTableModel(MTableModel table); } diff --git a/src/main/java/netneutrality/db/entities/Guild.java b/src/main/java/netneutrality/db/entities/Guild.java deleted file mode 100644 index c562498..0000000 --- a/src/main/java/netneutrality/db/entities/Guild.java +++ /dev/null @@ -1,16 +0,0 @@ -package netneutrality.db.entities;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - - -public class Guild { - - private int guildID; - - public Guild() { - - } -} diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java new file mode 100644 index 0000000..5d8decd --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -0,0 +1,53 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import netneutrality.db.models.MTableModel; + +public class OGuild extends AbstractEntity { + + private String guildID; + public boolean logging; + public String logchannel; + + public OGuildSetting settings; + + public OGuild(String guildId) { + super(guildId); + + this.settings = new OGuildSetting(this); + } + + @Override + public boolean exists() { + return guildID != null; + } + + public String getGuildID() { + return guildID; + } + + @Override + public String getTableName() { + return "guilds"; + } + + @Override + public String[] getPrimaryKeys() { + return new String[] {"guild_id"}; + } + + + @Override + public void convertFromTableModel(MTableModel table) { + this.guildID = (String) table.getRow(0).get(0); + this.logging = ((Integer) table.getRow(0).get(1)) == 1; + this.logchannel = (String) table.getRow(0).get(2); + + } + +} diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java new file mode 100644 index 0000000..c463c73 --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -0,0 +1,74 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.db.models.MRowModel; +import netneutrality.db.models.MTableModel; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class OGuildSetting extends AbstractEntity { + private final OGuild guild; + private Map settings; + + public OGuildSetting(OGuild OGuild) { + super(OGuild.getGuildID()); + + this.guild = OGuild; + } + + public OGuild getGuild() { + return guild; + } + + public Map getSettings() { + return settings; + } + + public String getSettingByKey(String key) { + if (settings.containsKey(key)) { + return settings.get(key); + } + + return null; + } + + @Override + public String getTableName() { + return "guild_settings"; + } + + @Override + public String[] getPrimaryKeys() { + return new String[] {"guild_id"}; + } + + @Override + public boolean exists() { + return !settings.isEmpty(); + } + + @Override + public void convertFromTableModel(MTableModel table) { + settings = new HashMap<>(); + + List columns = table.getColumns(); + MRowModel row = table.getRowModel(0); + + for (int i = 0; i < columns.size(); i++) { + if (i == 0) continue; + + String key = columns.get(i).replace('_', '.'); + String value = (row.getItem(i) == null ? "" : row.getItem(i).toString()); + + settings.put(key, value); + } + + + } +} diff --git a/src/main/java/netneutrality/db/entities/OPermission.java b/src/main/java/netneutrality/db/entities/OPermission.java new file mode 100644 index 0000000..8f35ffe --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OPermission.java @@ -0,0 +1,66 @@ +package netneutrality.db.entities;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.command.CommandType; +import netneutrality.db.models.MTableModel; + +import java.util.List; + +public class OPermission extends AbstractEntity { + private final String guild_id; + private final String role_id; + public CommandType type; + public String command; + + public OPermission(String guild_id, String role_id) { + super(guild_id, role_id); + + this.guild_id = guild_id; + this.role_id = role_id; + } + + @Override + public boolean exists() { + return guild_id != null && role_id != null; + } + + public String getGuildId() { + return guild_id; + } + + public String getRoleId() { + return role_id; + } + + public CommandType getType() { + return type; + } + + public String getCommand() { + return command; + } + + + @Override + public String getTableName() { + return "permissions"; + } + + @Override + public String[] getPrimaryKeys() { + return new String[] {"guild_id", "role_id"}; + } + + + @Override + public void convertFromTableModel(MTableModel table) { + + this.type = (CommandType) table.getRow(0).get(2); + this.command = (String) table.getRow(0).get(3); + + } +} diff --git a/src/main/java/netneutrality/db/entities/Permission.java b/src/main/java/netneutrality/db/entities/Permission.java deleted file mode 100644 index 553b1ed..0000000 --- a/src/main/java/netneutrality/db/entities/Permission.java +++ /dev/null @@ -1,53 +0,0 @@ -package netneutrality.db.entities;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.CommandType; -import netneutrality.db.models.MTableModel; - -import java.util.List; - -public class Permission implements EntityInterface { - private final String guild_id; - private final String role_id; - private final CommandType type; - private final String command; - - public Permission(String guild_id, String role_id, CommandType type, String command) { - this.guild_id = guild_id; - this.role_id = role_id; - this.type = type; - this.command = command; - } - - public Permission(List row) { - this.guild_id = (String) row.get(0); - this.role_id = (String) row.get(1); - this.type = (CommandType) row.get(2); - this.command = (String) row.get(3); - } - - public String getGuild_id() { - return guild_id; - } - - public String getRole_id() { - return role_id; - } - - public CommandType getType() { - return type; - } - - public String getCommand() { - return command; - } - - @Override - public Permission ConvertFromTableModel(MTableModel table) { - return null; - } -} diff --git a/src/main/java/netneutrality/db/models/MRowModel.java b/src/main/java/netneutrality/db/models/MRowModel.java index 0d0dae4..a277bee 100644 --- a/src/main/java/netneutrality/db/models/MRowModel.java +++ b/src/main/java/netneutrality/db/models/MRowModel.java @@ -11,17 +11,27 @@ import java.util.Arrays; import java.util.List; public class MRowModel { - private ArrayList row; + private final ArrayList row; + private int rowIndex; public MRowModel() { row = new ArrayList<>(); } + public MRowModel(Integer rowIndex) { + row = new ArrayList<>(); + this.rowIndex = rowIndex; + } + public MRowModel(Object... objs) { row = new ArrayList<>(); row.addAll(Arrays.asList(objs)); } + public int getRowIndex() { + return rowIndex; + } + public void addColumnToRow(Object obj) { row.add(obj); } diff --git a/src/main/java/netneutrality/db/models/MRowsModel.java b/src/main/java/netneutrality/db/models/MRowsModel.java index 2cce3b0..fd9da06 100644 --- a/src/main/java/netneutrality/db/models/MRowsModel.java +++ b/src/main/java/netneutrality/db/models/MRowsModel.java @@ -9,7 +9,8 @@ package netneutrality.db.models; import java.util.ArrayList; public class MRowsModel { - private ArrayList rows; + private final ArrayList rows; + private String[] primaryKeys; public MRowsModel() { rows = new ArrayList<>(); @@ -26,6 +27,10 @@ public class MRowsModel { return null; } + public int size() { + return rows.size(); + } + public void addColumnInRow(int index, Object obj) { rows.get(index).addColumnToRow(obj); } diff --git a/src/main/java/netneutrality/db/models/MTableModel.java b/src/main/java/netneutrality/db/models/MTableModel.java index 5a93c95..e69d5a4 100644 --- a/src/main/java/netneutrality/db/models/MTableModel.java +++ b/src/main/java/netneutrality/db/models/MTableModel.java @@ -3,36 +3,49 @@ package netneutrality.db.models; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ - import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class MTableModel { + private String name; private final List column; private final MRowsModel rows; public MTableModel() { + this.name = null; this.column = new LinkedList<>(); this.rows = new MRowsModel(); } public MTableModel(String tableName) { + this.name = tableName; this.column = new LinkedList<>(); this.rows = new MRowsModel(); } public MTableModel(String... columns) { + this.name = null; this.column = new LinkedList<>(); this.rows = new MRowsModel(); this.column.addAll(Arrays.asList(columns)); } + public String getName() { + return name; + } + + public void setName(String name) { + if (this.name != null) + this.name = name; + } + public MTableModel addColumn(String name) { column.add(name); return this; @@ -75,6 +88,6 @@ public class MTableModel { @Override public String toString() { - return "Column: [" + column + "], Rows (" + getNbRows() + "): [" + rows + "]"; + return "Column: " + column + ", Rows (" + getNbRows() + "): " + rows; } } diff --git a/src/main/java/netneutrality/handler/ReactionHandler.java b/src/main/java/netneutrality/handler/ReactionHandler.java new file mode 100644 index 0000000..512a834 --- /dev/null +++ b/src/main/java/netneutrality/handler/ReactionHandler.java @@ -0,0 +1,31 @@ +package netneutrality.handler;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +public class ReactionHandler extends ListenerAdapter { + + @Override + public void onGuildMessageReactionAdd(@NotNull GuildMessageReactionAddEvent event) { + Member member = event.getMember(); + } + + @Override + public void onGuildMessageReactionRemove(@NotNull GuildMessageReactionRemoveEvent event) { + super.onGuildMessageReactionRemove(event); + } + + @Override + public void onGuildMessageUpdate(@NotNull GuildMessageUpdateEvent event) { + super.onGuildMessageUpdate(event); + } +} From 98d2f5d411936352bed081397826bcb7476f3bf7 Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 27 Oct 2021 12:16:34 -0400 Subject: [PATCH 038/155] scuffed push --- .mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++ .mvn/wrapper/maven-wrapper.properties | 2 + Dockerfile | 12 + bot.config.example | 20 +- docker-compose.yml | 38 +++ mvnw | 310 ++++++++++++++++++ mvnw.cmd | 182 ++++++++++ pom.xml | 19 +- netneutrality.sql => sql/netneutrality.sql | 1 + src/main/java/netneutrality/GuildManager.java | 65 ++++ src/main/java/netneutrality/MusicBot.java | 23 +- .../java/netneutrality/ThreadManager.java | 8 +- .../command/PermissionManager.java | 3 - .../command/bot/ConfigureCommand.java | 60 ++++ .../java/netneutrality/db/DBController.java | 2 +- .../java/netneutrality/db/MysqlDatabase.java | 19 +- .../netneutrality/db/entities/OGuild.java | 19 +- .../handler/MessageRateLimit.java | 44 --- .../handler/NewCommandListener.java | 24 +- .../handler/ServerJoinHandler.java | 3 +- .../ratelimiter/IMessageRateLimiter.java | 16 + .../ratelimiter/MessageRateLimiterImpl.java | 51 +++ .../http/server/ActionHandler.java | 2 +- .../netneutrality/music/TrackScheduler.java | 5 +- .../netneutrality/utils/MessageFunction.java | 2 +- .../java/netneutrality/utils/Settings.java | 27 +- src/main/resources/log4j2.xml | 6 +- 27 files changed, 971 insertions(+), 109 deletions(-) create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 mvnw create mode 100644 mvnw.cmd rename netneutrality.sql => sql/netneutrality.sql (99%) create mode 100644 src/main/java/netneutrality/GuildManager.java create mode 100644 src/main/java/netneutrality/command/bot/ConfigureCommand.java delete mode 100644 src/main/java/netneutrality/handler/MessageRateLimit.java create mode 100644 src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java create mode 100644 src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..b901097 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..77ba04c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM openjdk:11-jdk-slim + +WORKDIR /app + +COPY .mvn/ .mvn +COPY mvnw pom.xml ./ +COPY src ./src +COPY bot.config.example bot.config ./ + +RUN ./mvnw -q -Dmaven.test.skip=true package + +CMD ["java", "-jar", "target/netneutrality-jar-with-dependencies.jar"] \ No newline at end of file diff --git a/bot.config.example b/bot.config.example index 76fa6b1..5495ed4 100644 --- a/bot.config.example +++ b/bot.config.example @@ -1,11 +1,11 @@ -bot.token= -bot.prefix= -bot.owner= -bot.ownerguild= -bot.errorchannel= +BOT_TOKEN= +BOT_PREFIX= +BOT_OWNER= +BOT_OWNERGUILD= +BOT_ERRORCHANNEL= -mysql.host=localhost -mysql.user=root -mysql.password= -mysql.database= -mysql.port=3306 \ No newline at end of file +MYSQL_HOST= +MYSQL_USER= +MYSQL_PASSWORD= +MYSQL_DATABASE= +MYSQL_PORT=3306 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e1f3842 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.3' + +services: + db: + image: mysql:5.7 + restart: always + volumes: + - netneutrality-db:/var/lib/mysql + - ./sql/netneutrality.sql:/docker-entrypoint-initdb.d/dump.sql + environment: + MYSQL_DATABASE: 'netneutrality' + MYSQL_USER: 'java' + MYSQL_PASSWORD: 'password' + MYSQL_ROOT_PASSWORD: 'password' + ports: + - "3306" + networks: + - internal + app: + image: netneutrality:dev + restart: always + depends_on: + - db + environment: + MYSQL_HOST: 'db' + MYSQL_USER: 'java' + MYSQL_PASSWORD: 'password' + MYSQL_DATABASE: 'netneutrality' + ports: + - "9000:9000" + networks: + - internal + +volumes: + netneutrality-db: + +networks: + internal: \ No newline at end of file diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..41c0f0c --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..8611571 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 3a94aaf..e7f8810 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,6 @@ 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.5.4 - - com.xtremcommunity.discord netneutrality @@ -17,10 +11,20 @@ 11 + UTF-8 + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + UTF-8 + + org.apache.maven.plugins @@ -47,6 +51,9 @@ true true + + true + jar-with-dependencies diff --git a/netneutrality.sql b/sql/netneutrality.sql similarity index 99% rename from netneutrality.sql rename to sql/netneutrality.sql index 62209aa..69be13f 100644 --- a/netneutrality.sql +++ b/sql/netneutrality.sql @@ -14,6 +14,7 @@ SET time_zone = "+00:00"; -- -- Base de données : `netneutrality` -- +USE netneutrality; -- -------------------------------------------------------- diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java new file mode 100644 index 0000000..2824f91 --- /dev/null +++ b/src/main/java/netneutrality/GuildManager.java @@ -0,0 +1,65 @@ +package netneutrality; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Guild; +import netneutrality.db.entities.OGuild; +import netneutrality.db.entities.OGuildSetting; +import netneutrality.handler.ratelimiter.IMessageRateLimiter; +import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class GuildManager { + + public static final Logger logger = LoggerFactory.getLogger(GuildManager.class); + private static final Map managers = new ConcurrentHashMap<>(); + private final Guild guild; + private final OGuild guildEntity; + private final IMessageRateLimiter rateLimiter; + + private GuildManager(Guild guild) { + this.guild = guild; + this.guildEntity = new OGuild(guild.getId()); + + this.rateLimiter = new MessageRateLimiterImpl(); + managers.put(guild.getId(), this); + } + + public static GuildManager getManager(Guild guild) { + if (managers.containsKey(guild.getId())) { + return managers.get(guild.getId()); + } else { + return new GuildManager(guild); + } + } + + public String getSetting(String key) { + return guildEntity.getSettings().getSettingByKey(key); + } + + public void reloadSettings() { + guildEntity.reloadSettings(); + } + + public IMessageRateLimiter getRateLimiter() { + return rateLimiter; + } + + public Guild getGuild() { + return guild; + } + + + + private void load() { + + } +} diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 8c3c02b..b734615 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -13,6 +13,9 @@ import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; import netneutrality.utils.Settings; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,29 +32,36 @@ public class MusicBot { DBController.init(); try { - jda = JDABuilder.createDefault(Settings.getInstance().get("bot.token")) + jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")) .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) .build(); jda.awaitReady(); } catch (LoginException | IllegalArgumentException | InterruptedException e) { logger.error(e.getMessage()); - shutdown(); + System.exit(0); } - jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new NewCommandListener(), new EditHandler()); new WebApi(); jda.getPresence().setActivity(Activity.watching("you")); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + if( LogManager.getContext() instanceof LoggerContext) { + logger.debug("Shutting down log4j2"); + Configurator.shutdown((LoggerContext)LogManager.getContext()); + } + + MusicBot.shutdown(); + })); ConsoleHandler consoleInput = new ConsoleHandler(); switch (consoleInput.init()) { case "quit": - shutdown(); + System.exit(0); break; } @@ -59,13 +69,12 @@ public class MusicBot { } public static void shutdown() { - logger.info("[Net Neutrality] Shutting down..."); + System.out.println("[Net Neutrality] Shutting down..."); MusicManager.disconnectPlayers(); ThreadManager.shutdownExecutor(); disconnect(); DBController.shutdown(); - logger.info("[Net Neutrality] Shutdown complete"); - System.exit(0); + System.out.println("[Net Neutrality] Shutdown complete"); } public static JDA getJDA() { diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 7fb860a..8225af1 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -65,7 +65,7 @@ public class ThreadManager { } public static void shutdownExecutor() { - logger.debug("[Executor] Shutting down..."); + System.out.println("[Executor] Shutting down..."); try { for (ExecutorService ex : executors.values()) { @@ -74,19 +74,19 @@ public class ThreadManager { } } catch (InterruptedException e) { - logger.warn("[Executor] Running tasks interrupted"); + System.err.println("[Executor] Running tasks interrupted"); } finally { executors.forEach((name, ex) -> { if (!ex.isTerminated()) { - logger.warn("[Executor: " + name + "] Forcing shutdown of running tasks.."); + System.err.println("[Executor: " + name + "] Forcing shutdown of running tasks.."); ex.shutdownNow(); } }); } - logger.debug("[Executor] Shutdown finished!"); + System.out.println("[Executor] Shutdown finished!"); } diff --git a/src/main/java/netneutrality/command/PermissionManager.java b/src/main/java/netneutrality/command/PermissionManager.java index dec8203..d2c799e 100644 --- a/src/main/java/netneutrality/command/PermissionManager.java +++ b/src/main/java/netneutrality/command/PermissionManager.java @@ -8,9 +8,6 @@ package netneutrality.command;/* import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; -import netneutrality.db.DBController; -import netneutrality.db.entities.Permission; -import netneutrality.db.models.MTableModel; import java.util.List; diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java new file mode 100644 index 0000000..9918add --- /dev/null +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -0,0 +1,60 @@ +package netneutrality.command.bot;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; +import netneutrality.command.Visibility; + +public class ConfigureCommand extends AbstractCommand { + @Override + public boolean needAdmin() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getCommand() { + return "configure"; + } + + @Override + public String[] getAlias() { + return new String[] { + "conf" + }; + } + + @Override + public String getUsage() { + return null; + } + + @Override + public String getDescription() { + return "Used to configure the bot on this server"; + } + + @Override + public Visibility getVisibility() { + return Visibility.CHANNEL; + } + + @Override + public CommandType getType() { + return CommandType.ADMINISTRATION; + } + + @Override + public String execute(MessageReceivedEvent event, String args) { + return null; + } +} diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index e572608..19d0041 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -28,7 +28,7 @@ public class DBController { private final static HashMap controllers = new HashMap<>(); private final static Logger logger = LoggerFactory.getLogger(DBController.class); - private static final MysqlDatabase database = new MysqlDatabase(Settings.getInstance().get("mysql.database", "netneutrality")); + private static final MysqlDatabase database = new MysqlDatabase(Settings.getInstance().get("MYSQL_DATABASE", "netneutrality")); /** * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 78b49a2..1ab401f 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -42,16 +42,16 @@ public class MysqlDatabase { protected MysqlDatabase(String dbName) { this.dbName = dbName; - String dbUser = Settings.getInstance().get("mysql.user", "root"); - String dbPass = Settings.getInstance().get("mysql.password", ""); - String dbHost = Settings.getInstance().get("mysql.host", "localhost"); + String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); + String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); + String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); try { - logger.info(String.format("Connecting to database '%1$s' at %2$s:3306", dbName, dbHost)); + logger.info(String.format("Connecting to database '%1$s' at %2$s:3306 with user '%3$s'", dbName, dbHost, dbUser)); connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); } catch (SQLException e) { logger.error("Error connecting to database. Shutting down..", e); - MusicBot.shutdown(); + System.exit(0); } } @@ -147,8 +147,7 @@ public class MysqlDatabase { ResultSet rs = query.executeQuery(); return rs; } catch (SQLException e) { - logger.error(e.getMessage()); - e.printStackTrace(); + logger.error(e.getMessage(), e); } return null; @@ -221,13 +220,15 @@ public class MysqlDatabase { * Recreate and reconnect the MySQL connection. */ public void reconnect() { + String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); + String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); + String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); try { logger.info("Reconnecting to database..."); - connection = new MysqlConnector(dbName, "root", "localhost", "").connect().getConnection(); + connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); } catch (SQLException e) { logger.error("Error connecting to database. Shutting down.."); - MusicBot.shutdown(); System.exit(0); } } diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java index 5d8decd..557dab0 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -6,6 +6,7 @@ package netneutrality.db.entities;/* */ +import netneutrality.GuildManager; import netneutrality.db.models.MTableModel; public class OGuild extends AbstractEntity { @@ -14,7 +15,7 @@ public class OGuild extends AbstractEntity { public boolean logging; public String logchannel; - public OGuildSetting settings; + private OGuildSetting settings; public OGuild(String guildId) { super(guildId); @@ -22,15 +23,24 @@ public class OGuild extends AbstractEntity { this.settings = new OGuildSetting(this); } - @Override - public boolean exists() { - return guildID != null; + public void reloadSettings() { + GuildManager.logger.debug("Reloading settings for guild: " + guildID); + this.settings = new OGuildSetting(this); } public String getGuildID() { return guildID; } + public OGuildSetting getSettings() { + return settings; + } + + @Override + public boolean exists() { + return guildID != null; + } + @Override public String getTableName() { return "guilds"; @@ -49,5 +59,4 @@ public class OGuild extends AbstractEntity { this.logchannel = (String) table.getRow(0).get(2); } - } diff --git a/src/main/java/netneutrality/handler/MessageRateLimit.java b/src/main/java/netneutrality/handler/MessageRateLimit.java deleted file mode 100644 index 3e19285..0000000 --- a/src/main/java/netneutrality/handler/MessageRateLimit.java +++ /dev/null @@ -1,44 +0,0 @@ -package netneutrality.handler; - -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.MessageChannel; -import net.dv8tion.jda.api.entities.PrivateChannel; -import netneutrality.ThreadManager; - -import java.time.OffsetDateTime; - -public class MessageRateLimit { - - private static Member lastSender; - private static OffsetDateTime timestamp; - private static final long cooldown = 500000000L; // 1 seconds = 1000000000 nanoseconds - - public synchronized static boolean check(Member member, Message message, MessageChannel channel) { - - if (channel instanceof PrivateChannel) - return false; - - if (lastSender == null || timestamp == null) { - lastSender = member; - timestamp = message.getTimeCreated(); - return false; - } - - if (member.getUser().getId().equals(lastSender.getUser().getId())) { - if (message.getTimeCreated().minusNanos(cooldown).isBefore(timestamp)) { - lastSender = member; - timestamp = message.getTimeCreated(); - message.delete().queue(); - return true; - } - } - - lastSender = member; - timestamp = message.getTimeCreated(); - - return false; - - } - -} diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index cf7b4a8..fd86c05 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -4,18 +4,18 @@ package netneutrality.handler; import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.GuildManager; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandManager; import netneutrality.command.Visibility; -import netneutrality.command.basic.HelpCommand; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; import netneutrality.utils.MessageFunction; import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; - -import java.time.format.DateTimeFormatter; +import org.jetbrains.annotations.NotNull; public class NewCommandListener extends ListenerAdapter { @@ -24,11 +24,21 @@ public class NewCommandListener extends ListenerAdapter { } @Override - public void onMessageReceived(MessageReceivedEvent event) { + public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + if (event.getAuthor().isBot()) return; + if (event.isWebhookMessage()) return; + GuildManager.getManager(event.getGuild()).getRateLimiter().check(event.getMember(), event.getMessage(), event.getChannel()); + + + } + + @Override + public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (event.getAuthor().isBot()) return; if (event.isWebhookMessage()) return; - if (MessageRateLimit.check(event.getMember(), event.getMessage(), event.getChannel())) return; + + if (event.getMessage().isEdited()) if (event.isFromType(ChannelType.TEXT)) { ((DBMessage) DBController.get("message")).log(event.getGuild(), event.getTextChannel(), event.getAuthor(), event.getMessage()); @@ -37,8 +47,8 @@ public class NewCommandListener extends ListenerAdapter { Message message = event.getMessage(); String msg = message.getContentDisplay().trim(); - if (msg.startsWith(Settings.getInstance().get("bot.prefix"))) { - msg = msg.substring(1); + if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()); String cmd = msg.split(" ", 2)[0]; if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { diff --git a/src/main/java/netneutrality/handler/ServerJoinHandler.java b/src/main/java/netneutrality/handler/ServerJoinHandler.java index 3cb8b6b..7b33992 100644 --- a/src/main/java/netneutrality/handler/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/ServerJoinHandler.java @@ -9,11 +9,12 @@ package netneutrality.handler; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { @Override - public void onGuildJoin(GuildJoinEvent event){ + public void onGuildJoin(@NotNull GuildJoinEvent event){ diff --git a/src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java b/src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java new file mode 100644 index 0000000..4ce8d7b --- /dev/null +++ b/src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java @@ -0,0 +1,16 @@ +package netneutrality.handler.ratelimiter; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; + +public interface IMessageRateLimiter { + + void check(Member member, Message message, TextChannel channel); +} diff --git a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java new file mode 100644 index 0000000..6a4bdbf --- /dev/null +++ b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java @@ -0,0 +1,51 @@ +package netneutrality.handler.ratelimiter;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.handler.ratelimiter.IMessageRateLimiter; + +import java.time.OffsetDateTime; + +public class MessageRateLimiterImpl implements IMessageRateLimiter { + private int messagePerSecond = 5; + private static Member lastSender; + private static OffsetDateTime timestamp; + private static final long cooldown = 500000000L; // 1 seconds = 1000000000 nanoseconds + + @Override + public void check(Member member, Message message, TextChannel channel) { + + if (lastSender == null || timestamp == null) { + lastSender = member; + timestamp = message.getTimeCreated(); + return; + } + + if (member.getUser().getId().equals(lastSender.getUser().getId())) { + if (message.getTimeCreated().minusNanos(cooldown).isBefore(timestamp)) { + lastSender = member; + timestamp = message.getTimeCreated(); + message.delete().queue(); + return; + } + } + + lastSender = member; + timestamp = message.getTimeCreated(); + + return; + } +} diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index c36f4dc..5d99f42 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -22,7 +22,7 @@ public class ActionHandler implements HttpHandler { if (path.equals("/actions/shutdown")) { LogManager.getLogger(MusicBot.class).info("Request to shutdown received"); WebApi.sendStringResponse(exchange, "Shutting down.."); - MusicBot.shutdown(); + System.exit(0); return; } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 05bf815..cc9d1e7 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -33,10 +33,11 @@ public class TrackScheduler extends AudioEventAdapter { // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. boolean start = player.startTrack(track, true); + channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); + if (!start) { queue.offer(track); - } else - channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); + } } public void setTextChannel(TextChannel channel) { diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index cde1de6..063d8b6 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -108,7 +108,7 @@ public class MessageFunction { } - message.addField(Settings.getInstance().get("bot.prefix") + command.getCommand() + " - Arguments: " + usage, description, false); + message.addField(Settings.getInstance().get("BOT_PREFIX") + command.getCommand() + " - Arguments: " + usage, description, false); } return message.build(); diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 3f1b730..567ef8b 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -6,6 +6,7 @@ import net.dv8tion.jda.api.entities.User; import netneutrality.MusicBot; import java.io.*; +import java.util.Map; import java.util.Properties; public class Settings { @@ -15,21 +16,37 @@ public class Settings { public Settings() { File file = new File("bot.config"); + FileInputStream fis = null; try { file.createNewFile(); - - FileInputStream fis = new FileInputStream(file); + fis = new FileInputStream(file); prop.load(fis); - fis.close(); + + loadEnvironmentVariables(); } catch (IOException e) { e.printStackTrace(); + } finally { + try { + if (fis != null) + fis.close(); + } catch (IOException ignored) { } } } + private void loadEnvironmentVariables() { + Map envs = System.getenv(); + + for (Map.Entry env : envs.entrySet()) { + if (prop.containsKey(env.getKey())) { + prop.setProperty(env.getKey(), env.getValue()); + } + } + } + public static Settings getInstance() { - if(INSTANCE == null) { + if (INSTANCE == null) { INSTANCE = new Settings(); } @@ -43,7 +60,7 @@ public class Settings { public String get(String key, String def) { String property = prop.getProperty(key); - if (property == null) + if (property == null || property.isEmpty()) return def; return property; diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index c27bace..ac416cb 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,16 +1,16 @@ - + - + - \ No newline at end of file + From 65143eb003db176c7b82ab2e42d4395f21c893ef Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 00:27:01 -0400 Subject: [PATCH 039/155] Optimized command arguments parsing --- .../command/AbstractCommand.java | 25 -------- .../java/netneutrality/command/ICommand.java | 2 +- .../command/basic/HelpCommand.java | 2 +- .../command/basic/PingCommand.java | 4 +- .../command/bot/ConfigureCommand.java | 2 +- .../command/crypto/BitcoinPriceCommand.java | 10 ++-- .../command/crypto/EthereumPriceCommand.java | 8 +-- .../command/crypto/LitecoinPriceCommand.java | 8 +-- .../command/message/BlacklistCommand.java | 8 +-- .../command/message/PruneCommand.java | 6 +- .../command/music/BitconnectCommand.java | 2 +- .../command/music/DeleteQueueCommand.java | 2 +- .../command/music/JoinCommand.java | 2 +- .../command/music/LeaveCommand.java | 2 +- .../command/music/PlayCommand.java | 6 +- .../command/music/SkipCommand.java | 2 +- .../command/music/StopCommand.java | 2 +- .../command/music/VolumeCommand.java | 4 +- .../command/music/VoteSkipCommand.java | 58 +++++++++++++++++++ .../command/specific/DatabaseCommand.java | 14 ++--- .../command/specific/EvalMethod.java | 2 +- .../command/specific/LoggingCommand.java | 2 +- .../command/specific/SellyCommand.java | 8 +-- .../command/specific/ShutdownCommand.java | 2 +- .../command/specific/TestCommand.java | 6 +- 25 files changed, 109 insertions(+), 80 deletions(-) create mode 100644 src/main/java/netneutrality/command/music/VoteSkipCommand.java diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 6e048da..76c1eec 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -1,14 +1,7 @@ package netneutrality.command; -import java.util.Arrays; -import java.util.List; - public abstract class AbstractCommand implements ICommand { - public AbstractCommand() { - - } - /** * @return if the command needs administrator privilege */ @@ -39,22 +32,4 @@ public abstract class AbstractCommand implements ICommand { public abstract CommandType getType(); - - public int countArgs(String command) { - if (command.isEmpty()) - return 0; - - List args = Arrays.asList(command.split(" ")); - return args.size(); - } - - public String parseArgs(String command, int arg) { - if (command.isEmpty()) - return ""; - - List args = Arrays.asList(command.split(" ")); - return args.get(arg); - } - - } diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 6439c06..21b7013 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -12,5 +12,5 @@ public interface ICommand { /** * @param args the arguments to the command */ - String execute(MessageReceivedEvent event, String args); + String execute(MessageReceivedEvent event, String[] args); } diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 792a9b2..098ede5 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -20,7 +20,7 @@ public class HelpCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { sendHelp(CommandManager.commands, CommandManager.commandsAlias, event.getAuthor(), event.getChannel()); return null; diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 5c91b8a..1ded4c0 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -9,8 +9,8 @@ import netneutrality.command.Visibility; public class PingCommand extends AbstractCommand { @Override - public String execute(MessageReceivedEvent event, String args) { - if (countArgs(args) == 0) + public String execute(MessageReceivedEvent event, String[] args) { + if (args.length == 0) event.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); return null; diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 9918add..1ddaafe 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -54,7 +54,7 @@ public class ConfigureCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { return null; } } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index ddc51ac..c71b70f 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -30,11 +30,11 @@ public class BitcoinPriceCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) throws JSONException, ArrayIndexOutOfBoundsException { - - if (countArgs(args) == 1) { - if (Currency.isCurrency(args.toUpperCase())) - this.currency = args.toUpperCase(); + public String execute(MessageReceivedEvent event, String[] args) throws JSONException, ArrayIndexOutOfBoundsException { + + if (args.length == 1) { + if (Currency.isCurrency(args[0].toUpperCase())) + this.currency = args[0].toUpperCase(); else { event.getTextChannel().sendMessage("Please enter a valid currency").queue(); return null; diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index ef24518..2f43a3d 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -27,11 +27,11 @@ public class EthereumPriceCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) throws JSONException, ArrayIndexOutOfBoundsException { + public String execute(MessageReceivedEvent event, String[] args) throws JSONException, ArrayIndexOutOfBoundsException { - if (countArgs(args) == 1) { - if (Currency.isCurrency(args.toUpperCase())) - this.currency = args.toUpperCase(); + if (args.length == 1) { + if (Currency.isCurrency(args[0].toUpperCase())) + this.currency = args[0].toUpperCase(); else { event.getTextChannel().sendMessage("Please enter a valid currency").queue(); return null; diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 8b9086e..3a7efb1 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -27,11 +27,11 @@ public class LitecoinPriceCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) throws ArrayIndexOutOfBoundsException, JSONException { + public String execute(MessageReceivedEvent event, String[] args) throws ArrayIndexOutOfBoundsException, JSONException { - if (countArgs(args) == 1) { - if (Currency.isCurrency(args.toUpperCase())) - this.currency = args; + if (args.length == 1) { + if (Currency.isCurrency(args[0].toUpperCase())) + this.currency = args[0].toUpperCase(); else { event.getTextChannel().sendMessage("Please enter a valid currency").queue(); return null; diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 3618cba..b1a6ce3 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -51,12 +51,12 @@ public class BlacklistCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { - if (countArgs(args) > 0 && countArgs(args) < 3) { - String word = (countArgs(args) == 2 ? parseArgs(args, 1) : ""); + if (args.length > 0 && args.length < 3) { + String word = (args.length == 2 ? args[1] : ""); - switch (parseArgs(args, 0)) { + switch (args[0]) { case "get": event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index 6fda00e..f8645a6 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -49,9 +49,9 @@ public class PruneCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { - if (countArgs(args) == 1) - ChannelFunction.bulkDeleteMessage(event.getTextChannel(), Integer.parseInt(args)); + public String execute(MessageReceivedEvent event, String[] args) { + if (args.length == 1) + ChannelFunction.bulkDeleteMessage(event.getTextChannel(), Integer.parseInt(args[0])); else event.getTextChannel().sendMessage("Failed to delete messages!").queue(); diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 896c31b..969ddd7 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -56,7 +56,7 @@ public class BitconnectCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 2b20368..ce8f8a2 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -56,7 +56,7 @@ public class DeleteQueueCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 3667fbe..9a64153 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -56,7 +56,7 @@ public class JoinCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); if (member.getVoiceState().inVoiceChannel()) { diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 3bb094d..10786c2 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -56,7 +56,7 @@ public class LeaveCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); VoiceChannel vChannel = member.getVoiceState().getChannel(); diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index f8c87e2..7d85dd0 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -56,7 +56,7 @@ public class PlayCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); @@ -67,14 +67,14 @@ public class PlayCommand extends AbstractCommand { if (player.isConnectedTo(vChannel)) { event.getMessage().delete().queue(); - player.play(args, event.getTextChannel(), event.getMember(), false); + player.play(args[0], event.getTextChannel(), event.getMember(), false); } else event.getTextChannel().sendMessage("Not in your voice channel").queue(); } else { player.connect(vChannel); event.getMessage().delete().queue(); - player.play(args, event.getTextChannel(), event.getMember(), false); + player.play(args[0], event.getTextChannel(), event.getMember(), false); } } else event.getTextChannel().sendMessage("You are not in a voice channel").queue(); diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index cf031ab..8c48bdf 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -56,7 +56,7 @@ public class SkipCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 027b34b..2fea9b3 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -56,7 +56,7 @@ public class StopCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index fec6c46..aa6daa8 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -56,7 +56,7 @@ public class VolumeCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); MusicManager player = MusicManager.get(event.getGuild()); @@ -67,7 +67,7 @@ public class VolumeCommand extends AbstractCommand { if (player.isConnectedTo(vChannel)) { try { - int volume = Integer.parseInt(args.split(" ")[0]); + int volume = Integer.parseInt(args[0]); player.setVolume(volume); } catch (NumberFormatException e) { e.printStackTrace(); diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java new file mode 100644 index 0000000..ca36281 --- /dev/null +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -0,0 +1,58 @@ +package netneutrality.command.music;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; +import netneutrality.command.Visibility; + +public class VoteSkipCommand extends AbstractCommand { + @Override + public boolean needAdmin() { + return false; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public String getCommand() { + return null; + } + + @Override + public String[] getAlias() { + return new String[0]; + } + + @Override + public String getUsage() { + return null; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public Visibility getVisibility() { + return null; + } + + @Override + public CommandType getType() { + return null; + } + + @Override + public String execute(MessageReceivedEvent event, String[] args) { + return null; + } +} diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 575658c..cf92c7f 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -61,7 +61,7 @@ public class DatabaseCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { //TODO: Clean up the mess event.getMessage().delete().queue(); @@ -69,26 +69,26 @@ public class DatabaseCommand extends AbstractCommand { if (!event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) return null; - if (countArgs(args) > 0) { - switch (parseArgs(args, 0)) { + if (args.length > 0) { + switch (args[0]) { case "message": - if (countArgs(args) > 1) { + if (args.length > 1) { - MMessage message = ((DBMessage) DBController.get("message")).getMessage(parseArgs(args, 1)); + MMessage message = ((DBMessage) DBController.get("message")).getMessage(args[1]); if (message != null) { EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.BLUE); embed.setTimestamp( DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT).parse(message.getDateSent())); - embed.setFooter("Guild : " + message.getServerName() + " | ID : " + message.getMessageId(), null); + embed.setFooter("Guild : " + message.getServerId() + " | ID : " + message.getMessageId(), null); embed.setDescription( "Message from " + message.getSender() + " on the channel " + message.getChannelName()); embed.addField("Message: ", "" + message.getMessage(), false); event.getTextChannel().sendMessage(embed.build()).queue(); } else { - User user = event.getJDA().getUserById(parseArgs(args, 1)); + User user = event.getJDA().getUserById(args[1]); if (user != null) { ArrayList messages = ((DBMessage) DBController.get("message")) .getMessagesFromUser(user.getName(), event.getGuild().getName(), 10); diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 9b9677a..26ff480 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -60,7 +60,7 @@ public class EvalMethod extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { if (event.getAuthor().getId().equals(Settings.getInstance().getCreator().getId())) { ScriptEngine se = new ScriptEngineManager().getEngineByName("Nashorn"); diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index 3ea3b70..19d7455 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -52,7 +52,7 @@ public class LoggingCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { return null; diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java index cd30092..5432075 100644 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ b/src/main/java/netneutrality/command/specific/SellyCommand.java @@ -60,7 +60,7 @@ public class SellyCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { String sellyEmail = ((DBSettings) DBController.get("settings")).getSettingsByKey("selly_email"); String sellyKey = ((DBSettings) DBController.get("settings")).getSettingsByKey(""); @@ -70,9 +70,9 @@ public class SellyCommand extends AbstractCommand { System.out.println(selly.getProducts().toString()); - if (countArgs(args) > 1) { - String email = parseArgs(args, 0); - String id = parseArgs(args, 1); + if (args.length > 1) { + String email = args[0]; + String id = args[1]; if (orders.containsKey(id)) { MSellyOrder order = orders.get(id); diff --git a/src/main/java/netneutrality/command/specific/ShutdownCommand.java b/src/main/java/netneutrality/command/specific/ShutdownCommand.java index 1c6432a..d053765 100644 --- a/src/main/java/netneutrality/command/specific/ShutdownCommand.java +++ b/src/main/java/netneutrality/command/specific/ShutdownCommand.java @@ -48,7 +48,7 @@ public class ShutdownCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { event.getJDA().shutdown(); System.exit(0); return null; diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index 076b24c..fffee93 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -15,10 +15,6 @@ import netneutrality.utils.Settings; public class TestCommand extends AbstractCommand { - public TestCommand() { - - } - @Override public boolean needAdmin() { return true; @@ -60,7 +56,7 @@ public class TestCommand extends AbstractCommand { } @Override - public String execute(MessageReceivedEvent event, String args) { + public String execute(MessageReceivedEvent event, String[] args) { if (event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) { MessageFunction.isStartingWithMention(event.getMessage()); } From 41cb8f4b8f78fbb96e5a4c5c6b6c385c77e8cdae Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 00:28:44 -0400 Subject: [PATCH 040/155] Refactored database access methods --- .../java/netneutrality/db/MysqlDatabase.java | 46 +++--------- .../netneutrality/db/controllers/DBGuild.java | 7 +- .../db/controllers/DBLogging.java | 40 ++--------- .../db/controllers/DBMessage.java | 33 +++------ .../netneutrality/db/models/MMessage.java | 71 +++---------------- .../netneutrality/handler/EditHandler.java | 5 +- .../handler/NewCommandListener.java | 3 +- .../handler/ServerJoinHandler.java | 6 +- 8 files changed, 52 insertions(+), 159 deletions(-) diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 1ab401f..a3be18d 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -62,9 +62,7 @@ public class MysqlDatabase { * @param query The SQL query to execute * @return {@link ResultSet} */ - public ResultSet query(String query) { - logger.debug("Query: " + query); - + protected ResultSet query(String query) { Statement stmt; try { stmt = connection.createStatement(); @@ -84,7 +82,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - public synchronized int update(String sql, Object... params) { + protected synchronized int update(String sql, Object... params) { return executeUpdate(sql, params); } @@ -96,7 +94,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - public synchronized int insert(String sql, Object... params) { + protected synchronized int insert(String sql, Object... params) { return executeUpdate(sql, params); } @@ -108,7 +106,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - public synchronized int delete(String sql, Object... params) { + protected synchronized int delete(String sql, Object... params) { return executeUpdate(sql, params); } @@ -139,7 +137,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} */ - public synchronized ResultSet prepareAndExecute(String sql, Object... params) { + protected synchronized ResultSet prepareAndExecute(String sql, Object... params) { try { PreparedStatement query = connection.prepareStatement(sql); @@ -212,7 +210,7 @@ public class MysqlDatabase { * @throws SQLException */ public void close() throws SQLException { - logger.info("Closing database..."); + System.out.println("Closing database..."); connection.close(); } @@ -250,8 +248,9 @@ public class MysqlDatabase { * @param rs The ResultSet returned by the SELECT query * @return a {@link MTableModel} with the appropriate column and rows */ - public static MTableModel convertToTableModel(ResultSet rs, String tableName) { + protected static MTableModel convertToTableModel(ResultSet rs, String tableName) { MTableModel table = new MTableModel(); + table.setName(tableName); try { ResultSetMetaData metadata = rs.getMetaData(); @@ -275,33 +274,4 @@ public class MysqlDatabase { return table; } - /** - * @param rs The ResultSet returned by the SELECT query - * @return a {@link MTableModel} with the appropriate column and rows - */ - public static MTableModel convertToTableModel(ResultSet rs) { - MTableModel table = new MTableModel(); - - try { - ResultSetMetaData metadata = rs.getMetaData(); - - for (int i = 1; i < metadata.getColumnCount() + 1; i++) { - table.addColumn(metadata.getColumnName(i)); - } - - while (rs.next()) { - MRowModel row = new MRowModel(); - for (int i = 0; i < metadata.getColumnCount(); i++) { - row.addColumnToRow(rs.getObject(i + 1)); - } - table.addRow(row); - } - - } catch (SQLException e) { - e.printStackTrace(); - } - - return table; - } - } diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java index 84edf01..cca67e1 100644 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -5,11 +5,16 @@ package netneutrality.db.controllers;/* * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.entities.Guild; import netneutrality.db.AbstractController; public class DBGuild extends AbstractController { - + public void insertGuildInDB(Guild g) { + if (!database.exists("guilds", "guild_id", g.getId())) { + database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), "0", null).blocking(); + } + } @Override public String getControllerName() { diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java index 41805f4..d7fc6b4 100644 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ b/src/main/java/netneutrality/db/controllers/DBLogging.java @@ -13,6 +13,7 @@ import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.db.AbstractController; import netneutrality.db.DBController; +import netneutrality.db.models.MTableModel; import netneutrality.handler.LogHandler; import java.sql.ResultSet; @@ -21,27 +22,9 @@ import java.util.function.Consumer; public class DBLogging extends AbstractController { - public void logGuild(Guild g) { - ThreadManager.getExecutor("db-action").submit(() -> { - if (!database.exists("guilds", "guild_id", g.getId())) { - database.insert("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), g.getName(), g.getOwner().getUser().getName()); - } - }); - } - public void getLoggingChannel(String serverId, Consumer success) { - - ThreadManager.getExecutor("db-action").submit(() -> { - TextChannel txt = null; - ResultSet rs = database.prepareAndExecute("SELECT channelId FROM logging WHERE serverId = ?", serverId); - - try { - if (rs.next()) { - txt = MusicBot.getJDA().getGuildById(serverId).getTextChannelById(rs.getString(1)); - } - } catch (SQLException e) { - e.printStackTrace(); - } + database.prepareAndExecuteAsync("SELECT channelId FROM logging WHERE serverId = ?", serverId).async((table) -> { + TextChannel txt = MusicBot.getJDA().getGuildById(serverId).getTextChannelById((String) table.getRow(0).get(0)); success.accept(txt); }); @@ -49,26 +32,17 @@ public class DBLogging extends AbstractController { } public void setupLog(String serverId, String channelId) { - database.insert("INSERT INTO logging VALUES(?,?,?)", serverId, channelId, true); + database.prepareAndExecuteAsync("INSERT INTO logging VALUES(?,?,?)", serverId, channelId, true).blocking(); } public void toggleLog(String serverId, String channelId) { - database.update("UPDATE logging SET enabled = NOT enabled"); + database.prepareAndExecuteAsync("UPDATE logging SET enabled = NOT enabled WHERE serverId = ? AND channelId = ?", serverId, channelId).blocking(); } public boolean isLoggingEnabled(String serverId, String channelId) { + MTableModel table = database.prepareAndExecuteAsync("SELECT enabled FROM logging WHERE serverId = ? AND channelId = ?", serverId, channelId).blocking(); - try { - ResultSet rs = database.prepareAndExecute("SELECT enabled FROM logging WHERE serverId = ? AND channelId = ?", serverId, channelId); - if (rs.next()) { - return rs.getBoolean(1); - } - - } catch (SQLException e) { - e.printStackTrace(); - } - - return false; + return Boolean.parseBoolean((String) table.getRow(0).get(0)); } @Override diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 7b32ec9..7386ac1 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -36,15 +36,14 @@ public class DBMessage extends AbstractController { } public void log(Guild guild, TextChannel channel, User author, Message message) { - String servername = guild.getId(); - String channelname = channel.getName(); - String username = author.getName(); + String serverid = guild.getId(); + String channelid = channel.getId(); + String userid = author.getId(); String datesent = message.getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT)); String messageid = message.getId(); String msg = message.getContentRaw().trim(); - database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageid, msg, null).async(); - + database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", serverid, channelid, userid, datesent, messageid, msg, null).async(); } public void logEdit(String messageId, String newMessage) { @@ -53,18 +52,16 @@ public class DBMessage extends AbstractController { } public MMessage getMessage(String messageId) { - ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE messageId = ?", messageId); - MTableModel table = MysqlDatabase.convertToTableModel(rs); + MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE messageId = ?", messageId).blocking(); if (table.getNbRows() > 0) { return new MMessage(table.getRowModel(0)); } - return null; } public void getMessagesFromUser(String username, String serverName, int max, Consumer> success) { - database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE userName = ? AND serverName = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).async(table -> { + database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE userId = ? AND serverId = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).async(table -> { ArrayList messages = new ArrayList<>(); if (table.getNbRows() > 0) { @@ -82,32 +79,20 @@ public class DBMessage extends AbstractController { public ArrayList getMessagesFromUser(String username, String serverName, int max) { ArrayList messages = new ArrayList<>(); - ResultSet rs = database.prepareAndExecute("SELECT * FROM log_message WHERE userName = ? AND serverName = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max); - MTableModel table = MysqlDatabase.convertToTableModel(rs); + MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE userId = ? AND serverId = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).blocking();; if (table.getNbRows() > 0) { for (int row = 0; row < max; row++) { messages.add(new MMessage(table.getRowModel(row))); } } - return messages; } public String getMessageString(String messageId) { + MTableModel table = database.prepareAndExecuteAsync("SELECT message FROM log_message WHERE messageId = ?", messageId).blocking(); - try { - ResultSet rs = database.prepareAndExecute("SELECT message FROM log_message WHERE messageId = ?", messageId); - if (rs.next()) { - return rs.getString(1); - } - - } catch (SQLException e) { - logger.error(e.getMessage()); - LogHandler.log(e); - } - - return "No message found"; + return (String) table.getRowModel(0).getItem(0); } diff --git a/src/main/java/netneutrality/db/models/MMessage.java b/src/main/java/netneutrality/db/models/MMessage.java index 251c323..c8a50a8 100644 --- a/src/main/java/netneutrality/db/models/MMessage.java +++ b/src/main/java/netneutrality/db/models/MMessage.java @@ -2,27 +2,16 @@ package netneutrality.db.models; public class MMessage { - private String serverName; - private String channelName; - private String sender; - private String dateSent; - private String messageId; - private String message; - private String editedMessage; - - public MMessage(String serverName, String channelName, String sender, String dateSent, String messageId, - String message) { - this.serverName = serverName; - this.channelName = channelName; - this.sender = sender; - this.dateSent = dateSent; - this.messageId = messageId; - this.message = message; - this.editedMessage = ""; - } + private final String serverId; + private final String channelName; + private final String sender; + private final String dateSent; + private final String messageId; + private final String message; + private final String editedMessage; public MMessage(MRowModel row) { - this.serverName = (String) row.getItem(0); + this.serverId = (String) row.getItem(0); this.channelName = (String) row.getItem(1); this.sender = (String) row.getItem(2); this.dateSent = (String) row.getItem(3); @@ -31,75 +20,37 @@ public class MMessage { this.editedMessage = ""; } - public MMessage(Object serverName, Object channelName, Object sender, Object dateSent, Object messageId, Object message) { - this.serverName = (String) serverName; - this.channelName = (String) channelName; - this.sender = (String) sender; - this.dateSent = (String) dateSent; - this.messageId = (String) messageId; - this.message = (String) message; - this.editedMessage = ""; - } - - public String getServerName() { - return serverName; - } - - public void setServerName(String serverName) { - this.serverName = serverName; + public String getServerId() { + return serverId; } public String getChannelName() { return channelName; } - public void setChannelName(String channelName) { - this.channelName = channelName; - } - public String getSender() { return sender; } - public void setSender(String sender) { - this.sender = sender; - } - public String getDateSent() { return dateSent; } - public void setDateSent(String dateSent) { - this.dateSent = dateSent; - } - public String getMessageId() { return messageId; } - public void setMessageId(String messageId) { - this.messageId = messageId; - } - public String getMessage() { return message; } - public void setMessage(String message) { - this.message = message; - } - public String getEditedMessage() { return editedMessage; } - public void setEditedMessage(String editedMessage) { - this.editedMessage = editedMessage; - } - @Override public String toString() { - return "MMessage [serverName=" + serverName + ", channelName=" + channelName + ", sender=" + sender + return "MMessage [serverName=" + serverId + ", channelName=" + channelName + ", sender=" + sender + ", dateSent=" + dateSent + ", messageId=" + messageId + ", message=" + message + ", editedMessage=" + editedMessage + "]"; } diff --git a/src/main/java/netneutrality/handler/EditHandler.java b/src/main/java/netneutrality/handler/EditHandler.java index ab81501..6a991cc 100644 --- a/src/main/java/netneutrality/handler/EditHandler.java +++ b/src/main/java/netneutrality/handler/EditHandler.java @@ -9,6 +9,7 @@ import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; import netneutrality.db.controllers.DBMessage; import netneutrality.db.controllers.DBSettings; +import netneutrality.db.models.MTableModel; public class EditHandler extends ListenerAdapter { @@ -17,7 +18,9 @@ public class EditHandler extends ListenerAdapter { if (event.getAuthor().isBot()) return; - Object logChannel = MysqlDatabase.convertToTableModel(DBController.get().prepareAndExecute("SELECT channelId FROM logging WHERE serverId = ? AND enabled = 1", event.getGuild().getId())).getRowModel(0).getItem(0); + MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channelId FROM logging WHERE serverId = ? AND enabled = 1", event.getGuild().getId()).blocking(); + + Object logChannel = table.getRowModel(0).getItem(0); if (logChannel != null) { String originalMessage = ((DBMessage) DBController.get("message")).getMessageString(event.getMessage().getId()); ((DBMessage) DBController.get("message")).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index fd86c05..df15bb9 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -50,6 +50,7 @@ public class NewCommandListener extends ListenerAdapter { if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()); String cmd = msg.split(" ", 2)[0]; + String[] args = msg.replaceFirst("(" + cmd + ")( )?", "").split(" "); if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { @@ -62,7 +63,7 @@ public class NewCommandListener extends ListenerAdapter { } } - c.execute(event, msg.replaceFirst("(" + cmd + ")( )?", "")); + c.execute(event, args); } } } else { diff --git a/src/main/java/netneutrality/handler/ServerJoinHandler.java b/src/main/java/netneutrality/handler/ServerJoinHandler.java index 7b33992..ccffa70 100644 --- a/src/main/java/netneutrality/handler/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/ServerJoinHandler.java @@ -9,13 +9,17 @@ package netneutrality.handler; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.db.DBController; +import netneutrality.db.controllers.DBGuild; import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { @Override public void onGuildJoin(@NotNull GuildJoinEvent event){ - + if (!DBController.get().exists("guilds", "guild_id", event.getGuild().getId())) { + ((DBGuild) DBController.get("guild")).insertGuildInDB(event.getGuild()); + } } From fd32bbee914eee52eb37e53891cd70cadf62ab82 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 00:34:39 -0400 Subject: [PATCH 041/155] Updated sql schema --- sql/netneutrality.sql | 94 ++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/sql/netneutrality.sql b/sql/netneutrality.sql index 69be13f..ba60239 100644 --- a/sql/netneutrality.sql +++ b/sql/netneutrality.sql @@ -1,7 +1,13 @@ --- Database for the bot +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: 127.0.0.1:3306 +-- Generation Time: Nov 07, 2021 at 04:31 AM +-- Server version: 10.4.10-MariaDB +-- PHP Version: 7.4.19 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -SET AUTOCOMMIT = 0; START TRANSACTION; SET time_zone = "+00:00"; @@ -12,43 +18,71 @@ SET time_zone = "+00:00"; /*!40101 SET NAMES utf8mb4 */; -- --- Base de données : `netneutrality` +-- Database: `netneutrality` -- -USE netneutrality; -- -------------------------------------------------------- -- --- Structure de la table `blacklist` +-- Table structure for table `blacklist` -- DROP TABLE IF EXISTS `blacklist`; CREATE TABLE IF NOT EXISTS `blacklist` ( `word` varchar(255) NOT NULL, `serverId` varchar(255) NOT NULL, - `isEnabled` tinyint(4) NOT NULL, + `isEnabled` tinyint(1) NOT NULL, `creatorId` varchar(255) NOT NULL, PRIMARY KEY (`word`,`serverId`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -------------------------------------------------------- -- --- Structure de la table `guilds` +-- Table structure for table `guilds` -- DROP TABLE IF EXISTS `guilds`; CREATE TABLE IF NOT EXISTS `guilds` ( `guild_id` varchar(255) NOT NULL, - `name` varchar(255) NOT NULL, - `owner` varchar(255) NOT NULL, + `logging` int(11) DEFAULT 0, + `logchannel` varchar(255) DEFAULT NULL, PRIMARY KEY (`guild_id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `guilds` +-- + +INSERT INTO `guilds` (`guild_id`, `logging`, `logchannel`) VALUES +('195386426400047105', 0, NULL); -- -------------------------------------------------------- -- --- Structure de la table `logging` +-- Table structure for table `guild_settings` +-- + +DROP TABLE IF EXISTS `guild_settings`; +CREATE TABLE IF NOT EXISTS `guild_settings` ( + `guild_id` varchar(255) NOT NULL, + `music_role` varchar(255) DEFAULT NULL, + `music_channel` varchar(255) DEFAULT NULL, + `blacklist_exclude_channels` text DEFAULT NULL, + PRIMARY KEY (`guild_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `guild_settings` +-- + +INSERT INTO `guild_settings` (`guild_id`, `music_role`, `music_channel`, `blacklist_exclude_channels`) VALUES +('195386426400047105', NULL, NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `logging` -- DROP TABLE IF EXISTS `logging`; @@ -57,19 +91,19 @@ CREATE TABLE IF NOT EXISTS `logging` ( `channelId` varchar(255) NOT NULL, `enabled` tinyint(4) NOT NULL, PRIMARY KEY (`serverId`,`channelId`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -------------------------------------------------------- -- --- Structure de la table `log_message` +-- Table structure for table `log_message` -- DROP TABLE IF EXISTS `log_message`; CREATE TABLE IF NOT EXISTS `log_message` ( - `serverName` varchar(255) NOT NULL, - `channelName` varchar(255) NOT NULL, - `userName` varchar(255) NOT NULL, + `serverId` varchar(255) NOT NULL, + `channelId` varchar(255) NOT NULL, + `userId` varchar(255) NOT NULL, `dateSent` varchar(255) NOT NULL, `messageId` varchar(255) NOT NULL, `message` varchar(2000) DEFAULT NULL, @@ -80,15 +114,27 @@ CREATE TABLE IF NOT EXISTS `log_message` ( -- -------------------------------------------------------- -- --- Structure de la table `settings` +-- Table structure for table `permissions` -- -DROP TABLE IF EXISTS `settings`; -CREATE TABLE IF NOT EXISTS `settings` ( - `skey` varchar(60) NOT NULL, - `value` varchar(2048) NOT NULL, - PRIMARY KEY (`skey`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `permissions`; +CREATE TABLE IF NOT EXISTS `permissions` ( + `guild_id` varchar(255) NOT NULL, + `role_id` varchar(255) NOT NULL, + `type` int(11) DEFAULT NULL, + `command` int(11) DEFAULT NULL, + PRIMARY KEY (`guild_id`,`role_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `guild_settings` +-- +ALTER TABLE `guild_settings` + ADD CONSTRAINT `fk_guildid_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); COMMIT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; From a5f68511628dd8d1f26d63dea24811c9dcf39e14 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 08:57:55 -0500 Subject: [PATCH 042/155] Refactored mysql connector --- .../java/netneutrality/db/MysqlConnector.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index 9a33dc2..d8f0063 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -1,8 +1,7 @@ package netneutrality.db; -import com.mysql.cj.jdbc.MysqlDataSource; - import java.sql.Connection; +import java.sql.DriverManager; import java.sql.SQLException; public class MysqlConnector { @@ -26,16 +25,13 @@ public class MysqlConnector { * @return {@link MysqlConnector} */ public MysqlConnector connect() throws SQLException { - MysqlDataSource dataSource = new MysqlDataSource(); - dataSource.setUser(dbUser); - dataSource.setPassword(dbPass); - dataSource.setServerName(dbHost); - dataSource.setPort(3306); - dataSource.setDatabaseName(dbName); - dataSource.setAutoReconnect(true); - dataSource.setConnectTimeout(5000); - c = dataSource.getConnection(); - + try { + Class.forName("com.mysql.jdbc.Driver"); + c = DriverManager.getConnection("jdbc:mysql://" + dbHost + ":3306/" + dbName, dbUser, dbPass); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return this; } From 4036a7ddeaeb9f3062fdc5b32ba1d72c0068862e Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 09:09:36 -0500 Subject: [PATCH 043/155] Oopsy --- src/main/java/netneutrality/db/MysqlConnector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index d8f0063..92c7676 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -26,12 +26,12 @@ public class MysqlConnector { */ public MysqlConnector connect() throws SQLException { try { - Class.forName("com.mysql.jdbc.Driver"); + Class.forName("com.mysql.cj.jdbc.Driver"); c = DriverManager.getConnection("jdbc:mysql://" + dbHost + ":3306/" + dbName, dbUser, dbPass); } catch (ClassNotFoundException e) { e.printStackTrace(); } - + return this; } From 9aa8f3da752a4b76d49198267a12e31ca84d27b9 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 10:22:29 -0500 Subject: [PATCH 044/155] Basic permission for music commands --- .../command/AbstractCommand.java | 7 ++++ .../command/AbstractMusicCommand.java | 32 +++++++++++++++++++ .../java/netneutrality/command/ICommand.java | 4 +++ .../command/music/BitconnectCommand.java | 10 ++---- .../command/music/DeleteQueueCommand.java | 10 ++---- .../command/music/JoinCommand.java | 10 ++---- .../command/music/LeaveCommand.java | 10 ++---- .../command/music/PlayCommand.java | 10 ++---- .../command/music/SkipCommand.java | 10 ++---- .../command/music/StopCommand.java | 10 ++---- .../command/music/VolumeCommand.java | 10 ++---- .../command/music/VoteSkipCommand.java | 10 ++---- 12 files changed, 61 insertions(+), 72 deletions(-) create mode 100644 src/main/java/netneutrality/command/AbstractMusicCommand.java diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 76c1eec..96e98f8 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -1,5 +1,8 @@ package netneutrality.command; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; + public abstract class AbstractCommand implements ICommand { /** @@ -32,4 +35,8 @@ public abstract class AbstractCommand implements ICommand { public abstract CommandType getType(); + @Override + public boolean canBeExecutedBy(Guild guild, Member member) { + return true; + } } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java new file mode 100644 index 0000000..b4f8ea5 --- /dev/null +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -0,0 +1,32 @@ +package netneutrality.command;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import netneutrality.GuildManager; +import netneutrality.MusicBot; + +public abstract class AbstractMusicCommand extends AbstractCommand { + + @Override + public CommandType getType() { + return CommandType.MUSIC; + } + + @Override + public boolean canBeExecutedBy(Guild guild, Member member) { + String roleDb = GuildManager.getManager(guild).getSetting("music_role"); + + if (!roleDb.isEmpty()) { + Role neededRole = MusicBot.getJDA().getRoleById(roleDb); + return member.getRoles().contains(neededRole); + } + + return false; + } +} diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 21b7013..73ad158 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -5,6 +5,8 @@ package netneutrality.command;/* * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; public interface ICommand { @@ -13,4 +15,6 @@ public interface ICommand { * @param args the arguments to the command */ String execute(MessageReceivedEvent event, String[] args); + + boolean canBeExecutedBy(Guild guild, Member member); } diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 969ddd7..0286bce 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class BitconnectCommand extends AbstractCommand { +public class BitconnectCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class BitconnectCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index ce8f8a2..b21cc43 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class DeleteQueueCommand extends AbstractCommand { +public class DeleteQueueCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class DeleteQueueCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 9a64153..92dffce 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class JoinCommand extends AbstractCommand { +public class JoinCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class JoinCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 10786c2..7b2c512 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class LeaveCommand extends AbstractCommand { +public class LeaveCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class LeaveCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 7d85dd0..fae599a 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class PlayCommand extends AbstractCommand { +public class PlayCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class PlayCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 8c48bdf..914c981 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class SkipCommand extends AbstractCommand { +public class SkipCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class SkipCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 2fea9b3..4db372b 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class StopCommand extends AbstractCommand { +public class StopCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class StopCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index aa6daa8..843e056 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -9,12 +9,11 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; import netneutrality.music.MusicManager; -public class VolumeCommand extends AbstractCommand { +public class VolumeCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return true; @@ -50,11 +49,6 @@ public class VolumeCommand extends AbstractCommand { return Visibility.CHANNEL; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index ca36281..b33db0e 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -6,11 +6,10 @@ package netneutrality.command.music;/* */ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; +import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; -public class VoteSkipCommand extends AbstractCommand { +public class VoteSkipCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { return false; @@ -46,11 +45,6 @@ public class VoteSkipCommand extends AbstractCommand { return null; } - @Override - public CommandType getType() { - return null; - } - @Override public String execute(MessageReceivedEvent event, String[] args) { return null; From 325aa1df7737f2d6060067d2c9234e3fe73b0b9d Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 10:22:54 -0500 Subject: [PATCH 045/155] Fix oopsy v2 --- src/main/java/netneutrality/utils/Settings.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 567ef8b..6aec4d6 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -69,15 +69,15 @@ public class Settings { public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; public User getCreator() { - return MusicBot.getJDA().getUserById(get("bot.owner")); + return MusicBot.getJDA().getUserById(get("BOT_OWNER")); } public Guild getOwnerGuild() { - return MusicBot.getJDA().getGuildById(get("bot.ownerguild")); + return MusicBot.getJDA().getGuildById(get("BOT_OWNERGUILD")); } public TextChannel getLogChannel() { - return MusicBot.getJDA().getTextChannelById(get("bot.errorchannel")); + return MusicBot.getJDA().getTextChannelById(get("BOT_ERRORCHANNEL")); } From 9902a3c9134f59a0732579740052bb79756adcf3 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 7 Nov 2021 10:23:19 -0500 Subject: [PATCH 046/155] refactored code --- src/main/java/netneutrality/MusicBot.java | 10 ---------- src/main/java/netneutrality/db/MysqlConnector.java | 4 +++- .../java/netneutrality/db/controllers/DBGuild.java | 1 + .../java/netneutrality/handler/NewCommandListener.java | 5 ++++- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index b734615..cc11e06 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -56,16 +56,6 @@ public class MusicBot { MusicBot.shutdown(); })); - ConsoleHandler consoleInput = new ConsoleHandler(); - - switch (consoleInput.init()) { - - case "quit": - System.exit(0); - break; - - } - } public static void shutdown() { diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index 92c7676..ced5beb 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -25,9 +25,11 @@ public class MysqlConnector { * @return {@link MysqlConnector} */ public MysqlConnector connect() throws SQLException { + String jdbc = "jdbc:mysql://" + dbHost + ":3306/" + dbName; + try { Class.forName("com.mysql.cj.jdbc.Driver"); - c = DriverManager.getConnection("jdbc:mysql://" + dbHost + ":3306/" + dbName, dbUser, dbPass); + c = DriverManager.getConnection(jdbc, dbUser, dbPass); } catch (ClassNotFoundException e) { e.printStackTrace(); } diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java index cca67e1..8e946d9 100644 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -13,6 +13,7 @@ public class DBGuild extends AbstractController { public void insertGuildInDB(Guild g) { if (!database.exists("guilds", "guild_id", g.getId())) { database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), "0", null).blocking(); + database.prepareAndExecuteAsync("INSERT INTO guild_settings VALUES(?)", g.getId()).blocking(); } } diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index df15bb9..75ad125 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -63,7 +63,10 @@ public class NewCommandListener extends ListenerAdapter { } } - c.execute(event, args); + if (c.canBeExecutedBy(event.getGuild(), event.getMember())) { + c.execute(event, args); + } + } } } else { From 94980bf41992c476cb249570a9f19e6acc8e98c6 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 4 Jan 2022 16:57:44 -0500 Subject: [PATCH 047/155] Modify DB scheme and update dependencies --- pom.xml | 16 +- sql/netneutrality_new.sql | 183 ++++++++++++++++++ src/main/java/netneutrality/GuildManager.java | 1 + .../command/AbstractMusicCommand.java | 3 +- .../db/controllers/DBBlacklist.java | 25 +-- .../netneutrality/db/controllers/DBGuild.java | 1 - .../db/controllers/DBMessage.java | 21 +- .../http/server/AbstractHandler.java | 33 ++++ .../http/server/ActionHandler.java | 18 +- .../http/server/GuildBrowser.java | 58 ------ .../http/server/GuildHandler.java | 47 +++++ .../http/server/RootHandler.java | 14 +- .../netneutrality/http/server/WebApi.java | 16 +- .../netneutrality/music/TrackScheduler.java | 12 +- 14 files changed, 324 insertions(+), 124 deletions(-) create mode 100644 sql/netneutrality_new.sql create mode 100644 src/main/java/netneutrality/http/server/AbstractHandler.java delete mode 100644 src/main/java/netneutrality/http/server/GuildBrowser.java create mode 100644 src/main/java/netneutrality/http/server/GuildHandler.java diff --git a/pom.xml b/pom.xml index e7f8810..2de176b 100644 --- a/pom.xml +++ b/pom.xml @@ -91,13 +91,13 @@ net.dv8tion JDA - 4.3.0_277 + 4.4.0_350 com.squareup.okhttp3 okhttp - 4.9.1 + 4.9.3 @@ -111,7 +111,7 @@ org.reflections reflections - 0.9.12 + 0.10.2 @@ -122,17 +122,17 @@ org.apache.logging.log4j log4j-api - 2.14.1 + 2.17.0 org.apache.logging.log4j log4j-core - 2.14.1 + 2.17.0 org.apache.logging.log4j log4j-slf4j-impl - 2.14.1 + 2.17.0 commons-logging @@ -143,13 +143,13 @@ org.fusesource.jansi jansi - 2.3.4 + 2.4.0 runtime com.sedmelluq lavaplayer - 1.3.77 + 1.3.78 junit diff --git a/sql/netneutrality_new.sql b/sql/netneutrality_new.sql new file mode 100644 index 0000000..0f23fb3 --- /dev/null +++ b/sql/netneutrality_new.sql @@ -0,0 +1,183 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: 127.0.0.1:3306 +-- Generation Time: Jan 04, 2022 at 09:55 PM +-- Server version: 10.4.10-MariaDB +-- PHP Version: 7.4.19 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `netneutrality` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `blacklist` +-- + +DROP TABLE IF EXISTS `blacklist`; +CREATE TABLE IF NOT EXISTS `blacklist` ( + `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `word` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `enabled` tinyint(1) NOT NULL, + `creator_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`guild_id`,`word`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `guilds` +-- + +DROP TABLE IF EXISTS `guilds`; +CREATE TABLE IF NOT EXISTS `guilds` ( + `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `logging` int(11) DEFAULT 0, + `log_channel` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`guild_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `guilds` +-- + +INSERT INTO `guilds` (`guild_id`, `logging`, `log_channel`) VALUES +('195386426400047105', 0, NULL), +('250767028397408256', 0, NULL); + +-- +-- Triggers `guilds` +-- +DROP TRIGGER IF EXISTS `insert_settings`; +DELIMITER $$ +CREATE TRIGGER `insert_settings` AFTER INSERT ON `guilds` FOR EACH ROW INSERT INTO guild_settings(guild_id) VALUES (new.guild_id) +$$ +DELIMITER ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `guild_settings` +-- + +DROP TABLE IF EXISTS `guild_settings`; +CREATE TABLE IF NOT EXISTS `guild_settings` ( + `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `music_role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `music_channel` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `blacklist_exclude_channels` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`guild_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `guild_settings` +-- + +INSERT INTO `guild_settings` (`guild_id`, `music_role`, `music_channel`, `blacklist_exclude_channels`) VALUES +('195386426400047105', NULL, NULL, NULL), +('250767028397408256', NULL, NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `logging` +-- + +DROP TABLE IF EXISTS `logging`; +CREATE TABLE IF NOT EXISTS `logging` ( + `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `channel_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `enabled` tinyint(4) NOT NULL, + PRIMARY KEY (`guild_id`,`channel_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `log_message` +-- + +DROP TABLE IF EXISTS `log_message`; +CREATE TABLE IF NOT EXISTS `log_message` ( + `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `channel_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `date_sent` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + `message_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `message` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `edited_message` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`message_id`), + KEY `fk_log_guilds` (`guild_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `permissions` +-- + +DROP TABLE IF EXISTS `permissions`; +CREATE TABLE IF NOT EXISTS `permissions` ( + `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `role_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `type` int(11) DEFAULT NULL, + `command` int(11) DEFAULT NULL, + PRIMARY KEY (`guild_id`,`role_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `web_users` +-- + +DROP TABLE IF EXISTS `web_users`; +CREATE TABLE IF NOT EXISTS `web_users` ( + `id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `email` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `expires` timestamp NOT NULL DEFAULT current_timestamp(), + `refresh_token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `blacklist` +-- +ALTER TABLE `blacklist` + ADD CONSTRAINT `fk_blacklist_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); + +-- +-- Constraints for table `guild_settings` +-- +ALTER TABLE `guild_settings` + ADD CONSTRAINT `fk_guildid_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); + +-- +-- Constraints for table `log_message` +-- +ALTER TABLE `log_message` + ADD CONSTRAINT `fk_log_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 2824f91..0429cb2 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -42,6 +42,7 @@ public class GuildManager { } public String getSetting(String key) { + reloadSettings(); return guildEntity.getSettings().getSettingByKey(key); } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index b4f8ea5..7afcb52 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -20,7 +20,8 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting("music_role"); + String roleDb = GuildManager.getManager(guild).getSetting("music.role"); + System.out.println(roleDb); if (!roleDb.isEmpty()) { Role neededRole = MusicBot.getJDA().getRoleById(roleDb); diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index fc6c757..c78d662 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -1,7 +1,6 @@ package netneutrality.db.controllers; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; @@ -15,14 +14,10 @@ public class DBBlacklist extends AbstractController { private final Logger logger = LoggerFactory.getLogger(DBBlacklist.class); - public DBBlacklist() { - - } - public void add(MBlacklist obj, Consumer success) { isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> { if (blacklisted == 0) { - database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()).async(); + database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getServerId(), obj.getWord(), obj.isEnabled(), obj.getCreatorId()).async(); success.accept(true); } else { success.accept(false); @@ -34,7 +29,7 @@ public class DBBlacklist extends AbstractController { public void delete(String word, String serverId, Consumer success) { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { - database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(); + database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(); logger.debug("removed word from blacklist"); success.accept(true); } else { @@ -49,7 +44,7 @@ public class DBBlacklist extends AbstractController { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { - database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId).async(); + database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 1 WHERE word = ? AND guild_id = ?", word, serverId).async(); logger.info("enabled"); success.accept(true); } else { @@ -64,7 +59,7 @@ public class DBBlacklist extends AbstractController { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { - database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId).async(); + database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 0 WHERE word = ? AND guild_id = ?", word, serverId).async(); logger.info("disabled"); success.accept(true); } else { @@ -78,7 +73,7 @@ public class DBBlacklist extends AbstractController { @Deprecated public void getBlacklistForWord(String word, String serverId, Consumer success) { - database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async((table -> { + database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async((table -> { MBlacklist blacklisted = null; if (table.getNbRows() > 0) { @@ -91,7 +86,7 @@ public class DBBlacklist extends AbstractController { } public void getBlacklistFromServer(String serverId, Consumer> success) { - database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> { + database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE guild_id = ? AND enabled = 1", serverId).async(model -> { ArrayList output = new ArrayList<>(); if (model.getNbRows() > 0) { @@ -108,9 +103,9 @@ public class DBBlacklist extends AbstractController { } @Deprecated - public ArrayList getBlacklistFromServer(String serverId) throws ExecutionException, InterruptedException { + public ArrayList getBlacklistFromServer(String serverId) { - MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).blocking(); + MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE guild_id = ? AND enabled = 1", serverId).blocking(); ArrayList output = new ArrayList<>(); if (model.getNbRows() > 0) { @@ -128,7 +123,7 @@ public class DBBlacklist extends AbstractController { private boolean isAlreadyBlacklisted(String word, String serverId) { AtomicBoolean result = new AtomicBoolean(); - database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> { + database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(table -> { if (!table.isEmpty()) { result.set((int) table.getRowModel(0).getItem(0) != 0); } @@ -140,7 +135,7 @@ public class DBBlacklist extends AbstractController { private void isAlreadyBlacklisted(String word, String serverId, Consumer result) { - database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> { + database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(table -> { if (!table.isEmpty()) { int count = Integer.parseInt(table.getRowModel(0).getItem(0).toString()); diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java index 8e946d9..cca67e1 100644 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -13,7 +13,6 @@ public class DBGuild extends AbstractController { public void insertGuildInDB(Guild g) { if (!database.exists("guilds", "guild_id", g.getId())) { database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), "0", null).blocking(); - database.prepareAndExecuteAsync("INSERT INTO guild_settings VALUES(?)", g.getId()).blocking(); } } diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 7386ac1..2988246 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -1,9 +1,7 @@ package netneutrality.db.controllers; -import java.sql.SQLException; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.sql.ResultSet; +import java.util.Date; import java.util.function.Consumer; import net.dv8tion.jda.api.entities.Guild; @@ -15,16 +13,13 @@ import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MMessage; import netneutrality.db.models.MTableModel; -import netneutrality.handler.LogHandler; -import netneutrality.utils.Settings; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DBMessage extends AbstractController { private final static Logger logger = LoggerFactory.getLogger(DBMessage.class); - public DBMessage() { - } /** * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class @@ -39,7 +34,7 @@ public class DBMessage extends AbstractController { String serverid = guild.getId(); String channelid = channel.getId(); String userid = author.getId(); - String datesent = message.getTimeCreated().format(DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT)); + Date datesent = new Date(message.getTimeCreated().toInstant().toEpochMilli()); String messageid = message.getId(); String msg = message.getContentRaw().trim(); @@ -47,12 +42,12 @@ public class DBMessage extends AbstractController { } public void logEdit(String messageId, String newMessage) { - database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async(); + database.prepareAndExecuteAsync("UPDATE log_message SET edited_message = ? WHERE message_id = ?", newMessage, messageId).async(); } public MMessage getMessage(String messageId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE messageId = ?", messageId).blocking(); + MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE message_id = ?", messageId).blocking(); if (table.getNbRows() > 0) { return new MMessage(table.getRowModel(0)); } @@ -61,7 +56,7 @@ public class DBMessage extends AbstractController { } public void getMessagesFromUser(String username, String serverName, int max, Consumer> success) { - database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE userId = ? AND serverId = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).async(table -> { + database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE user_id = ? AND server_id = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).async(table -> { ArrayList messages = new ArrayList<>(); if (table.getNbRows() > 0) { @@ -79,7 +74,7 @@ public class DBMessage extends AbstractController { public ArrayList getMessagesFromUser(String username, String serverName, int max) { ArrayList messages = new ArrayList<>(); - MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE userId = ? AND serverId = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).blocking();; + MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE user_id = ? AND server_id = ? ORDER BY date_sent DESC LIMIT ?", username, serverName, max).blocking();; if (table.getNbRows() > 0) { for (int row = 0; row < max; row++) { messages.add(new MMessage(table.getRowModel(row))); @@ -90,7 +85,7 @@ public class DBMessage extends AbstractController { } public String getMessageString(String messageId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT message FROM log_message WHERE messageId = ?", messageId).blocking(); + MTableModel table = database.prepareAndExecuteAsync("SELECT message FROM log_message WHERE message_id = ?", messageId).blocking(); return (String) table.getRowModel(0).getItem(0); } diff --git a/src/main/java/netneutrality/http/server/AbstractHandler.java b/src/main/java/netneutrality/http/server/AbstractHandler.java new file mode 100644 index 0000000..3fe8581 --- /dev/null +++ b/src/main/java/netneutrality/http/server/AbstractHandler.java @@ -0,0 +1,33 @@ +package netneutrality.http.server;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import java.io.IOException; +import java.io.OutputStream; + +public abstract class AbstractHandler implements HttpHandler { + + public abstract void handle(HttpExchange exchange) throws IOException; + + public void sendStringResponse(HttpExchange exchange, String str) throws IOException { + exchange.sendResponseHeaders(200, str.length()); + OutputStream os = exchange.getResponseBody(); + os.write(str.getBytes()); + os.close(); + } + + public void sendJsonResponse(HttpExchange exchange, String str) throws IOException { + exchange.getResponseHeaders().add("Content-Type", "application/json"); + exchange.sendResponseHeaders(200, str.length()); + OutputStream os = exchange.getResponseBody(); + os.write(str.getBytes()); + os.close(); + } +} diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 5d99f42..fc77d85 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -8,12 +8,15 @@ package netneutrality.http.server;/* import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import netneutrality.MusicBot; +import netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; import java.io.IOException; import java.io.OutputStream; +import java.util.Map; +import java.util.TreeMap; -public class ActionHandler implements HttpHandler { +public class ActionHandler extends AbstractHandler { @Override public void handle(HttpExchange exchange) throws IOException { @@ -21,12 +24,21 @@ public class ActionHandler implements HttpHandler { if (path.equals("/actions/shutdown")) { LogManager.getLogger(MusicBot.class).info("Request to shutdown received"); - WebApi.sendStringResponse(exchange, "Shutting down.."); + sendStringResponse(exchange, "Shutting down.."); System.exit(0); return; } - WebApi.sendStringResponse(exchange, path); + if (path.equals("/actions/status")) { + TreeMap json = new TreeMap<>(); + json.put("health", String.valueOf(MusicBot.getJDA().getStatus())); + json.put("ping", String.valueOf(MusicBot.getJDA().getGatewayPing())); + + sendJsonResponse(exchange, WebModule.createJson(json)); + return; + } + + sendStringResponse(exchange, path); } } diff --git a/src/main/java/netneutrality/http/server/GuildBrowser.java b/src/main/java/netneutrality/http/server/GuildBrowser.java deleted file mode 100644 index 06e7d02..0000000 --- a/src/main/java/netneutrality/http/server/GuildBrowser.java +++ /dev/null @@ -1,58 +0,0 @@ -package netneutrality.http.server; - -/* - * Copyright (c) anthorob - * - * This file is closed-source. It should not be distributed or copied in any way or form - */ - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import netneutrality.MusicBot; -import netneutrality.http.WebModule; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.TreeMap; - -public class GuildBrowser implements HttpHandler { - - @Override - public void handle(HttpExchange he) throws IOException { - - - String url[] = he.getRequestURI().toString().split("/"); - StringBuilder response = new StringBuilder(); - String json; - - if (url.length > 2) { - TreeMap users = new TreeMap<>(); - for (Guild guild : MusicBot.getJDA().getGuilds()) { - if (guild.getName().equalsIgnoreCase(url[2])) { - for (Member member : guild.getMembers()) { - users.put(member.getUser().getName(), member.getEffectiveName()); - } - } - } - - json = WebModule.createJsonArray(users); - - } else { - for (Guild guild : MusicBot.getJDA().getGuilds()) { - response.append("\"" + guild.getName() + "\""); - response.append(","); - } - response.insert(0, "["); - - json = response.substring(0, response.length() - 1) + "]"; - } - - he.getResponseHeaders().add("Content-Type", "application/json"); - he.sendResponseHeaders(200, json.getBytes().length); - OutputStream os = he.getResponseBody(); - os.write(json.getBytes()); - os.close(); - } -} diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/netneutrality/http/server/GuildHandler.java new file mode 100644 index 0000000..525684b --- /dev/null +++ b/src/main/java/netneutrality/http/server/GuildHandler.java @@ -0,0 +1,47 @@ +package netneutrality.http.server; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import netneutrality.MusicBot; +import netneutrality.http.WebModule; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.*; + +public class GuildHandler extends AbstractHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + + String path = exchange.getRequestURI().getRawPath(); + + if (path.equals("/guilds/owner")) { + + TreeMap owners = new TreeMap<>(); + + JDA jda = MusicBot.getJDA(); + + jda.getGuilds().forEach(guild -> { + owners.put(guild.getId(), guild.getOwnerId()); + }); + + sendJsonResponse(exchange, WebModule.createJsonArray(owners)); + return; + + } + + sendStringResponse(exchange, path); + + } +} diff --git a/src/main/java/netneutrality/http/server/RootHandler.java b/src/main/java/netneutrality/http/server/RootHandler.java index 177c3a3..cee2056 100644 --- a/src/main/java/netneutrality/http/server/RootHandler.java +++ b/src/main/java/netneutrality/http/server/RootHandler.java @@ -3,7 +3,8 @@ package netneutrality.http.server; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import com.sun.net.httpserver.HttpExchange; @@ -12,14 +13,13 @@ import com.sun.net.httpserver.HttpHandler; import java.io.IOException; import java.io.OutputStream; -public class RootHandler implements HttpHandler { +public class RootHandler extends AbstractHandler { @Override - public void handle(HttpExchange he) throws IOException { + public void handle(HttpExchange exchange) throws IOException { + String response = "

Server start success if you see this message

"; - he.sendResponseHeaders(200, response.length()); - OutputStream os = he.getResponseBody(); - os.write(response.getBytes()); - os.close(); + + sendStringResponse(exchange, response); } } diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index dd1f128..13da7b1 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -3,17 +3,16 @@ package netneutrality.http.server; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; import netneutrality.thread.BaseThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; @@ -36,22 +35,15 @@ public class WebApi { } catch (IOException e) { e.printStackTrace(); } + server.createContext("/", new RootHandler()); server.createContext("/actions", new ActionHandler()); - server.createContext("/guild", new GuildBrowser()); + server.createContext("/guilds", new GuildHandler()); server.setExecutor(executor); server.start(); logger.info("Web server started at [" + server.getAddress() + "]"); } - public static void sendStringResponse(HttpExchange exchange, String str) throws IOException { - exchange.sendResponseHeaders(200, str.length()); - OutputStream os = exchange.getResponseBody(); - os.write(str.getBytes()); - os.close(); - } - - } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index cc9d1e7..81cc068 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -33,7 +33,7 @@ public class TrackScheduler extends AudioEventAdapter { // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. boolean start = player.startTrack(track, true); - channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); + //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); if (!start) { queue.offer(track); @@ -55,7 +55,7 @@ public class TrackScheduler extends AudioEventAdapter { public void resetTopic() { if (this.channel != null) { - this.channel.getManager().setTopic(this.topic).queue(); + //this.channel.getManager().setTopic(this.topic).queue(); } this.topic = ""; @@ -69,10 +69,10 @@ public class TrackScheduler extends AudioEventAdapter { // giving null to startTrack, which is a valid argument and will simply stop the player. AudioTrack track = queue.poll(); if (track != null) { - channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); + //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); player.startTrack(track, false); } else { - channel.getManager().setTopic(topic).queue(); + //channel.getManager().setTopic(topic).queue(); } @@ -109,11 +109,11 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { - // An already playing track threw an exception (track end event will still be received separately) + channel.sendMessage("Error while playing track: " + track.getInfo().title).queue(); } @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { - // Audio track has been unable to provide us any audio, might want to just start a new track + nextTrack(); } } From 390e2c3163d6f36963918f2f9a91144e414b3362 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 4 Jan 2022 17:53:48 -0500 Subject: [PATCH 048/155] Fix arguments length and switch to java 17 --- pom.xml | 8 +++++--- src/main/java/netneutrality/MusicBot.java | 1 - .../java/netneutrality/command/AbstractMusicCommand.java | 2 +- .../java/netneutrality/command/basic/PingCommand.java | 3 +-- .../java/netneutrality/command/music/JoinCommand.java | 3 ++- .../java/netneutrality/handler/NewCommandListener.java | 9 +++++---- .../handler/ratelimiter/MessageRateLimiterImpl.java | 1 - 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 2de176b..9119b8e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ jar - 11 + 17 UTF-8 @@ -21,9 +21,11 @@ maven-compiler-plugin 3.8.0 - 11 + 17 UTF-8 - + 17 + 17 +
diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index cc11e06..d784a11 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.db.DBController; -import netneutrality.handler.ConsoleHandler; import netneutrality.handler.EditHandler; import netneutrality.handler.NewCommandListener; import netneutrality.http.server.WebApi; diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 7afcb52..3e89bdf 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -28,6 +28,6 @@ public abstract class AbstractMusicCommand extends AbstractCommand { return member.getRoles().contains(neededRole); } - return false; + return true; } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 1ded4c0..42e2027 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -12,9 +12,8 @@ public class PingCommand extends AbstractCommand { public String execute(MessageReceivedEvent event, String[] args) { if (args.length == 0) event.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); - + return null; - } @Override diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 92dffce..c85555c 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -52,8 +52,9 @@ public class JoinCommand extends AbstractMusicCommand { @Override public String execute(MessageReceivedEvent event, String[] args) { Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); + if (member.getVoiceState().inVoiceChannel()) { + MusicManager player = MusicManager.get(event.getGuild()); VoiceChannel vChannel = member.getVoiceState().getChannel(); if (!player.isConnected()) { diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java index 75ad125..b150b2e 100644 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ b/src/main/java/netneutrality/handler/NewCommandListener.java @@ -48,12 +48,14 @@ public class NewCommandListener extends ListenerAdapter { String msg = message.getContentDisplay().trim(); if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()); + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); String cmd = msg.split(" ", 2)[0]; - String[] args = msg.replaceFirst("(" + cmd + ")( )?", "").split(" "); + String[] args = msg.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); + + if (args.length == 1 && args[0].isEmpty()) + args = new String[0]; if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { - AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); if (Visibility.check(event.getChannel(), c.getVisibility())) { @@ -66,7 +68,6 @@ public class NewCommandListener extends ListenerAdapter { if (c.canBeExecutedBy(event.getGuild(), event.getMember())) { c.execute(event, args); } - } } } else { diff --git a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java index 6a4bdbf..277c09d 100644 --- a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java +++ b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java @@ -15,7 +15,6 @@ package netneutrality.handler.ratelimiter;/* import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.handler.ratelimiter.IMessageRateLimiter; import java.time.OffsetDateTime; From 4ca4fa7dba55a7cab5aa49537c5624ae9e50145f Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 4 Jan 2022 18:00:06 -0500 Subject: [PATCH 049/155] Add debug --- src/main/java/netneutrality/db/MysqlDatabase.java | 5 +++-- src/main/java/netneutrality/db/controllers/DBLogging.java | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index a3be18d..ba7aab7 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -135,9 +135,10 @@ public class MysqlDatabase { * * @param sql The SQL query to execute * @param params The parameters to include in the query - * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} + * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet, String)} */ protected synchronized ResultSet prepareAndExecute(String sql, Object... params) { + logger.debug(sql); try { PreparedStatement query = connection.prepareStatement(sql); @@ -157,7 +158,7 @@ public class MysqlDatabase { * * @param sql The SQL query to execute * @param params The parameters to include in the query - * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} + * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet, String)} */ public AsyncMySqlAction prepareAndExecuteAsync(String sql, Object... params) { return new AsyncMySqlAction(this, sql, params); diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java index d7fc6b4..f874553 100644 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ b/src/main/java/netneutrality/db/controllers/DBLogging.java @@ -23,7 +23,7 @@ import java.util.function.Consumer; public class DBLogging extends AbstractController { public void getLoggingChannel(String serverId, Consumer success) { - database.prepareAndExecuteAsync("SELECT channelId FROM logging WHERE serverId = ?", serverId).async((table) -> { + database.prepareAndExecuteAsync("SELECT channelId FROM logging WHERE guild_id = ?", serverId).async((table) -> { TextChannel txt = MusicBot.getJDA().getGuildById(serverId).getTextChannelById((String) table.getRow(0).get(0)); success.accept(txt); @@ -36,11 +36,11 @@ public class DBLogging extends AbstractController { } public void toggleLog(String serverId, String channelId) { - database.prepareAndExecuteAsync("UPDATE logging SET enabled = NOT enabled WHERE serverId = ? AND channelId = ?", serverId, channelId).blocking(); + database.prepareAndExecuteAsync("UPDATE logging SET enabled = NOT enabled WHERE guild_id = ? AND channelId = ?", serverId, channelId).blocking(); } public boolean isLoggingEnabled(String serverId, String channelId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT enabled FROM logging WHERE serverId = ? AND channelId = ?", serverId, channelId).blocking(); + MTableModel table = database.prepareAndExecuteAsync("SELECT enabled FROM logging WHERE guild_id = ? AND channelId = ?", serverId, channelId).blocking(); return Boolean.parseBoolean((String) table.getRow(0).get(0)); } From 3bccd6ce5ac4c28797af7f067a7af70e277cc305 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 4 Jan 2022 18:38:13 -0500 Subject: [PATCH 050/155] Add check to prevent null exceptions to isAdmin function --- src/main/java/netneutrality/db/MysqlDatabase.java | 1 - src/main/java/netneutrality/utils/UserFunction.java | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index ba7aab7..43592de 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -138,7 +138,6 @@ public class MysqlDatabase { * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet, String)} */ protected synchronized ResultSet prepareAndExecute(String sql, Object... params) { - logger.debug(sql); try { PreparedStatement query = connection.prepareStatement(sql); diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/netneutrality/utils/UserFunction.java index 5d46d3c..e61777b 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/netneutrality/utils/UserFunction.java @@ -3,13 +3,15 @@ package netneutrality.utils; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.User; public class UserFunction { public static boolean isAdmin(Member user) { // This check will only be present during the development of the bot - if (user.getUser().getId().equals(Settings.getInstance().getCreator().getId())) { + User creator = Settings.getInstance().getCreator(); + if (creator != null && user.getId().equals(creator.getId())) { return true; } From 6e1f4c2027178c8b5c58f8ce238a66e01af2d749 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 4 Jan 2022 19:05:39 -0500 Subject: [PATCH 051/155] Fix blacklist model to reflect db changes --- .../java/netneutrality/command/AbstractMusicCommand.java | 5 +++++ .../java/netneutrality/command/music/BitconnectCommand.java | 4 ---- src/main/java/netneutrality/command/music/JoinCommand.java | 4 ---- src/main/java/netneutrality/command/music/PlayCommand.java | 4 ---- .../java/netneutrality/command/music/VoteSkipCommand.java | 4 ---- src/main/java/netneutrality/db/entities/AbstractEntity.java | 4 ++-- src/main/java/netneutrality/db/models/MBlacklist.java | 4 ++-- 7 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 3e89bdf..aac0603 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -13,6 +13,11 @@ import netneutrality.MusicBot; public abstract class AbstractMusicCommand extends AbstractCommand { + @Override + public boolean needAdmin() { + return false; + } + @Override public CommandType getType() { return CommandType.MUSIC; diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 0286bce..76c2f0c 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -14,10 +14,6 @@ import netneutrality.command.Visibility; import netneutrality.music.MusicManager; public class BitconnectCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index c85555c..209a642 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -14,10 +14,6 @@ import netneutrality.command.Visibility; import netneutrality.music.MusicManager; public class JoinCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index fae599a..b33761d 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -14,10 +14,6 @@ import netneutrality.command.Visibility; import netneutrality.music.MusicManager; public class PlayCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index b33db0e..b15c456 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -10,10 +10,6 @@ import netneutrality.command.AbstractMusicCommand; import netneutrality.command.Visibility; public class VoteSkipCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return false; - } @Override public boolean isEnabled() { diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java index bcc2873..1ba12d9 100644 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -36,13 +36,13 @@ public abstract class AbstractEntity implements EntityInterface { String sql = "SELECT * FROM " + getTableName() + " WHERE " + whereClause; - System.out.println(sql + " - pk: " + primaryKey); + MusicBot.logger.debug(sql + " - pk: " + primaryKey); if (this.primaryKeys.length > 0) this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey, this.primaryKeys).blocking(); else this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey).blocking(); - System.out.println(table); + } } diff --git a/src/main/java/netneutrality/db/models/MBlacklist.java b/src/main/java/netneutrality/db/models/MBlacklist.java index 8d6eb91..bc5a61a 100644 --- a/src/main/java/netneutrality/db/models/MBlacklist.java +++ b/src/main/java/netneutrality/db/models/MBlacklist.java @@ -17,10 +17,10 @@ public class MBlacklist { } public MBlacklist(List row) { - this.word = (String) row.get(0); + this.word = (String) row.get(1); this.enabled = (Boolean) row.get(2); this.creatorId = (String) row.get(3); - this.serverId = (String) row.get(1); + this.serverId = (String) row.get(0); } /** From a70be9785a1036602391baeb2b6e904803ee4581 Mon Sep 17 00:00:00 2001 From: anthorob Date: Thu, 6 Jan 2022 15:52:21 -0500 Subject: [PATCH 052/155] Update build process for Java 17 --- .gitlab-ci.yml | 2 +- Dockerfile | 2 +- pom.xml | 11 +++-------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0c71e7..01d57cf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: maven:3-jdk-11 +image: openjdk:17-jdk-slim variables: MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode" diff --git a/Dockerfile b/Dockerfile index 77ba04c..217542e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11-jdk-slim +FROM openjdk:17-jdk-slim WORKDIR /app diff --git a/pom.xml b/pom.xml index 9119b8e..61208d3 100644 --- a/pom.xml +++ b/pom.xml @@ -109,7 +109,6 @@ 20210307 - org.reflections reflections @@ -119,7 +118,7 @@ mysql mysql-connector-java - 8.0.26 + 8.0.27 org.apache.logging.log4j @@ -136,18 +135,14 @@ log4j-slf4j-impl 2.17.0 + + commons-logging commons-logging 1.2 - - org.fusesource.jansi - jansi - 2.4.0 - runtime - com.sedmelluq lavaplayer From aff2a1431f91ab626a8c6fbee606e6e98aa1f341 Mon Sep 17 00:00:00 2001 From: anthorob Date: Thu, 6 Jan 2022 15:54:19 -0500 Subject: [PATCH 053/155] Update build process for Java 17 --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 01d57cf..27e878e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,17 +17,17 @@ stages: compile: stage: compile script: - - "mvn --batch-mode compile" + - "./mvnw --batch-mode compile" test: stage: test script: - - "mvn --batch-mode test" + - "./mvnw --batch-mode test" package: stage: package script: - - "mvn --batch-mode package" + - "./mvnw --batch-mode package" artifacts: paths: - target/netneutrality-jar-with-dependencies.jar \ No newline at end of file From 132fa92557f886afae51eba8b00201c54390e681 Mon Sep 17 00:00:00 2001 From: anthorob Date: Thu, 6 Jan 2022 15:56:47 -0500 Subject: [PATCH 054/155] Update build process for Java 17 --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 27e878e..904a55f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,16 +17,19 @@ stages: compile: stage: compile script: + - "chmod +x ./mvnw" - "./mvnw --batch-mode compile" test: stage: test script: + - "chmod +x ./mvnw" - "./mvnw --batch-mode test" package: stage: package script: + - "chmod +x ./mvnw" - "./mvnw --batch-mode package" artifacts: paths: From 2a1c7c4f3b6cbf83d04de6434c65c132d1a7c12a Mon Sep 17 00:00:00 2001 From: anthorob Date: Thu, 6 Jan 2022 16:10:48 -0500 Subject: [PATCH 055/155] Changed settings class to remove dependency to JDA --- src/main/java/netneutrality/MusicBot.java | 24 ++++++++++--------- .../command/specific/DatabaseCommand.java | 4 +--- .../command/specific/EvalMethod.java | 2 +- .../command/specific/TestCommand.java | 2 +- .../java/netneutrality/db/MysqlConnector.java | 15 +++++++----- .../db/entities/AbstractEntity.java | 2 +- .../netneutrality/handler/LogHandler.java | 3 ++- .../java/netneutrality/utils/Settings.java | 17 +++++-------- .../netneutrality/utils/UserFunction.java | 5 ++-- 9 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index d784a11..98bd160 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -26,19 +26,9 @@ public class MusicBot { public final static Logger logger = LoggerFactory.getLogger(MusicBot.class); public static void main(String[] args) { - System.setProperty("log4j.skipJansi", "false"); - DBController.init(); - try { - jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")) - .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) - .build(); - jda.awaitReady(); - } catch (LoginException | IllegalArgumentException | InterruptedException e) { - logger.error(e.getMessage()); - System.exit(0); - } + initJDA(); jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new NewCommandListener(), new EditHandler()); @@ -57,6 +47,18 @@ public class MusicBot { } + public static void initJDA() { + try { + jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")) + .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) + .build(); + jda.awaitReady(); + } catch (LoginException | IllegalArgumentException | InterruptedException e) { + logger.error(e.getMessage()); + System.exit(0); + } + } + public static void shutdown() { System.out.println("[Net Neutrality] Shutting down..."); MusicManager.disconnectPlayers(); diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index cf92c7f..b3db69f 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -4,10 +4,8 @@ import java.awt.Color; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.function.Consumer; import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.PrivateChannel; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; @@ -66,7 +64,7 @@ public class DatabaseCommand extends AbstractCommand { event.getMessage().delete().queue(); - if (!event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) + if (!event.getAuthor().getId().equals(Settings.getInstance().getCreatorId())) return null; if (args.length > 0) { diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 26ff480..cf0d8d1 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -62,7 +62,7 @@ public class EvalMethod extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String[] args) { - if (event.getAuthor().getId().equals(Settings.getInstance().getCreator().getId())) { + if (event.getAuthor().getId().equals(Settings.getInstance().getCreatorId())) { ScriptEngine se = new ScriptEngineManager().getEngineByName("Nashorn"); try { se.eval("var imports = new JavaImporter(java.io, java.lang, java.util);"); diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index fffee93..c8843b3 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -57,7 +57,7 @@ public class TestCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String[] args) { - if (event.getAuthor().getDiscriminator().equals(Settings.getInstance().getCreator().getDiscriminator())) { + if (event.getAuthor().getId().equals(Settings.getInstance().getCreatorId())) { MessageFunction.isStartingWithMention(event.getMessage()); } diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index ced5beb..6f6849c 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -1,5 +1,7 @@ package netneutrality.db; +import com.mysql.cj.jdbc.MysqlDataSource; + import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; @@ -25,14 +27,15 @@ public class MysqlConnector { * @return {@link MysqlConnector} */ public MysqlConnector connect() throws SQLException { + MysqlDataSource dataSource = new MysqlDataSource(); String jdbc = "jdbc:mysql://" + dbHost + ":3306/" + dbName; - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - c = DriverManager.getConnection(jdbc, dbUser, dbPass); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } + dataSource.setURL(jdbc); + dataSource.setUser(dbUser); + dataSource.setPassword(dbPass); + dataSource.setAutoReconnect(true); + dataSource.setConnectTimeout(5000); + c = dataSource.getConnection(); return this; } diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java index 1ba12d9..3a4d96a 100644 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -42,7 +42,7 @@ public abstract class AbstractEntity implements EntityInterface { this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey, this.primaryKeys).blocking(); else this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey).blocking(); - + } } diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index 578fdf4..bfdac39 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -19,7 +19,8 @@ public class LogHandler { logger.error(e.getMessage()); //TODO: to remove or add check if jda is started - Settings.getInstance().getLogChannel().sendMessage("Error : " + e).queue(); + String channel = Settings.getInstance().getLogChannel(); + MusicBot.getJDA().getTextChannelById(channel).sendMessage("Error : " + e).queue(); } diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 6aec4d6..fad2544 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -1,10 +1,5 @@ package netneutrality.utils; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.entities.User; -import netneutrality.MusicBot; - import java.io.*; import java.util.Map; import java.util.Properties; @@ -68,16 +63,16 @@ public class Settings { public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - public User getCreator() { - return MusicBot.getJDA().getUserById(get("BOT_OWNER")); + public String getCreatorId() { + return get("BOT_OWNER"); } - public Guild getOwnerGuild() { - return MusicBot.getJDA().getGuildById(get("BOT_OWNERGUILD")); + public String getOwnerGuild() { + return get("BOT_OWNERGUILD"); } - public TextChannel getLogChannel() { - return MusicBot.getJDA().getTextChannelById(get("BOT_ERRORCHANNEL")); + public String getLogChannel() { + return get("BOT_ERRORCHANNEL"); } diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/netneutrality/utils/UserFunction.java index e61777b..8eee156 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/netneutrality/utils/UserFunction.java @@ -3,15 +3,14 @@ package netneutrality.utils; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; public class UserFunction { public static boolean isAdmin(Member user) { // This check will only be present during the development of the bot - User creator = Settings.getInstance().getCreator(); - if (creator != null && user.getId().equals(creator.getId())) { + String creatorId = Settings.getInstance().getCreatorId(); + if (creatorId != null && user.getId().equals(creatorId)) { return true; } From 696d989f7be1a18e22495973e25b4f89631bc34f Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 7 Jan 2022 12:53:37 -0500 Subject: [PATCH 056/155] Create global crypto command --- .../command/crypto/CryptoPriceCommand.java | 95 +++++++++++++++++++ .../command/crypto/LitecoinPriceCommand.java | 2 +- .../java/netneutrality/http/WebModule.java | 24 ++++- 3 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java new file mode 100644 index 0000000..14b4ba9 --- /dev/null +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -0,0 +1,95 @@ +package netneutrality.command.crypto; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; +import netneutrality.command.Visibility; +import netneutrality.http.WebModule; +import org.json.JSONException; + +import java.io.IOException; + +public class CryptoPriceCommand extends AbstractCommand { + + private String currency = "USD"; + private final String baseURL = "https://min-api.cryptocompare.com/data/price"; + private String price = ""; + + @Override + public boolean needAdmin() { + return false; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getCommand() { + return "crypto"; + } + + @Override + public String[] getAlias() { + return new String[0]; + } + + @Override + public String getUsage() { + return " "; + } + + @Override + public String getDescription() { + return "Get the price of cryptocurrrency"; + } + + @Override + public Visibility getVisibility() { + return Visibility.CHANNEL; + } + + @Override + public CommandType getType() { + return null; + } + + @Override + public String execute(MessageReceivedEvent event, String[] args) { + + if (args.length > 0) { + + if (args.length == 2) { + if (Currency.isCurrency(args[1].toUpperCase())) + this.currency = args[1].toUpperCase(); + else { + event.getTextChannel().sendMessage("Please enter a valid currency").queue(); + return null; + } + + } + + event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + + try { + WebModule ethereumHttp = new WebModule(baseURL + "?fsym=" + args[0] + "&tsyms=" + currency.toUpperCase()).request(); + price = Double.toString(ethereumHttp.getAsObject().getDouble(currency)); + + if (price == null) + throw new IllegalArgumentException("Crypto doesn't exist"); + + } catch (IOException | JSONException | IllegalArgumentException e) { + e.printStackTrace(); + t.editMessage("Error getting ethereum price!").queue(); + } + + t.editMessage(String.format("The current price of %s in %s is %s$", args[0].toUpperCase(), currency, price)).queue(); + }); + } + + + return null; + } + +} diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 3a7efb1..c1d2616 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -15,7 +15,7 @@ import netneutrality.http.WebModule; public class LitecoinPriceCommand extends AbstractCommand { private String currency; - private final String currencyUrl = "https://api.coinmarketcap.com/v1/ticker/litecoin/?convert="; + private final String currencyUrl = "https://min-api.cryptocompare.com/data/price?fsym=LTC&tsyms="; private String price; public LitecoinPriceCommand() { diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index c955828..b0c8002 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -13,8 +13,8 @@ import java.util.TreeMap; public class WebModule { - private String url; - private OkHttpClient client = new OkHttpClient(); + private final String url; + private final OkHttpClient client = new OkHttpClient(); private Response response; public WebModule(String url) { @@ -30,7 +30,7 @@ public class WebModule { public WebModule request() { Request request = new Request.Builder().url(this.url) - .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36") + .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 OPR/82.0.4227.43") .build(); try { response = client.newCall(request).execute(); @@ -72,8 +72,6 @@ public class WebModule { } public static String createJson(TreeMap params) { - - StringBuilder json = new StringBuilder(); for (Map.Entry param : params.entrySet()) { @@ -86,6 +84,21 @@ public class WebModule { return (json.length() > 1 ? json.substring(0, json.length() - 1) + "}" : ""); } + public static String createJsonObject(List key, List value) { + if (key.size() != value.size()) + throw new IllegalArgumentException("Key list size not equal to value list size"); + + StringBuilder json = new StringBuilder(); + + for (int index = 0; index < key.size();) { + json.append(String.format("\"%s\":\"%s\"", key.get(index), value.get(index))); + json.append(","); + } + json.insert(0, "{"); + + return (json.length() > 1 ? json.substring(0, json.length() - 1) + "}" : ""); + } + public static String createJsonArray(List list) { StringBuilder json = new StringBuilder(); @@ -110,6 +123,7 @@ public class WebModule { return (json.length() > 1 ? json.substring(0, json.length() - 1) + "]" : "[]"); } + /** * @return the response as a JSONObject From 5e5539914d837cceb9de226007b3b16720ca3237 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 7 Jan 2022 13:21:54 -0500 Subject: [PATCH 057/155] fix typo --- .../java/netneutrality/command/crypto/CryptoPriceCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 14b4ba9..0718590 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -81,7 +81,7 @@ public class CryptoPriceCommand extends AbstractCommand { } catch (IOException | JSONException | IllegalArgumentException e) { e.printStackTrace(); - t.editMessage("Error getting ethereum price!").queue(); + t.editMessage("Error getting price!").queue(); } t.editMessage(String.format("The current price of %s in %s is %s$", args[0].toUpperCase(), currency, price)).queue(); From 8031856bc28b734df476b46a37138cde93252e64 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 7 Jan 2022 19:09:49 -0500 Subject: [PATCH 058/155] Fix playlist loading and prepare for JDA 5 --- pom.xml | 8 +- src/main/java/netneutrality/GuildManager.java | 21 +++++ .../command/AbstractMusicCommand.java | 6 +- .../command/basic/HelpCommand.java | 22 ++--- .../command/crypto/CryptoPriceCommand.java | 11 +-- .../command/message/PruneCommand.java | 4 +- .../command/music/DeleteQueueCommand.java | 4 +- .../command/music/PlayCommand.java | 4 +- .../command/music/ViewQueueCommand.java | 81 +++++++++++++++++++ .../command/specific/DatabaseCommand.java | 4 +- .../netneutrality/handler/EditHandler.java | 4 +- .../music/LoadResultHandler.java | 5 +- .../netneutrality/music/MusicManager.java | 23 +++--- .../netneutrality/music/SourceFinder.java | 2 +- .../netneutrality/music/TrackScheduler.java | 6 +- .../netneutrality/utils/MessageFunction.java | 58 ++++++++++--- 16 files changed, 200 insertions(+), 63 deletions(-) create mode 100644 src/main/java/netneutrality/command/music/ViewQueueCommand.java diff --git a/pom.xml b/pom.xml index 61208d3..50dbbea 100644 --- a/pom.xml +++ b/pom.xml @@ -136,13 +136,11 @@ 2.17.0 - - commons-logging - commons-logging - 1.2 + org.apache.commons + commons-lang3 + 3.12.0 - com.sedmelluq lavaplayer diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 0429cb2..724efbb 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -19,6 +19,21 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { + public enum GuildSettings { + MUSIC_ROLE("muisc.role"), MUSIC_CHANNEL("music.channel"), BLACKLIST_CHANNELS("blacklist.exclude.channels"); + + private final String setting; + + GuildSettings(String setting) { + this.setting = setting; + } + + @Override + public String toString() { + return setting; + } + } + public static final Logger logger = LoggerFactory.getLogger(GuildManager.class); private static final Map managers = new ConcurrentHashMap<>(); private final Guild guild; @@ -46,6 +61,12 @@ public class GuildManager { return guildEntity.getSettings().getSettingByKey(key); } + public String getSetting(GuildSettings key) { + reloadSettings(); + System.out.println(key); + return guildEntity.getSettings().getSettingByKey(key.toString()); + } + public void reloadSettings() { guildEntity.reloadSettings(); } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index aac0603..7f7e915 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -25,11 +25,11 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting("music.role"); + String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSettings.MUSIC_ROLE); System.out.println(roleDb); - if (!roleDb.isEmpty()) { - Role neededRole = MusicBot.getJDA().getRoleById(roleDb); + if (roleDb != null && !roleDb.isEmpty()) { + Role neededRole = guild.getRoleById(roleDb); return member.getRoles().contains(neededRole); } diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 098ede5..58a6e97 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -15,17 +15,6 @@ import java.util.HashMap; public class HelpCommand extends AbstractCommand { - public HelpCommand() { - - } - - @Override - public String execute(MessageReceivedEvent event, String[] args) { - sendHelp(CommandManager.commands, CommandManager.commandsAlias, event.getAuthor(), event.getChannel()); - - return null; - } - @Override public boolean needAdmin() { return false; @@ -66,11 +55,14 @@ public class HelpCommand extends AbstractCommand { return CommandType.UTILITY; } - public void sendHelp(HashMap commands, HashMap alias, User user, MessageChannel channel) { + @Override + public String execute(MessageReceivedEvent event, String[] args) { - if (channel instanceof TextChannel) - channel.sendMessage(new MessageBuilder().append(user).append(" help has been sent your way!").build()).queue(); + if (event.getChannel() instanceof TextChannel) + event.getChannel().sendMessage(new MessageBuilder().append(event.getAuthor()).append(" help has been sent your way!").build()).queue(); - user.openPrivateChannel().queue(t -> t.sendMessage(MessageFunction.buildHelpMessage(commands, alias)).queue()); + event.getAuthor().openPrivateChannel().queue(t -> t.sendMessageEmbeds(MessageFunction.buildHelpMessage(CommandManager.commands, CommandManager.commandsAlias)).queue()); + + return null; } } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 0718590..fb6b852 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -11,7 +11,6 @@ import java.io.IOException; public class CryptoPriceCommand extends AbstractCommand { - private String currency = "USD"; private final String baseURL = "https://min-api.cryptocompare.com/data/price"; private String price = ""; @@ -57,12 +56,13 @@ public class CryptoPriceCommand extends AbstractCommand { @Override public String execute(MessageReceivedEvent event, String[] args) { + String currency = "USD"; if (args.length > 0) { if (args.length == 2) { if (Currency.isCurrency(args[1].toUpperCase())) - this.currency = args[1].toUpperCase(); + currency = args[1].toUpperCase(); else { event.getTextChannel().sendMessage("Please enter a valid currency").queue(); return null; @@ -70,11 +70,12 @@ public class CryptoPriceCommand extends AbstractCommand { } + String finalCurrency = currency; event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { try { - WebModule ethereumHttp = new WebModule(baseURL + "?fsym=" + args[0] + "&tsyms=" + currency.toUpperCase()).request(); - price = Double.toString(ethereumHttp.getAsObject().getDouble(currency)); + WebModule ethereumHttp = new WebModule(baseURL + "?fsym=" + args[0] + "&tsyms=" + finalCurrency.toUpperCase()).request(); + price = Double.toString(ethereumHttp.getAsObject().getDouble(finalCurrency)); if (price == null) throw new IllegalArgumentException("Crypto doesn't exist"); @@ -84,7 +85,7 @@ public class CryptoPriceCommand extends AbstractCommand { t.editMessage("Error getting price!").queue(); } - t.editMessage(String.format("The current price of %s in %s is %s$", args[0].toUpperCase(), currency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s$", args[0].toUpperCase(), finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index f8645a6..98d1f5e 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -30,12 +30,12 @@ public class PruneCommand extends AbstractCommand { @Override public String getUsage() { - return "Prune n messages from the channel you are currently on"; + return ""; } @Override public String getDescription() { - return null; + return "Delete n messages from the channel you are currently on"; } @Override diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index b21cc43..facb8fb 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -59,9 +59,9 @@ public class DeleteQueueCommand extends AbstractMusicCommand { if (player.isConnected()) { if (player.isConnectedTo(vChannel)) { - int queueSize = player.getScheduler().queue.size(); + int queueSize = player.getScheduler().getQueue().size(); if (queueSize > 0) { - player.getScheduler().queue.clear(); + player.getScheduler().getQueue().clear(); event.getTextChannel().sendMessage("Removed " + queueSize + (queueSize > 1 ? " tracks" : "track") + " from the queue").queue(); } else { event.getTextChannel().sendMessage("Queue is empty!").queue(); diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index b33761d..aa92d1f 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -32,12 +32,12 @@ public class PlayCommand extends AbstractMusicCommand { @Override public String getUsage() { - return null; + return ""; } @Override public String getDescription() { - return null; + return "Get the party going"; } @Override diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java new file mode 100644 index 0000000..1f6a60e --- /dev/null +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -0,0 +1,81 @@ +package netneutrality.command.music; + +/* + * Copyright (c) anthorob + * + * This file is closed-source. It should not be distributed or copied in any way or form + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.Visibility; +import netneutrality.music.MusicManager; +import netneutrality.utils.MessageFunction; + +public class ViewQueueCommand extends AbstractMusicCommand { + @Override + public boolean needAdmin() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getCommand() { + return "viewqueue"; + } + + @Override + public String[] getAlias() { + return new String[]{"viewq"}; + } + + @Override + public String getUsage() { + return null; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public Visibility getVisibility() { + return Visibility.CHANNEL; + } + + @Override + public String execute(MessageReceivedEvent event, String[] args) { + Member member = event.getMember(); + + if (member.getVoiceState().inVoiceChannel()) { + MusicManager player = MusicManager.get(event.getGuild()); + VoiceChannel vChannel = member.getVoiceState().getChannel(); + + if (player.isConnected()) { + if (player.isConnectedTo(vChannel)) { + int queueSize = player.getScheduler().getQueue().size(); + if (queueSize > 0) { + + event.getTextChannel().sendMessageEmbeds(MessageFunction.buildViewQueueMessage(player, member)).queue(); + } else { + event.getTextChannel().sendMessage("Queue is empty!").queue(); + } + + } else + event.getTextChannel().sendMessage("Not in your voice channel").queue(); + } else { + event.getTextChannel().sendMessage("Player is not connected").queue(); + } + } else + event.getTextChannel().sendMessage("You are not in a voice channel").queue(); + + return null; + } +} diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index b3db69f..0190ef8 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -84,7 +84,7 @@ public class DatabaseCommand extends AbstractCommand { embed.setDescription( "Message from " + message.getSender() + " on the channel " + message.getChannelName()); embed.addField("Message: ", "" + message.getMessage(), false); - event.getTextChannel().sendMessage(embed.build()).queue(); + event.getTextChannel().sendMessageEmbeds(embed.build()).queue(); } else { User user = event.getJDA().getUserById(args[1]); if (user != null) { @@ -101,7 +101,7 @@ public class DatabaseCommand extends AbstractCommand { } embed.setFooter("Guild : " + event.getGuild().getName(), null); - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage(embed.build()).queue()); + event.getAuthor().openPrivateChannel().queue(t -> t.sendMessageEmbeds(embed.build()).queue()); } } diff --git a/src/main/java/netneutrality/handler/EditHandler.java b/src/main/java/netneutrality/handler/EditHandler.java index 6a991cc..883b171 100644 --- a/src/main/java/netneutrality/handler/EditHandler.java +++ b/src/main/java/netneutrality/handler/EditHandler.java @@ -18,7 +18,7 @@ public class EditHandler extends ListenerAdapter { if (event.getAuthor().isBot()) return; - MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channelId FROM logging WHERE serverId = ? AND enabled = 1", event.getGuild().getId()).blocking(); + MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); Object logChannel = table.getRowModel(0).getItem(0); if (logChannel != null) { @@ -42,7 +42,7 @@ public class EditHandler extends ListenerAdapter { editEmbed.setFooter("ID : " + event.getMessageId(), null); editEmbed.setTimestamp(event.getMessage().getTimeCreated()); - event.getJDA().getTextChannelById(logChannel.toString()).sendMessage(editEmbed.build()).queue(); + event.getJDA().getTextChannelById(logChannel.toString()).sendMessageEmbeds(editEmbed.build()).queue(); } diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java index d89fa67..0413f09 100644 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -33,7 +33,7 @@ public class LoadResultHandler implements AudioLoadResultHandler { @Override public void trackLoaded(AudioTrack audioTrack) { if (!silent) { - channel.sendMessage(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); } scheduler.queue(audioTrack); @@ -45,9 +45,10 @@ public class LoadResultHandler implements AudioLoadResultHandler { if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); - channel.sendMessage(MessageFunction.buildAddingTrackMessage(track, user)).queue(); + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user)).queue(); scheduler.queue(track); } else { + channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user)).queue(); for (AudioTrack track : audioPlaylist.getTracks()) { scheduler.queue(track); } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 1470208..61f73ed 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -16,6 +16,7 @@ import netneutrality.ThreadManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -64,8 +65,9 @@ public class MusicManager { guild.getAudioManager().openAudioConnection(vChannel); ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { - if ((getCurrentlyPlaying() == null && scheduler.queue.isEmpty()) || vChannel.getMembers().size() == 0) + if ((getCurrentlyPlaying() == null && scheduler.getQueue().isEmpty()) || vChannel.getMembers().size() == 0) { leave(); + } }, 120, 120, TimeUnit.SECONDS); } else logger.error("Error connecting!"); @@ -81,20 +83,19 @@ public class MusicManager { public synchronized void leave() { if (isConnected()) { - player.destroy(); + player.stopTrack(); + guild.getAudioManager().closeAudioConnection(); } scheduler.resetTopic(); - if (guild != null) { - guild.getAudioManager().closeAudioConnection(); - } - } public static void disconnectPlayers() { for (MusicManager mm : managers.values()) { mm.leave(); + mm.player.destroy(); + mm.scheduler.getQueue().clear(); } } @@ -114,7 +115,7 @@ public class MusicManager { } public synchronized void skip() { - if (!scheduler.queue.isEmpty()) { + if (!scheduler.getQueue().isEmpty()) { scheduler.nextTrack(); } else { leave(); @@ -129,9 +130,11 @@ public class MusicManager { return scheduler; } - public List getAllQueuedTrack() { - List queuedTracks = new LinkedList<>(); - scheduler.queue.forEach((a) -> queuedTracks.add(a.getInfo().title)); + public ArrayList getAllQueuedTrack() { + ArrayList queuedTracks = new ArrayList<>(); + scheduler.getQueue().forEach((a) -> { + queuedTracks.add(a.getInfo().title); + }); return queuedTracks; } diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index 2196ff4..2a09d40 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -50,7 +50,7 @@ public class SourceFinder { switch (getSource(url)) { case Youtube: - identifier = youtubeMatcher.group(1); + identifier = url; break; case Soundcloud: identifier = url; diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 81cc068..ebc6031 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -20,7 +20,7 @@ public class TrackScheduler extends AudioEventAdapter { private final AudioPlayer player; private TextChannel channel; - public final BlockingQueue queue; + private final BlockingQueue queue; public String topic; public TrackScheduler(AudioPlayer player) { @@ -53,6 +53,10 @@ public class TrackScheduler extends AudioEventAdapter { return channel; } + public BlockingQueue getQueue() { + return queue; + } + public void resetTopic() { if (this.channel != null) { //this.channel.getManager().setTopic(this.topic).queue(); diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 063d8b6..9428b11 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -7,13 +7,9 @@ package netneutrality.utils; */ import java.awt.*; -import java.time.Duration; -import java.time.LocalDateTime; import java.time.OffsetDateTime; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; @@ -23,6 +19,8 @@ import netneutrality.command.AbstractCommand; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; +import netneutrality.music.MusicManager; +import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,23 +58,35 @@ public class MessageFunction { return false; } - public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { - Duration d = Duration.ofMillis(track.getDuration()); - + public synchronized static MessageEmbed buildCurrentlyPlayingMessage(AudioTrack track, Member user) { EmbedBuilder message = new EmbedBuilder(); - message.setTitle("Adding track to queue.."); + message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); + message.setTitle("Currently playing:"); message.setColor(Color.BLUE); message.addField("Track title: ", track.getInfo().title, false); - message.addField("Duration: ", d.toMinutesPart() + ":" + d.toSecondsPart(), false); + message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); + return message.build(); + } + + public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { + EmbedBuilder message = new EmbedBuilder(); + message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); + message.setTitle("Adding track to queue.."); + message.setColor(Color.BLUE); + message.addField("Track title: ", track.getInfo().title, false); + message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); + message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setTimestamp(OffsetDateTime.now()); return message.build(); } public synchronized static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user) { EmbedBuilder message = new EmbedBuilder(); + message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier())); message.setTitle("Adding playlist to queue.."); message.setColor(Color.BLUE); message.addField("Playlist: ", playlist.getName(), false); @@ -88,6 +98,33 @@ public class MessageFunction { return message.build(); } + public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user) { + ArrayList tracks = manager.getAllQueuedTrack(); + Collections.reverse(tracks); + AudioTrack current = manager.getCurrentlyPlaying(); + + EmbedBuilder message = new EmbedBuilder(); + message.setTitle("Current queue (showing max 10 items):"); + message.setColor(Color.BLUE); + + int index = 0; + for (String track: tracks) { + String text = track; + + if (Objects.equals(track, current.getInfo().title)) + text += " (Currently playing)"; + + message.addField("Track #" + ++index, text, false); + + if (index == 10) break; + } + + message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setTimestamp(OffsetDateTime.now()); + + return message.build(); + } + public static MessageEmbed buildHelpMessage(HashMap commands, HashMap alias) { EmbedBuilder message = new EmbedBuilder(); message.setTitle("Commands for Net Neutrality"); @@ -135,5 +172,4 @@ public class MessageFunction { }); } - } From 6ed956a05359c53753d191ea36ff9fa2fef6f9ae Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 7 Jan 2022 20:06:29 -0500 Subject: [PATCH 059/155] Fix view queue command and add currently playing command --- src/main/java/netneutrality/GuildManager.java | 3 - .../music/CurrentlyPlayingCommand.java | 75 +++++++++++++++++++ .../music/LoadResultHandler.java | 6 +- .../netneutrality/music/MusicManager.java | 5 +- .../netneutrality/utils/MessageFunction.java | 29 ++++--- 5 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 724efbb..611533b 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -57,13 +57,10 @@ public class GuildManager { } public String getSetting(String key) { - reloadSettings(); return guildEntity.getSettings().getSettingByKey(key); } public String getSetting(GuildSettings key) { - reloadSettings(); - System.out.println(key); return guildEntity.getSettings().getSettingByKey(key.toString()); } diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java new file mode 100644 index 0000000..a809e42 --- /dev/null +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -0,0 +1,75 @@ +package netneutrality.command.music; + +/* + * Copyright (c) anthorob + * + * This file is closed-source. It should not be distributed or copied in any way or form + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.Visibility; +import netneutrality.music.MusicManager; +import netneutrality.utils.MessageFunction; + +public class CurrentlyPlayingCommand extends AbstractMusicCommand { + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getCommand() { + return "playing"; + } + + @Override + public String[] getAlias() { + return new String[0]; + } + + @Override + public String getUsage() { + return null; + } + + @Override + public String getDescription() { + return "View currently playing track"; + } + + @Override + public Visibility getVisibility() { + return Visibility.CHANNEL; + } + + @Override + public String execute(MessageReceivedEvent event, String[] args) { + Member member = event.getMember(); + + if (member.getVoiceState().inVoiceChannel()) { + MusicManager player = MusicManager.get(event.getGuild()); + VoiceChannel vChannel = member.getVoiceState().getChannel(); + + if (player.isConnected()) { + if (player.isConnectedTo(vChannel)) { + if (player.getCurrentlyPlaying() != null) { + event.getTextChannel().sendMessageEmbeds(MessageFunction.buildCurrentlyPlayingMessage(player, member)).queue(); + } else { + event.getTextChannel().sendMessage("Player is not playing any track right now").queue(); + } + + } else + event.getTextChannel().sendMessage("Player is not in your voice channel").queue(); + } else { + event.getTextChannel().sendMessage("Player is not in a voice channel").queue(); + } + } else + event.getTextChannel().sendMessage("You are not in a voice channel").queue(); + + return null; + } +} diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java index 0413f09..56aab6c 100644 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -33,7 +33,7 @@ public class LoadResultHandler implements AudioLoadResultHandler { @Override public void trackLoaded(AudioTrack audioTrack) { if (!silent) { - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, user)).queue(); + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, user, identifier)).queue(); } scheduler.queue(audioTrack); @@ -45,10 +45,10 @@ public class LoadResultHandler implements AudioLoadResultHandler { if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user)).queue(); + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, identifier)).queue(); scheduler.queue(track); } else { - channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user)).queue(); + channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); for (AudioTrack track : audioPlaylist.getTracks()) { scheduler.queue(track); } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 61f73ed..9231760 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -132,7 +133,9 @@ public class MusicManager { public ArrayList getAllQueuedTrack() { ArrayList queuedTracks = new ArrayList<>(); - scheduler.getQueue().forEach((a) -> { + BlockingQueue queue = scheduler.getQueue(); + + queue.forEach((a) -> { queuedTracks.add(a.getInfo().title); }); diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 9428b11..a1159af 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -58,21 +58,25 @@ public class MessageFunction { return false; } - public synchronized static MessageEmbed buildCurrentlyPlayingMessage(AudioTrack track, Member user) { + public synchronized static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager, Member user) { + AudioTrack current = manager.getCurrentlyPlaying(); + EmbedBuilder message = new EmbedBuilder(); - message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); + message.setAuthor("Link to track", String.format("https://youtu.be/%s", current.getIdentifier())); + message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", current.getIdentifier())); message.setTitle("Currently playing:"); message.setColor(Color.BLUE); - message.addField("Track title: ", track.getInfo().title, false); - message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); + message.addField("Track title: ", current.getInfo().title, false); + message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user) { + public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user, String identifier) { EmbedBuilder message = new EmbedBuilder(); + message.setAuthor("Link to track", identifier); message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); @@ -84,8 +88,9 @@ public class MessageFunction { return message.build(); } - public synchronized static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user) { + public synchronized static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user, String identifier) { EmbedBuilder message = new EmbedBuilder(); + message.setAuthor("Link to playlist", identifier); message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier())); message.setTitle("Adding playlist to queue.."); message.setColor(Color.BLUE); @@ -94,27 +99,21 @@ public class MessageFunction { message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); - return message.build(); } public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user) { ArrayList tracks = manager.getAllQueuedTrack(); - Collections.reverse(tracks); AudioTrack current = manager.getCurrentlyPlaying(); EmbedBuilder message = new EmbedBuilder(); message.setTitle("Current queue (showing max 10 items):"); message.setColor(Color.BLUE); + message.addField("Track #1 (Currently playing)", current.getInfo().title, false); - int index = 0; + int index = 1; for (String track: tracks) { - String text = track; - - if (Objects.equals(track, current.getInfo().title)) - text += " (Currently playing)"; - - message.addField("Track #" + ++index, text, false); + message.addField("Track #" + ++index, track, false); if (index == 10) break; } From 061a18b4877698a37681aae8298f6a00e55c18e6 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 25 Jan 2022 22:45:21 -0500 Subject: [PATCH 060/155] Implement command context and improve logging + music manager + help command --- src/main/java/netneutrality/GuildManager.java | 16 +- src/main/java/netneutrality/MusicBot.java | 7 +- .../java/netneutrality/ThreadManager.java | 2 +- .../command/AbstractCommand.java | 58 +++--- .../command/AbstractMusicCommand.java | 3 +- .../netneutrality/command/CommandContext.java | 116 ++++++++++++ .../netneutrality/command/CommandType.java | 16 +- .../java/netneutrality/command/ICommand.java | 17 +- .../command/basic/HelpCommand.java | 32 ++-- .../command/basic/PingCommand.java | 82 ++++----- .../command/bot/ConfigureCommand.java | 19 +- .../command/crypto/BitcoinPriceCommand.java | 170 ++++++++--------- .../command/crypto/CryptoPriceCommand.java | 138 +++++++------- .../command/crypto/Currency.java | 44 +++-- .../command/crypto/EthereumPriceCommand.java | 150 ++++++++------- .../command/crypto/LitecoinPriceCommand.java | 150 ++++++++------- .../command/message/BlacklistCommand.java | 53 +++--- .../command/message/PruneCommand.java | 86 +++++---- .../command/music/BitconnectCommand.java | 39 +--- .../music/CurrentlyPlayingCommand.java | 44 ++--- .../command/music/DeleteQueueCommand.java | 48 ++--- .../command/music/JoinCommand.java | 36 +--- .../command/music/LeaveCommand.java | 27 +-- .../command/music/PlayCommand.java | 42 ++--- .../command/music/SkipCommand.java | 35 +--- .../command/music/StopCommand.java | 36 +--- .../command/music/ViewQueueCommand.java | 48 ++--- .../command/music/VolumeCommand.java | 48 ++--- .../command/music/VoteSkipCommand.java | 13 +- .../command/specific/DatabaseCommand.java | 173 +++++++++--------- .../command/specific/EvalMethod.java | 51 +++--- .../command/specific/LoggingCommand.java | 24 +-- .../command/specific/SellyCommand.java | 35 ++-- .../command/specific/ShutdownCommand.java | 57 ------ .../command/specific/TestCommand.java | 23 +-- .../netneutrality/db/controllers/DBGuild.java | 6 + .../db/controllers/DBMessage.java | 7 +- .../exceptions/CommandErrorException.java | 25 +++ .../exceptions/CommandException.java | 23 +++ .../exceptions/CommandExecutionException.java | 23 +++ .../UnimplementedParameterException.java | 5 +- .../netneutrality/handler/EditHandler.java | 75 ++++---- .../netneutrality/handler/LogHandler.java | 56 ++++-- .../handler/MessageReceivedHandler.java | 55 ++++++ .../handler/NewCommandListener.java | 77 -------- .../handler/ServerJoinHandler.java | 12 +- .../music/AudioPlayerSendHandler.java | 45 ++--- .../music/LoadResultHandler.java | 8 +- .../netneutrality/music/MusicManager.java | 44 ++++- .../netneutrality/music/SourceFinder.java | 37 ++-- .../netneutrality/music/TrackScheduler.java | 25 +-- .../netneutrality/utils/ChannelFunction.java | 2 +- .../netneutrality/utils/MessageFunction.java | 54 ++++-- .../java/netneutrality/utils/MusicUtils.java | 34 ++++ 54 files changed, 1280 insertions(+), 1271 deletions(-) create mode 100644 src/main/java/netneutrality/command/CommandContext.java delete mode 100644 src/main/java/netneutrality/command/specific/ShutdownCommand.java create mode 100644 src/main/java/netneutrality/exceptions/CommandErrorException.java create mode 100644 src/main/java/netneutrality/exceptions/CommandException.java create mode 100644 src/main/java/netneutrality/exceptions/CommandExecutionException.java create mode 100644 src/main/java/netneutrality/handler/MessageReceivedHandler.java delete mode 100644 src/main/java/netneutrality/handler/NewCommandListener.java create mode 100644 src/main/java/netneutrality/utils/MusicUtils.java diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 611533b..53a29bd 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -7,10 +7,15 @@ package netneutrality; */ import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.db.DBController; +import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OGuild; -import netneutrality.db.entities.OGuildSetting; import netneutrality.handler.ratelimiter.IMessageRateLimiter; import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; +import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +61,15 @@ public class GuildManager { } } + public void checkAndLogMessage(Message message, Member member, TextChannel channel) { + //((DBMessage) DBController.get("message")).log(guild, channel, member, message); + } + + public void checkBlacklist(Message message, Member member, TextChannel channel) { + //TODO: per-guild + MessageFunction.checkBlacklist(guild, message, channel); + } + public String getSetting(String key) { return guildEntity.getSettings().getSettingByKey(key); } diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 98bd160..3f4a025 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -5,9 +5,11 @@ import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.requests.GatewayIntent; +import netneutrality.command.CommandManager; import netneutrality.db.DBController; import netneutrality.handler.EditHandler; -import netneutrality.handler.NewCommandListener; +import netneutrality.handler.MessageReceivedHandler; +import netneutrality.handler.ServerJoinHandler; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; import netneutrality.utils.Settings; @@ -30,8 +32,9 @@ public class MusicBot { initJDA(); + CommandManager.init(); jda.getPresence().setActivity(Activity.watching("me load...")); - jda.addEventListener(new NewCommandListener(), new EditHandler()); + jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); new WebApi(); jda.getPresence().setActivity(Activity.watching("you")); diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 8225af1..d16b4a4 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -70,7 +70,7 @@ public class ThreadManager { try { for (ExecutorService ex : executors.values()) { ex.shutdown(); - ex.awaitTermination(5, TimeUnit.SECONDS); + ex.awaitTermination(2, TimeUnit.SECONDS); } } catch (InterruptedException e) { diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 96e98f8..0b13e68 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -4,39 +4,37 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; public abstract class AbstractCommand implements ICommand { - - /** - * @return if the command needs administrator privilege - */ - public abstract boolean needAdmin(); - - /** - * @return if the command is enabled - */ - public abstract boolean isEnabled(); - - /** - * The command name that a user will write in a channel - * - * @return the name of the command. - */ - public abstract String getCommand(); - - /** - * @return all the aliases the command has - */ - public abstract String[] getAlias(); - public abstract String getUsage(); + /** + * @return if the command needs administrator privilege + */ + public abstract boolean needAdmin(); - public abstract String getDescription(); + /** + * @return if the command should be loaded at runtime + */ + public abstract boolean isEnabled(); - public abstract Visibility getVisibility(); + /** + * The command name that a user will write in a channel + * + * @return the name of the command. + */ + public abstract String getCommand(); - public abstract CommandType getType(); + /** + * @return all the aliases the command has + */ + public abstract String[] getAlias(); - @Override - public boolean canBeExecutedBy(Guild guild, Member member) { - return true; - } + public abstract String getUsage(); + + public abstract String getDescription(); + + public abstract CommandType getType(); + + @Override + public boolean canBeExecutedBy(Guild guild, Member member) { + return true; + } } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 7f7e915..91a2136 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -9,7 +9,6 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import netneutrality.GuildManager; -import netneutrality.MusicBot; public abstract class AbstractMusicCommand extends AbstractCommand { @@ -26,7 +25,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSettings.MUSIC_ROLE); - System.out.println(roleDb); + //System.out.println(roleDb); if (roleDb != null && !roleDb.isEmpty()) { Role neededRole = guild.getRoleById(roleDb); diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java new file mode 100644 index 0000000..6e120f1 --- /dev/null +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -0,0 +1,116 @@ +package netneutrality.command; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import netneutrality.ThreadManager; +import netneutrality.handler.LogHandler; +import netneutrality.utils.UserFunction; + +import java.util.concurrent.ExecutorService; + +public class CommandContext { + + private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED, 10); + + private AbstractCommand command; + private final Message message; + private final Guild guild; + private final TextChannel channel; + private final Member member; + private final User user; + private final JDA jda; + + public CommandContext(Message message, Member member, User user, Guild guild, TextChannel channel, JDA jda) { + this.message = message; + this.member = member; + this.guild = guild; + this.channel = channel; + this.user = user; + this.jda = jda; + } + + public static CommandContext createContext(GuildMessageReceivedEvent event) { + Message message = event.getMessage(); + Member member = event.getMember(); + User user = event.getAuthor(); + Guild guild = event.getGuild(); + TextChannel channel = event.getChannel(); + JDA jda = event.getJDA(); + + return new CommandContext(message, member, user, guild, channel, jda); + } + + public String[] getArgumentsAsArray() { + String text = message.getContentRaw().trim(); + String cmd = text.split(" ", 2)[0]; + String[] args = text.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); + + if (args.length == 1 && args[0].isEmpty()) + args = new String[0]; + + return args; + } + + public String getMessageText() { + String text = message.getContentRaw().trim(); + String cmd = text.split(" ", 2)[0]; + + return text.replaceFirst("(" + cmd + ")(\s)?", ""); + } + + public Message getMessage() { + return message; + } + + public Guild getGuild() { + return guild; + } + + public TextChannel getChannel() { + return channel; + } + + public Member getGuildUser() { + return member; + } + + public User getDiscordUser() { + return user; + } + + public JDA getJDA() { + return jda; + } + + public AbstractCommand getCommand() { + return command; + } + + public void dispatch(AbstractCommand command) { + this.command = command; + //TODO: Add usage check + + if (command.needAdmin()) { + if (!UserFunction.isAdmin(member)) { + return; + } + } + + if (command.canBeExecutedBy(guild, member)) { + + try { + command.execute(this); + } catch (Exception e) { + LogHandler.log(e); + } + + } + } +} diff --git a/src/main/java/netneutrality/command/CommandType.java b/src/main/java/netneutrality/command/CommandType.java index ff7fd0e..87b57d5 100644 --- a/src/main/java/netneutrality/command/CommandType.java +++ b/src/main/java/netneutrality/command/CommandType.java @@ -6,9 +6,21 @@ package netneutrality.command;/* */ public enum CommandType { - MUSIC(1), ADMINISTRATION(0), UTILITY(5); + MUSIC("Music", 1), ADMINISTRATION("Administration", 0), UTILITY("Utility", 5), CRYPTO("Crypto", 6), UNLISTED("", -1); - CommandType(int i) { + private final String description; + private final int id; + CommandType(String description, int id) { + this.description = description; + this.id = id; + } + + public String getDescription() { + return description; + } + + public int getId() { + return id; } } diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 73ad158..6af6385 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -7,14 +7,19 @@ package netneutrality.command;/* import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; public interface ICommand { - /** - * @param args the arguments to the command - */ - String execute(MessageReceivedEvent event, String[] args); - boolean canBeExecutedBy(Guild guild, Member member); + + /** + * Command is executed with this function. + * + * @param context The context for the command + * @throws CommandErrorException Used to reply with a message in the text channel where the command was executed + * @throws CommandExecutionException Logs the error internally, without sending a message + */ + void execute(CommandContext context) throws CommandErrorException, CommandExecutionException; } diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 58a6e97..cf53ca5 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -1,17 +1,21 @@ package netneutrality.command.basic; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ import net.dv8tion.jda.api.MessageBuilder; -import net.dv8tion.jda.api.entities.MessageChannel; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.entities.MessageEmbed; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandManager; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; import netneutrality.utils.MessageFunction; +import netneutrality.utils.UserFunction; -import java.util.HashMap; +import java.util.List; public class HelpCommand extends AbstractCommand { @@ -45,24 +49,16 @@ public class HelpCommand extends AbstractCommand { return "Get every command with its usage"; } - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } - @Override public CommandType getType() { return CommandType.UTILITY; } @Override - public String execute(MessageReceivedEvent event, String[] args) { + public void execute(CommandContext context) { + List help = MessageFunction.buildHelpMessage(CommandManager.commands, CommandManager.commandsAlias, UserFunction.isAdmin(context.getGuildUser())); - if (event.getChannel() instanceof TextChannel) - event.getChannel().sendMessage(new MessageBuilder().append(event.getAuthor()).append(" help has been sent your way!").build()).queue(); - - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessageEmbeds(MessageFunction.buildHelpMessage(CommandManager.commands, CommandManager.commandsAlias)).queue()); - - return null; + context.getChannel().sendMessage(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()).queue(); + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessageEmbeds(help).queue()); } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 42e2027..c6c6633 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -1,59 +1,57 @@ package netneutrality.command.basic; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.MusicBot; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; public class PingCommand extends AbstractCommand { - @Override - public String execute(MessageReceivedEvent event, String[] args) { - if (args.length == 0) - event.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); + @Override + public boolean needAdmin() { + return false; + } - return null; - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public boolean needAdmin() { - return false; - } + @Override + public String getCommand() { + return "ping"; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public String[] getAlias() { + return new String[0]; + } - @Override - public String getCommand() { - return "ping"; - } + @Override + public String getUsage() { + return null; + } - @Override - public String[] getAlias() { - return new String[0]; - } + @Override + public String getDescription() { + return "Pong!"; + } - @Override - public String getUsage() { - return null; - } + @Override + public CommandType getType() { + return CommandType.UTILITY; + } - @Override - public String getDescription() { - return "Pong!"; - } - - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } - - @Override - public CommandType getType() { - return null; - } + @Override + public void execute(CommandContext context) { + if (context.getArgumentsAsArray().length == 0) + context.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); + } } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 1ddaafe..56051b3 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -1,14 +1,14 @@ -package netneutrality.command.bot;/* +package netneutrality.command.bot; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; public class ConfigureCommand extends AbstractCommand { @Override @@ -28,9 +28,7 @@ public class ConfigureCommand extends AbstractCommand { @Override public String[] getAlias() { - return new String[] { - "conf" - }; + return new String[]{"conf"}; } @Override @@ -43,18 +41,13 @@ public class ConfigureCommand extends AbstractCommand { return "Used to configure the bot on this server"; } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } - @Override public CommandType getType() { return CommandType.ADMINISTRATION; } @Override - public String execute(MessageReceivedEvent event, String[] args) { - return null; + public void execute(CommandContext context) { + } } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index c71b70f..375167d 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -1,110 +1,96 @@ package netneutrality.command.crypto; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; +import netneutrality.command.CommandType; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.http.WebModule; +import org.json.JSONException; import java.io.IOException; -import java.util.function.Consumer; - -import netneutrality.command.CommandType; -import netneutrality.command.Visibility; -import org.json.JSONException; -import org.json.JSONObject; - -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.http.WebModule; +import java.text.NumberFormat; +import java.util.Locale; public class BitcoinPriceCommand extends AbstractCommand { - - private String currency; - private final String currencyUrl = "https://api.coindesk.com/v1/bpi/currentprice/"; - private String price; - public BitcoinPriceCommand() { - this.currency = "USD"; - } - - private String messageBuilder(String price) { - String newPrice = price.substring(0, price.indexOf(".")); - - return "The current bitcoin price in " + this.currency + " is " + newPrice + "$"; - } + private final String baseURL = "https://min-api.cryptocompare.com/data/price"; + private final String crypto = "BTC"; - @Override - public String execute(MessageReceivedEvent event, String[] args) throws JSONException, ArrayIndexOutOfBoundsException { + @Override + public boolean needAdmin() { + return false; + } - if (args.length == 1) { - if (Currency.isCurrency(args[0].toUpperCase())) - this.currency = args[0].toUpperCase(); - else { - event.getTextChannel().sendMessage("Please enter a valid currency").queue(); - return null; - } - - } - - event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(new Consumer() { - - @Override - public void accept(Message t) { - try { - - WebModule bitcoinHttp = new WebModule(currencyUrl + currency + ".json").request(); - JSONObject bpi = bitcoinHttp.getAsObject().getJSONObject("bpi"); - price = bpi.getJSONObject(currency.toUpperCase()).getString("rate"); - - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - t.editMessage("Error getting bitcoin price!").queue(); - } - - t.editMessage(messageBuilder(price)).queue(); - - } - }); - - - - return null; - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public boolean needAdmin() { - return false; - } + @Override + public String getCommand() { + return "bitcoin"; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public String[] getAlias() { + return new String[]{"btc"}; + } - @Override - public String getCommand() { - return "bitcoin"; - } + @Override + public String getUsage() { + return null; + } - @Override - public String[] getAlias() { - return new String[] {"btc"}; - } + @Override + public String getDescription() { + return "Get the price of bitcoin"; + } - @Override - public String getUsage() { - return null; - } + @Override + public CommandType getType() { + return CommandType.CRYPTO; + } - @Override - public String getDescription() { - return "Get the bitcoin price"; - } + @Override + public void execute(CommandContext context) { + String[] args = context.getArgumentsAsArray(); + String currency = "USD"; - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } + if (args.length == 1) { + if (Currency.isCurrency(args[0].toUpperCase())) + currency = args[0].toUpperCase(); + else { + throw new CommandErrorException("Please enter a valid currency", context, null); + } - @Override - public CommandType getType() { - return null; - } + } + + String finalCurrency = currency; + context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + String price = "0"; + Locale usa = new Locale("en", "US"); + NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); + dollarFormat.setMaximumFractionDigits(24); + + try { + WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); + price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + + } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { + t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); + throw new CommandExecutionException("Error during web request", context, e); + } + + t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + + }); + } } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index fb6b852..d63703b 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -1,96 +1,100 @@ package netneutrality.command.crypto; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; import netneutrality.http.WebModule; import org.json.JSONException; import java.io.IOException; +import java.text.NumberFormat; +import java.util.Locale; public class CryptoPriceCommand extends AbstractCommand { - private final String baseURL = "https://min-api.cryptocompare.com/data/price"; - private String price = ""; + private final String baseURL = "https://min-api.cryptocompare.com/data/price"; - @Override - public boolean needAdmin() { - return false; - } + @Override + public boolean needAdmin() { + return false; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public String getCommand() { - return "crypto"; - } + @Override + public String getCommand() { + return "crypto"; + } - @Override - public String[] getAlias() { - return new String[0]; - } + @Override + public String[] getAlias() { + return new String[0]; + } - @Override - public String getUsage() { - return " "; - } + @Override + public String getUsage() { + return " "; + } - @Override - public String getDescription() { - return "Get the price of cryptocurrrency"; - } + @Override + public String getDescription() { + return "Get the price of cryptocurrrency"; + } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + @Override + public CommandType getType() { + return CommandType.CRYPTO; + } - @Override - public CommandType getType() { - return null; - } + @Override + public void execute(CommandContext context) { + String[] args = context.getArgumentsAsArray(); + String currency = "USD"; - @Override - public String execute(MessageReceivedEvent event, String[] args) { - String currency = "USD"; + if (args.length > 0) { - if (args.length > 0) { + if (args.length == 2) { + if (Currency.isCurrency(args[1].toUpperCase())) + currency = args[1].toUpperCase(); + else { + throw new CommandErrorException("Please enter a valid currency", context, null); + } - if (args.length == 2) { - if (Currency.isCurrency(args[1].toUpperCase())) - currency = args[1].toUpperCase(); - else { - event.getTextChannel().sendMessage("Please enter a valid currency").queue(); - return null; - } + } - } + String crypto = args[0].toUpperCase(); + String finalCurrency = currency; + context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + String price = "0"; + Locale usa = new Locale("en", "US"); + NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); + dollarFormat.setMaximumFractionDigits(24); - String finalCurrency = currency; - event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + try { + WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); + price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); - try { - WebModule ethereumHttp = new WebModule(baseURL + "?fsym=" + args[0] + "&tsyms=" + finalCurrency.toUpperCase()).request(); - price = Double.toString(ethereumHttp.getAsObject().getDouble(finalCurrency)); - - if (price == null) - throw new IllegalArgumentException("Crypto doesn't exist"); - - } catch (IOException | JSONException | IllegalArgumentException e) { - e.printStackTrace(); - t.editMessage("Error getting price!").queue(); - } - - t.editMessage(String.format("The current price of %s in %s is %s$", args[0].toUpperCase(), finalCurrency, price)).queue(); - }); - } + } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { + t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); + throw new CommandExecutionException("Error during web request", context, e); + } - return null; - } + + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); + }); + } + } } diff --git a/src/main/java/netneutrality/command/crypto/Currency.java b/src/main/java/netneutrality/command/crypto/Currency.java index 2b8235a..20c4013 100644 --- a/src/main/java/netneutrality/command/crypto/Currency.java +++ b/src/main/java/netneutrality/command/crypto/Currency.java @@ -1,8 +1,14 @@ package netneutrality.command.crypto; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ public enum Currency { - AED("AED"), AFN("AFN"), ALL("ALL"), AMD("AMD"), ANG("ANG"), AOA("AOA"), ARS("ARS"), AUD("AUD"), AWG("AWG"), AZN("AZN"), BAM("BAM"), BBD("BBD"), + AED("AED"), AFN("AFN"), ALL("ALL"), AMD("AMD"), ANG("ANG"), AOA("AOA"), ARS("ARS"), AUD("AUD"), AWG("AWG"), AZN("AZN"), BAM("BAM"), BBD("BBD"), BDT("BDT"), BGN("BGN"), BHD("BHD"), BIF("BIF"), BMD("BMD"), BND("BND"), BOB("BOB"), BOV("BOV"), BRL("BRL"), BSD("BSD"), BTN("BTN"), BWP("BWP"), BYN("BYN"), BYR("BYR"), BZD("BZD"), CAD("CAD"), CDF("CDF"), CHE("CHE"), CHF("CHF"), CHW("CHW"), CLF("CLF"), CLP("CLP"), CNY("CNY"), COP("COP"), COU("COU"), CRC("CRC"), CUC("CUC"), CUP("CUP"), CVE("CVE"), CZK("CZK"), DJF("DJF"), DKK("DKK"), DOP("DOP"), DZD("DZD"), EGP("EGP"), ERN("ERN"), @@ -17,24 +23,30 @@ public enum Currency { TWD("TWD"), TZS("TZS"), UAH("UAH"), UGX("UGX"), USD("USD"), USN("USN"), UYI("UYI"), UYU("UYU"), UZS("UZS"), VEF("VEF"), VND("VND"), VUV("VUV"), WST("WST"), XAF("XAF"), XAG("XAG"), XAU("XAU"), XBA("XBA"), XBB("XBB"), XBC("XBC"), XBD("XBD"), XCD("XCD"), XDR("XDR"), XFU("XFU"), XOF("XOF"), XPD("XPD"), XPF("XPF"), XPT("XPT"), XSU("XSU"), XTS("XTS"), XUA("XUA"), XXX("XXX"), YER("YER"), ZAR("ZAR"), ZMW("ZMW"); - - private final String iso4217Code; - Currency(String code) { + private final String iso4217Code; + + Currency(String code) { this.iso4217Code = code; } - - @Override - public String toString() { + + public String getIso4217Code() { return iso4217Code; } - - public static boolean isCurrency(String str) { - for (Currency c : Currency.values()) { - if (c.name().equals(str.toUpperCase())) - return true; - } - - return false; - } + + @Override + public String toString() { + return "Currency{" + + "iso4217Code='" + iso4217Code + '\'' + + '}'; + } + + public static boolean isCurrency(String str) { + for (Currency c : Currency.values()) { + if (c.name().equals(str.toUpperCase())) + return true; + } + + return false; + } } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 2f43a3d..29b8d64 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -1,98 +1,96 @@ package netneutrality.command.crypto; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import java.io.IOException; -import java.util.function.Consumer; - +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.http.WebModule; import org.json.JSONException; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.http.WebModule; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.Locale; public class EthereumPriceCommand extends AbstractCommand { - - private String currency; - private final String currencyUrl = "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms="; - private String price = ""; - public EthereumPriceCommand() { - this.currency = "USD"; - } - - private String messageBuilder(String price) { - return "The current ethereum price in " + this.currency + " is " + price + "$"; - } + private final String baseURL = "https://min-api.cryptocompare.com/data/price"; + private final String crypto = "ETH"; - @Override - public String execute(MessageReceivedEvent event, String[] args) throws JSONException, ArrayIndexOutOfBoundsException { - - if (args.length == 1) { - if (Currency.isCurrency(args[0].toUpperCase())) - this.currency = args[0].toUpperCase(); - else { - event.getTextChannel().sendMessage("Please enter a valid currency").queue(); - return null; - } - - } - - event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + @Override + public boolean needAdmin() { + return false; + } - try { - WebModule ethereumHttp = new WebModule(currencyUrl + currency.toUpperCase()).request(); - price = Double.toString(ethereumHttp.getAsObject().getDouble(currency)); + @Override + public boolean isEnabled() { + return true; + } - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - t.editMessage("Error getting ethereum price!").queue(); - } - t.editMessage(messageBuilder(price)).queue(); - }); + @Override + public String getCommand() { + return "ethereum"; + } - return null; - } + @Override + public String[] getAlias() { + return new String[]{"eth"}; + } - @Override - public boolean needAdmin() { - return false; - } + @Override + public String getUsage() { + return null; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public String getDescription() { + return "Get the ethereum price"; + } - @Override - public String getCommand() { - return "ethereum"; - } + @Override + public CommandType getType() { + return CommandType.CRYPTO; + } - @Override - public String[] getAlias() { - return new String[] {"eth"}; - } + @Override + public void execute(CommandContext context) { + String[] args = context.getArgumentsAsArray(); + String currency = "USD"; - @Override - public String getUsage() { - return null; - } + if (args.length == 1) { + if (Currency.isCurrency(args[0].toUpperCase())) + currency = args[0].toUpperCase(); + else { + throw new CommandErrorException("Please enter a valid currency", context, null); + } - @Override - public String getDescription() { - return "Get the ethereum price"; - } + } - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } + String finalCurrency = currency; + context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + String price = "0"; + Locale usa = new Locale("en", "US"); + NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); + dollarFormat.setMaximumFractionDigits(24); - @Override - public CommandType getType() { - return null; - } + try { + WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); + price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + + } catch (IOException | JSONException | IllegalArgumentException e) { + t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); + throw new CommandExecutionException("Error during web request", context, e); + } + + t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + + }); + } } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index c1d2616..cc4439c 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -1,97 +1,95 @@ package netneutrality.command.crypto; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import java.io.IOException; -import java.util.function.Consumer; - +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.http.WebModule; import org.json.JSONException; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.http.WebModule; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.Locale; public class LitecoinPriceCommand extends AbstractCommand { - private String currency; - private final String currencyUrl = "https://min-api.cryptocompare.com/data/price?fsym=LTC&tsyms="; - private String price; + private final String baseURL = "https://min-api.cryptocompare.com/data/price"; + private final String crypto = "LTC"; - public LitecoinPriceCommand() { - this.currency = "USD"; - } - - private String messageBuilder(String price) { - return "The current litecoin price in " + this.currency + " is " + price + "$"; - } + @Override + public boolean needAdmin() { + return false; + } - @Override - public String execute(MessageReceivedEvent event, String[] args) throws ArrayIndexOutOfBoundsException, JSONException { - - if (args.length == 1) { - if (Currency.isCurrency(args[0].toUpperCase())) - this.currency = args[0].toUpperCase(); - else { - event.getTextChannel().sendMessage("Please enter a valid currency").queue(); - return null; - } - - } - - event.getTextChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + @Override + public boolean isEnabled() { + return true; + } - try { - WebModule litecoinHttp = new WebModule(currencyUrl + currency).request(); - price = litecoinHttp.getAsArray().getJSONObject(0).getString("price_" + currency.toLowerCase()); - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - t.editMessage("Error getting litecoin price!").queue(); - } - t.editMessage(messageBuilder(price)).queue(); + @Override + public String getCommand() { + return "litecoin"; + } - }); - - return null; - } + @Override + public String[] getAlias() { + return new String[]{"ltc"}; + } - @Override - public boolean needAdmin() { - return false; - } + @Override + public String getUsage() { + return null; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public String getDescription() { + return "Get the litecoin price"; + } - @Override - public String getCommand() { - return "litecoin"; - } + @Override + public CommandType getType() { + return CommandType.CRYPTO; + } - @Override - public String[] getAlias() { - return new String[] {"ltc"}; - } + @Override + public void execute(CommandContext context) { + String[] args = context.getArgumentsAsArray(); + String currency = "USD"; - @Override - public String getUsage() { - return null; - } + if (args.length == 1) { + if (Currency.isCurrency(args[0].toUpperCase())) + currency = args[0].toUpperCase(); + else { + throw new CommandErrorException("Please enter a valid currency", context, null); + } - @Override - public String getDescription() { - return "Get the litecoin price"; - } + } - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } + String finalCurrency = currency; + context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { + String price = "0"; + Locale usa = new Locale("en", "US"); + NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); + dollarFormat.setMaximumFractionDigits(24); - @Override - public CommandType getType() { - return null; - } + try { + WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); + price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + + } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { + t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); + throw new CommandExecutionException("Error during web request", context, e); + } + + t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + + }); + } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index b1a6ce3..b160d53 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -1,9 +1,14 @@ package netneutrality.command.message; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; @@ -27,7 +32,7 @@ public class BlacklistCommand extends AbstractCommand { @Override public String[] getAlias() { - return new String[] {"bl"}; + return new String[]{"bl"}; } @Override @@ -40,18 +45,14 @@ public class BlacklistCommand extends AbstractCommand { return "Manages the blacklist of your server."; } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } - @Override public CommandType getType() { - return null; + return CommandType.ADMINISTRATION; } @Override - public String execute(MessageReceivedEvent event, String[] args) { + public void execute(CommandContext context) { + String[] args = context.getArgumentsAsArray(); if (args.length > 0 && args.length < 3) { String word = (args.length == 2 ? args[1] : ""); @@ -59,15 +60,15 @@ public class BlacklistCommand extends AbstractCommand { switch (args[0]) { case "get": - event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { + context.getChannel().sendMessage("Retrieving list, please wait...").queue(t -> { StringBuilder sb = new StringBuilder(); - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(event.getGuild().getId(), mBlacklists -> { + ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(context.getGuild().getId(), mBlacklists -> { for (MBlacklist bl : mBlacklists) { sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); } - t.editMessage("List of blacklisted words for this server [" + event.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); + t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); }); }); @@ -76,22 +77,22 @@ public class BlacklistCommand extends AbstractCommand { case "add": - ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, event.getAuthor().getId(), event.getGuild().getId()), response -> { + ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, context.getDiscordUser().getId(), context.getGuild().getId()), response -> { if (response) { - event.getTextChannel().sendMessage("Added the word \"" + word + "\" to the blacklist.").queue(); + context.getChannel().sendMessage("Added the word \"" + word + "\" to the blacklist.").queue(); } else { - event.getTextChannel().sendMessage("Error adding \"" + word + "\" to the blacklist. It's already blacklisted!").queue(); + context.getChannel().sendMessage("Error adding \"" + word + "\" to the blacklist. It's already blacklisted!").queue(); } }); break; case "remove": - ((DBBlacklist) DBController.get("blacklist")).delete(word, event.getGuild().getId(), success -> { + ((DBBlacklist) DBController.get("blacklist")).delete(word, context.getGuild().getId(), success -> { if (success) { - event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); } else { - event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); } }); @@ -99,11 +100,11 @@ public class BlacklistCommand extends AbstractCommand { case "disable": - ((DBBlacklist) DBController.get("blacklist")).disable(word, event.getGuild().getId(), success -> { + ((DBBlacklist) DBController.get("blacklist")).disable(word, context.getGuild().getId(), success -> { if (success) { - event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); } else { - event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); } }); @@ -111,11 +112,11 @@ public class BlacklistCommand extends AbstractCommand { case "enable": - ((DBBlacklist) DBController.get("blacklist")).enable(word, event.getGuild().getId(), success -> { + ((DBBlacklist) DBController.get("blacklist")).enable(word, context.getGuild().getId(), success -> { if (success) { - event.getTextChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); } else { - event.getTextChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); } }); @@ -123,8 +124,6 @@ public class BlacklistCommand extends AbstractCommand { } } - - return null; } } diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index 98d1f5e..94ae9cd 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -1,61 +1,59 @@ package netneutrality.command.message; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; import netneutrality.utils.ChannelFunction; public class PruneCommand extends AbstractCommand { - @Override - public boolean needAdmin() { - return true; - } + @Override + public boolean needAdmin() { + return true; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public String getCommand() { - return "prune"; - } + @Override + public String getCommand() { + return "prune"; + } - @Override - public String[] getAlias() { - return new String[] {"purge"}; - } + @Override + public String[] getAlias() { + return new String[]{"purge"}; + } - @Override - public String getUsage() { - return ""; - } + @Override + public String getUsage() { + return ""; + } - @Override - public String getDescription() { - return "Delete n messages from the channel you are currently on"; - } + @Override + public String getDescription() { + return "Delete n messages from the channel you are currently on"; + } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + @Override + public CommandType getType() { + return CommandType.ADMINISTRATION; + } - @Override - public CommandType getType() { - return null; - } - - @Override - public String execute(MessageReceivedEvent event, String[] args) { - if (args.length == 1) - ChannelFunction.bulkDeleteMessage(event.getTextChannel(), Integer.parseInt(args[0])); - else - event.getTextChannel().sendMessage("Failed to delete messages!").queue(); - - return null; - } + @Override + public void execute(CommandContext context) { + if (context.getArgumentsAsArray().length == 1) + ChannelFunction.bulkDeleteMessage(context.getChannel(), Integer.parseInt(context.getArgumentsAsArray()[0])); + else + context.getChannel().sendMessage("Failed to delete messages!").queue(); + } } diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 76c2f0c..713ff74 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -3,14 +3,13 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; +import netneutrality.command.CommandType; import netneutrality.music.MusicManager; public class BitconnectCommand extends AbstractMusicCommand { @@ -41,33 +40,15 @@ public class BitconnectCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; + public CommandType getType() { + return CommandType.UNLISTED; } @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", context, false, true); - if (member.getVoiceState().inVoiceChannel()) { - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", event.getTextChannel(), member, true); - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else { - player.connect(vChannel); - player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", event.getTextChannel(), member, true); - } - - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - event.getMessage().delete().queue(); - - return null; + context.getMessage().delete().queue(); } } diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index a809e42..995b7f2 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -3,16 +3,16 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; +import netneutrality.utils.MusicUtils; public class CurrentlyPlayingCommand extends AbstractMusicCommand { @@ -42,34 +42,16 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + Member member = context.getGuildUser(); + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); + if (player.getCurrentlyPlaying() != null) { + context.getChannel().sendMessageEmbeds(MessageFunction.buildCurrentlyPlayingMessage(player, member)).queue(); + } else { + context.getChannel().sendMessage("Player is not playing any tracks right now").queue(); + } - if (member.getVoiceState().inVoiceChannel()) { - MusicManager player = MusicManager.get(event.getGuild()); - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - if (player.getCurrentlyPlaying() != null) { - event.getTextChannel().sendMessageEmbeds(MessageFunction.buildCurrentlyPlayingMessage(player, member)).queue(); - } else { - event.getTextChannel().sendMessage("Player is not playing any track right now").queue(); - } - - } else - event.getTextChannel().sendMessage("Player is not in your voice channel").queue(); - } else { - event.getTextChannel().sendMessage("Player is not in a voice channel").queue(); - } - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; } } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index facb8fb..14bdd20 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -3,15 +3,14 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class DeleteQueueCommand extends AbstractMusicCommand { @Override @@ -45,36 +44,17 @@ public class DeleteQueueCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); + int queueSize = player.getScheduler().getQueue().size(); + if (queueSize > 0) { + player.getScheduler().getQueue().clear(); + context.getChannel().sendMessage("Removed " + queueSize + (queueSize > 1 ? " tracks" : "track") + " from the queue").queue(); + } else { + context.getChannel().sendMessage("Queue is empty!").queue(); + } - if (member.getVoiceState().inVoiceChannel()) { - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - int queueSize = player.getScheduler().getQueue().size(); - if (queueSize > 0) { - player.getScheduler().getQueue().clear(); - event.getTextChannel().sendMessage("Removed " + queueSize + (queueSize > 1 ? " tracks" : "track") + " from the queue").queue(); - } else { - event.getTextChannel().sendMessage("Queue is empty!").queue(); - } - - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else { - event.getTextChannel().sendMessage("Not in a voice channel").queue(); - } - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; } } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 209a642..3a2290a 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -3,15 +3,15 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class JoinCommand extends AbstractMusicCommand { @@ -41,29 +41,11 @@ public class JoinCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - - if (member.getVoiceState().inVoiceChannel()) { - MusicManager player = MusicManager.get(event.getGuild()); - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (!player.isConnected()) { - if (!player.isConnectedTo(vChannel)) { - player.connect(vChannel); - } else - event.getTextChannel().sendMessage("Already in a voice channel").queue(); - } else - event.getTextChannel().sendMessage("Already in a voice channel").queue(); - - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; + VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); + player.connect(vChannel); } } diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 7b2c512..0c18e89 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -3,15 +3,14 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class LeaveCommand extends AbstractMusicCommand { @Override @@ -45,20 +44,10 @@ public class LeaveCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnectedTo(vChannel)) { - player.leave(); - } - - return null; + player.leave(); } } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index aa92d1f..3df9ac4 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -3,14 +3,12 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; public class PlayCommand extends AbstractMusicCommand { @@ -41,34 +39,16 @@ public class PlayCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); + if (context.getArgumentsAsArray().length > 0) { + context.getMessage().delete().queue(); + player.play(context.getMessageText(), context, false, false); - if (member.getVoiceState().inVoiceChannel()) { - VoiceChannel vChannel = member.getVoiceState().getChannel(); + } else { + context.getChannel().sendMessage("No url provided").queue(); + } - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - event.getMessage().delete().queue(); - - player.play(args[0], event.getTextChannel(), event.getMember(), false); - - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else { - player.connect(vChannel); - event.getMessage().delete().queue(); - player.play(args[0], event.getTextChannel(), event.getMember(), false); - } - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; } } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 914c981..42818dc 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -3,15 +3,14 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class SkipCommand extends AbstractMusicCommand { @Override @@ -45,28 +44,10 @@ public class SkipCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); - - if (member.getVoiceState().inVoiceChannel()) { - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - player.skip(); - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else - event.getTextChannel().sendMessage("Not in a voice channel").queue(); - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; + player.skip(); } } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 4db372b..e4cad4b 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -3,15 +3,14 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class StopCommand extends AbstractMusicCommand { @Override @@ -45,29 +44,10 @@ public class StopCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); - - if (member.getVoiceState().inVoiceChannel()) { - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - player.leave(); - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else - event.getTextChannel().sendMessage("Not in a voice channel").queue(); - - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; + player.leave(); } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 1f6a60e..580112e 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -3,16 +3,16 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; +import netneutrality.utils.MusicUtils; public class ViewQueueCommand extends AbstractMusicCommand { @Override @@ -46,36 +46,16 @@ public class ViewQueueCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + Member member = context.getGuildUser(); + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - - if (member.getVoiceState().inVoiceChannel()) { - MusicManager player = MusicManager.get(event.getGuild()); - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - int queueSize = player.getScheduler().getQueue().size(); - if (queueSize > 0) { - - event.getTextChannel().sendMessageEmbeds(MessageFunction.buildViewQueueMessage(player, member)).queue(); - } else { - event.getTextChannel().sendMessage("Queue is empty!").queue(); - } - - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else { - event.getTextChannel().sendMessage("Player is not connected").queue(); - } - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; + int queueSize = player.getScheduler().getQueue().size(); + if (queueSize > 0) { + context.getChannel().sendMessageEmbeds(MessageFunction.buildViewQueueMessage(player, member)).queue(); + } else { + context.getChannel().sendMessage("Queue is empty!").queue(); + } } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 843e056..576cac6 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -3,15 +3,15 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; +import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class VolumeCommand extends AbstractMusicCommand { @Override @@ -45,36 +45,16 @@ public class VolumeCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + public void execute(CommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(player, context); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - Member member = event.getMember(); - MusicManager player = MusicManager.get(event.getGuild()); + try { + int volume = Integer.parseInt(context.getArgumentsAsArray()[0]); + player.setVolume(volume); + } catch (NumberFormatException e) { + throw new CommandErrorException("Please enter a value from 0 to 100", context, null); + } - if (member.getVoiceState().inVoiceChannel()) { - VoiceChannel vChannel = member.getVoiceState().getChannel(); - - if (player.isConnected()) { - if (player.isConnectedTo(vChannel)) { - - try { - int volume = Integer.parseInt(args[0]); - player.setVolume(volume); - } catch (NumberFormatException e) { - e.printStackTrace(); - } - - } else - event.getTextChannel().sendMessage("Not in your voice channel").queue(); - } else - event.getTextChannel().sendMessage("Not in a voice channel").queue(); - - } else - event.getTextChannel().sendMessage("You are not in a voice channel").queue(); - - return null; } } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index b15c456..54df3dc 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -1,13 +1,13 @@ -package netneutrality.command.music;/* +package netneutrality.command.music; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.Visibility; +import netneutrality.command.CommandContext; public class VoteSkipCommand extends AbstractMusicCommand { @@ -37,12 +37,7 @@ public class VoteSkipCommand extends AbstractMusicCommand { } @Override - public Visibility getVisibility() { - return null; - } + public void execute(CommandContext context) { - @Override - public String execute(MessageReceivedEvent event, String[] args) { - return null; } } diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 0190ef8..e5bd4b0 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -1,117 +1,116 @@ package netneutrality.command.specific; - -import java.awt.Color; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; import netneutrality.db.models.MMessage; import netneutrality.utils.Settings; +import java.awt.*; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; + public class DatabaseCommand extends AbstractCommand { - @Override - public boolean needAdmin() { - return true; - } + @Override + public boolean needAdmin() { + return true; + } - @Override - public boolean isEnabled() { - return true; - } + @Override + public boolean isEnabled() { + return true; + } - @Override - public String getCommand() { - return "database"; - } + @Override + public String getCommand() { + return "database"; + } - @Override - public String[] getAlias() { - return new String[] { "db" }; - } + @Override + public String[] getAlias() { + return new String[]{"db"}; + } - @Override - public String getUsage() { - return null; - } + @Override + public String getUsage() { + return null; + } - @Override - public String getDescription() { - return null; - } + @Override + public String getDescription() { + return null; + } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } + @Override + public CommandType getType() { + return CommandType.UNLISTED; + } - @Override - public CommandType getType() { - return null; - } + @Override + public void execute(CommandContext context) { + //TODO: Clean up the mess + String[] args = context.getArgumentsAsArray(); + context.getMessage().delete().queue(); - @Override - public String execute(MessageReceivedEvent event, String[] args) { - //TODO: Clean up the mess + if (!context.getGuildUser().getId().equals(Settings.getInstance().getCreatorId())) + return; - event.getMessage().delete().queue(); + if (args.length > 0) { + switch (args[0]) { - if (!event.getAuthor().getId().equals(Settings.getInstance().getCreatorId())) - return null; + case "message": - if (args.length > 0) { - switch (args[0]) { + if (args.length > 1) { - case "message": + MMessage message = ((DBMessage) DBController.get("message")).getMessage(args[1]); + if (message != null) { + EmbedBuilder embed = new EmbedBuilder(); + embed.setColor(Color.BLUE); + embed.setTimestamp( + DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT).parse(message.getDateSent())); + embed.setFooter("Guild : " + message.getServerId() + " | ID : " + message.getMessageId(), null); + embed.setDescription( + "Message from " + message.getSender() + " on the channel " + message.getChannelName()); + embed.addField("Message: ", "" + message.getMessage(), false); + context.getChannel().sendMessageEmbeds(embed.build()).queue(); + } else { + //TODO: cached user lol xd + User user = context.getJDA().getUserById(args[1]); + if (user != null) { + ArrayList messages = ((DBMessage) DBController.get("message")) + .getMessagesFromUser(user.getName(), context.getGuild().getName(), 10); + EmbedBuilder embed = new EmbedBuilder(); + embed.setColor(Color.BLUE); + embed.setTimestamp(OffsetDateTime.now()); + for (MMessage message1 : messages) { + embed.addField( + "Message in channel \"" + message1.getChannelName() + "\" sent on " + + message1.getDateSent(), + "" + message1.getMessage(), false); + } + embed.setFooter("Guild : " + context.getGuild().getName(), null); - if (args.length > 1) { + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessageEmbeds(embed.build()).queue()); + } + } - MMessage message = ((DBMessage) DBController.get("message")).getMessage(args[1]); - if (message != null) { - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.BLUE); - embed.setTimestamp( - DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT).parse(message.getDateSent())); - embed.setFooter("Guild : " + message.getServerId() + " | ID : " + message.getMessageId(), null); - embed.setDescription( - "Message from " + message.getSender() + " on the channel " + message.getChannelName()); - embed.addField("Message: ", "" + message.getMessage(), false); - event.getTextChannel().sendMessageEmbeds(embed.build()).queue(); - } else { - User user = event.getJDA().getUserById(args[1]); - if (user != null) { - ArrayList messages = ((DBMessage) DBController.get("message")) - .getMessagesFromUser(user.getName(), event.getGuild().getName(), 10); - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.BLUE); - embed.setTimestamp(OffsetDateTime.now()); - for (MMessage message1 : messages) { - embed.addField( - "Message in channel \"" + message1.getChannelName() + "\" sent on " - + message1.getDateSent(), - "" + message1.getMessage(), false); - } - embed.setFooter("Guild : " + event.getGuild().getName(), null); + } - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessageEmbeds(embed.build()).queue()); - } - } - - } - - break; - } - } - - return null; - } + break; + } + } + } } diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index cf0d8d1..21bbeaf 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -3,13 +3,14 @@ package netneutrality.command.specific; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.MessageBuilder; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; import netneutrality.music.MusicManager; import netneutrality.utils.Settings; @@ -36,7 +37,7 @@ public class EvalMethod extends AbstractCommand { @Override public String[] getAlias() { - return new String[] {"eval"}; + return new String[]{"eval"}; } @Override @@ -49,42 +50,38 @@ public class EvalMethod extends AbstractCommand { return null; } - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } - @Override public CommandType getType() { - return null; + return CommandType.UNLISTED; } @Override - public String execute(MessageReceivedEvent event, String[] args) { + public void execute(CommandContext context) { - if (event.getAuthor().getId().equals(Settings.getInstance().getCreatorId())) { + if (context.getDiscordUser().getId().equals(Settings.getInstance().getCreatorId())) { ScriptEngine se = new ScriptEngineManager().getEngineByName("Nashorn"); + + MessageBuilder message = new MessageBuilder(); + try { se.eval("var imports = new JavaImporter(java.io, java.lang, java.util);"); + se.put("jda", context.getJDA()); + se.put("guild", context.getGuild()); + se.put("channel", context.getChannel()); + se.put("member", context.getGuildUser()); + se.put("music", MusicManager.get(context.getGuild())); + + String script = String.format("( function() { with (imports) { return %s } } )();", context.getMessageText()); + + message.append("Evaluated Successfully:"); + message.appendCodeBlock(se.eval(script).toString(), "java"); + context.getChannel().sendMessage(message.build()).queue(); + } catch (ScriptException e) { e.printStackTrace(); + context.getChannel().sendMessage(" An exception was thrown:\n```\n" + e.getMessage() + " ```").queue(); } - se.put("event", event); - se.put("jda", event.getJDA()); - se.put("guild", event.getGuild()); - se.put("channel", event.getChannel()); - se.put("member", event.getMember()); - se.put("music", MusicManager.get(event.getGuild())); - - try { - event.getTextChannel().sendMessage(" Evaluated Successfully:\n```"+se.eval("(function() {with (imports) {\nreturn " + args + "\n}})();") + " ```").queue(); - } - catch(Exception e) { - event.getTextChannel().sendMessage(" An exception was thrown:\n```\n"+e+" ```").queue(); - } } - - return null; } } diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index 19d7455..22f275e 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -1,16 +1,17 @@ package netneutrality.command.specific; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; public class LoggingCommand extends AbstractCommand { - public LoggingCommand() { - - } - @Override public boolean needAdmin() { return true; @@ -41,20 +42,13 @@ public class LoggingCommand extends AbstractCommand { return null; } - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } - @Override public CommandType getType() { - return null; + return CommandType.UNLISTED; } @Override - public String execute(MessageReceivedEvent event, String[] args) { + public void execute(CommandContext context) { - - return null; } } diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java index 5432075..d629432 100644 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ b/src/main/java/netneutrality/command/specific/SellyCommand.java @@ -3,13 +3,13 @@ package netneutrality.command.specific; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; import netneutrality.db.DBController; import netneutrality.db.controllers.DBSettings; import netneutrality.db.models.MSellyOrder; @@ -49,19 +49,14 @@ public class SellyCommand extends AbstractCommand { return null; } - @Override - public Visibility getVisibility() { - return Visibility.PRIVATE; - } - @Override public CommandType getType() { - return null; + return CommandType.UNLISTED; } @Override - public String execute(MessageReceivedEvent event, String[] args) { - + public void execute(CommandContext context) { + //TODO: delete or move to custom command when implemented String sellyEmail = ((DBSettings) DBController.get("settings")).getSettingsByKey("selly_email"); String sellyKey = ((DBSettings) DBController.get("settings")).getSettingsByKey(""); Selly selly = new Selly(sellyEmail, sellyKey); @@ -70,24 +65,22 @@ public class SellyCommand extends AbstractCommand { System.out.println(selly.getProducts().toString()); - if (args.length > 1) { - String email = args[0]; - String id = args[1]; + if (context.getArgumentsAsArray().length > 1) { + String email = context.getArgumentsAsArray()[0]; + String id = context.getArgumentsAsArray()[1]; if (orders.containsKey(id)) { MSellyOrder order = orders.get(id); if (email.equals(order.getEmail())) { if (order.getStatus() == 100) { - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage("success").queue()); + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("success").queue()); } else - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage("not completed").queue()); + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("not completed").queue()); } else - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage("wrong email").queue()); + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("wrong email").queue()); } else - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage("order doesn't exist").queue()); + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("order doesn't exist").queue()); } else - event.getAuthor().openPrivateChannel().queue(t -> t.sendMessage("usage : $selly ").queue()); - - return null; + context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("usage : $selly ").queue()); } } diff --git a/src/main/java/netneutrality/command/specific/ShutdownCommand.java b/src/main/java/netneutrality/command/specific/ShutdownCommand.java deleted file mode 100644 index d053765..0000000 --- a/src/main/java/netneutrality/command/specific/ShutdownCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -package netneutrality.command.specific; - -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.Visibility; - -public class ShutdownCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return false; - } - - @Override - public String getCommand() { - return null; - } - - @Override - public String[] getAlias() { - return null; - } - - @Override - public String getUsage() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } - - @Override - public CommandType getType() { - return null; - } - - @Override - public String execute(MessageReceivedEvent event, String[] args) { - event.getJDA().shutdown(); - System.exit(0); - return null; - } - -} diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index c8843b3..9d7ef72 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -3,15 +3,13 @@ package netneutrality.command.specific; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.command.Visibility; -import netneutrality.utils.MessageFunction; -import netneutrality.utils.Settings; public class TestCommand extends AbstractCommand { @@ -22,7 +20,7 @@ public class TestCommand extends AbstractCommand { @Override public boolean isEnabled() { - return true; + return false; } @Override @@ -45,22 +43,13 @@ public class TestCommand extends AbstractCommand { return null; } - @Override - public Visibility getVisibility() { - return Visibility.BOTH; - } - @Override public CommandType getType() { - return null; + return CommandType.UNLISTED; } @Override - public String execute(MessageReceivedEvent event, String[] args) { - if (event.getAuthor().getId().equals(Settings.getInstance().getCreatorId())) { - MessageFunction.isStartingWithMention(event.getMessage()); - } + public void execute(CommandContext context) { - return null; } } diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java index cca67e1..7dbc6a6 100644 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -16,6 +16,12 @@ public class DBGuild extends AbstractController { } } + public void removeGuildInDB(Guild g) { + if (database.exists("guilds", "guild_id", g.getId())) { + database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), "0", null).blocking(); + } + } + @Override public String getControllerName() { return "guild"; diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 2988246..c360293 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -4,10 +4,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.function.Consumer; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.*; import netneutrality.db.AbstractController; import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; @@ -30,7 +27,7 @@ public class DBMessage extends AbstractController { return database; } - public void log(Guild guild, TextChannel channel, User author, Message message) { + public void log(Guild guild, TextChannel channel, Member author, Message message) { String serverid = guild.getId(); String channelid = channel.getId(); String userid = author.getId(); diff --git a/src/main/java/netneutrality/exceptions/CommandErrorException.java b/src/main/java/netneutrality/exceptions/CommandErrorException.java new file mode 100644 index 0000000..7debfb4 --- /dev/null +++ b/src/main/java/netneutrality/exceptions/CommandErrorException.java @@ -0,0 +1,25 @@ +package netneutrality.exceptions;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.command.CommandContext; + +/** + * Used to reply with a message in the text channel where the command was executed + */ +public class CommandErrorException extends CommandException { + + /** + * Used to reply with a message in the text channel where the command was executed + * + * @param message Message to send to the channel + * @param context The command context + */ + public CommandErrorException(String message, CommandContext context, Throwable cause) { + super(message, context, cause); + + } +} diff --git a/src/main/java/netneutrality/exceptions/CommandException.java b/src/main/java/netneutrality/exceptions/CommandException.java new file mode 100644 index 0000000..a9eacde --- /dev/null +++ b/src/main/java/netneutrality/exceptions/CommandException.java @@ -0,0 +1,23 @@ +package netneutrality.exceptions;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.command.CommandContext; + +public abstract class CommandException extends RuntimeException { + + public static String DEFAULT_MESSAGE = "Unknown error during command execution."; + private final CommandContext context; + + public CommandException(String message, CommandContext context, Throwable cause) { + super(message== null ? DEFAULT_MESSAGE : message, cause); + this.context = context; + } + + public CommandContext getCommandContext() { + return context; + } +} diff --git a/src/main/java/netneutrality/exceptions/CommandExecutionException.java b/src/main/java/netneutrality/exceptions/CommandExecutionException.java new file mode 100644 index 0000000..74f9341 --- /dev/null +++ b/src/main/java/netneutrality/exceptions/CommandExecutionException.java @@ -0,0 +1,23 @@ +package netneutrality.exceptions;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.command.CommandContext; + +/** + * Logs the error internally, without sending a message + */ +public class CommandExecutionException extends CommandException { + + /** + * Logs the error internally, without sending a message + * @param context The command context + */ + public CommandExecutionException(String message, CommandContext context, Throwable cause) { + super(message, context, cause); + } + +} diff --git a/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java b/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java index 71b1ae6..4cffbd5 100644 --- a/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java +++ b/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java @@ -19,9 +19,8 @@ package netneutrality.exceptions; import java.sql.SQLException; public class UnimplementedParameterException extends SQLException { - - private static final long serialVersionUID = 4721555678157694115L; - private String s; + + private final String s; public UnimplementedParameterException(Object parameter) { s = "Parameter not implemented at for: " + parameter; diff --git a/src/main/java/netneutrality/handler/EditHandler.java b/src/main/java/netneutrality/handler/EditHandler.java index 883b171..ad59f9a 100644 --- a/src/main/java/netneutrality/handler/EditHandler.java +++ b/src/main/java/netneutrality/handler/EditHandler.java @@ -1,5 +1,12 @@ package netneutrality.handler; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import java.awt.Color; import net.dv8tion.jda.api.EmbedBuilder; @@ -12,40 +19,40 @@ import netneutrality.db.controllers.DBSettings; import netneutrality.db.models.MTableModel; public class EditHandler extends ListenerAdapter { - - @Override - public void onMessageUpdate(MessageUpdateEvent event) { - - if (event.getAuthor().isBot()) return; - MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); + @Override + public void onMessageUpdate(MessageUpdateEvent event) { + + if (event.getAuthor().isBot()) return; + + MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); + + Object logChannel = table.getRowModel(0).getItem(0); + if (logChannel != null) { + String originalMessage = ((DBMessage) DBController.get("message")).getMessageString(event.getMessage().getId()); + ((DBMessage) DBController.get("message")).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); + + EmbedBuilder editEmbed = new EmbedBuilder(); + editEmbed.setColor(Color.RED); + editEmbed.setDescription(":pencil2: **Message edited by " + event.getAuthor().getName() + "**"); + try { + editEmbed.addField("Original message", (originalMessage == null ? "Not available" : originalMessage), false); + } catch (IllegalArgumentException ex) { + editEmbed.addField("Original message :", "Message too long. Check db for full message", false); + } + + try { + editEmbed.addField("Edited to :", event.getMessage().getContentDisplay(), false); + } catch (IllegalArgumentException ex) { + editEmbed.addField("Edited to :", "Message too long. Check db for full message", false); + } + + editEmbed.setFooter("ID : " + event.getMessageId(), null); + editEmbed.setTimestamp(event.getMessage().getTimeCreated()); + event.getJDA().getTextChannelById(logChannel.toString()).sendMessageEmbeds(editEmbed.build()).queue(); + } + + + } - Object logChannel = table.getRowModel(0).getItem(0); - if (logChannel != null) { - String originalMessage = ((DBMessage) DBController.get("message")).getMessageString(event.getMessage().getId()); - ((DBMessage) DBController.get("message")).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); - - EmbedBuilder editEmbed = new EmbedBuilder(); - editEmbed.setColor(Color.RED); - editEmbed.setDescription(":pencil2: **Message edited by " + event.getAuthor().getName() + "**"); - try { - editEmbed.addField("Original message", (originalMessage == null ? "Not available" : originalMessage), false); - } catch (IllegalArgumentException ex) { - editEmbed.addField("Original message :", "Message too long. Check db for full message", false); - } - - try { - editEmbed.addField("Edited to :", event.getMessage().getContentDisplay(), false); - } catch (IllegalArgumentException ex) { - editEmbed.addField("Edited to :", "Message too long. Check db for full message", false); - } - - editEmbed.setFooter("ID : " + event.getMessageId(), null); - editEmbed.setTimestamp(event.getMessage().getTimeCreated()); - event.getJDA().getTextChannelById(logChannel.toString()).sendMessageEmbeds(editEmbed.build()).queue(); - } - - - } - } diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index bfdac39..99bc553 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -1,30 +1,50 @@ package netneutrality.handler; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ -import netneutrality.MusicBot; -import netneutrality.utils.Settings; +import netneutrality.command.CommandContext; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogHandler { - private final static Logger logger = LoggerFactory.getLogger(LogHandler.class); + private final static Logger logger = LoggerFactory.getLogger(LogHandler.class); - /** - * Log the exception to the owner's log TextChannel as defined in {@link Settings#getLogChannel()} - * - * @param e The exceptions to log - */ - public static void log(Exception e) { + /** + * Log an exception accordingly + * + * @param e The exceptions to log + */ + public static void log(Exception e) { - logger.error(e.getMessage()); + if (e instanceof CommandErrorException) { + sendMessageToChannel((CommandErrorException) e); + } else if (e instanceof CommandExecutionException) { + logInternally((CommandExecutionException) e); + } else { + logger.error(e.getMessage(), e); + } - //TODO: to remove or add check if jda is started - String channel = Settings.getInstance().getLogChannel(); - MusicBot.getJDA().getTextChannelById(channel).sendMessage("Error : " + e).queue(); - - } + } - public static void logThread(Thread t, Throwable e) { - logger.error("Exception thrown in thread " + t, e); - } + public static void logThread(Thread t, Throwable e) { + logger.error("Exception thrown in thread {}", t); + log((Exception) e); + } + + private static void logInternally(CommandExecutionException error) { + CommandContext context = error.getCommandContext(); + logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommand(), context.getGuild().getId(), error.getMessage(), error); + } + + private static void sendMessageToChannel(CommandErrorException error) { + CommandContext context = error.getCommandContext(); + context.getChannel().sendMessage(error.getMessage()).queue(); + } } diff --git a/src/main/java/netneutrality/handler/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/MessageReceivedHandler.java new file mode 100644 index 0000000..5ac58d1 --- /dev/null +++ b/src/main/java/netneutrality/handler/MessageReceivedHandler.java @@ -0,0 +1,55 @@ +package netneutrality.handler; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.GuildManager; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; +import netneutrality.command.CommandManager; +import netneutrality.utils.Settings; +import org.jetbrains.annotations.NotNull; + +public class MessageReceivedHandler extends ListenerAdapter { + + @Override + public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + Message message = event.getMessage(); + Member member = event.getMember(); + User user = event.getAuthor(); + Guild guild = event.getGuild(); + TextChannel channel = event.getChannel(); + + if (user.isBot()) return; + if (event.isWebhookMessage()) return; + + GuildManager.getManager(guild).getRateLimiter().check(member, message, channel); + GuildManager.getManager(guild).checkAndLogMessage(message, member, channel); + + CommandContext context = CommandContext.createContext(event); + + String msg = message.getContentDisplay().trim(); + + if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + String cmd = msg.split(" ", 2)[0]; + + + if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { + AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); + + context.dispatch(c); + } + + } else { + GuildManager.getManager(guild).checkBlacklist(message, member, channel); + } + } + +} diff --git a/src/main/java/netneutrality/handler/NewCommandListener.java b/src/main/java/netneutrality/handler/NewCommandListener.java deleted file mode 100644 index b150b2e..0000000 --- a/src/main/java/netneutrality/handler/NewCommandListener.java +++ /dev/null @@ -1,77 +0,0 @@ -package netneutrality.handler; - - -import net.dv8tion.jda.api.entities.ChannelType; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.GuildManager; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandManager; -import netneutrality.command.Visibility; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBMessage; -import netneutrality.utils.MessageFunction; -import netneutrality.utils.Settings; -import netneutrality.utils.UserFunction; -import org.jetbrains.annotations.NotNull; - -public class NewCommandListener extends ListenerAdapter { - - public NewCommandListener() { - CommandManager.init(); - } - - @Override - public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { - if (event.getAuthor().isBot()) return; - if (event.isWebhookMessage()) return; - GuildManager.getManager(event.getGuild()).getRateLimiter().check(event.getMember(), event.getMessage(), event.getChannel()); - - - } - - @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { - - if (event.getAuthor().isBot()) return; - if (event.isWebhookMessage()) return; - - if (event.getMessage().isEdited()) - - if (event.isFromType(ChannelType.TEXT)) { - ((DBMessage) DBController.get("message")).log(event.getGuild(), event.getTextChannel(), event.getAuthor(), event.getMessage()); - } - - Message message = event.getMessage(); - String msg = message.getContentDisplay().trim(); - - if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); - String cmd = msg.split(" ", 2)[0]; - String[] args = msg.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); - - if (args.length == 1 && args[0].isEmpty()) - args = new String[0]; - - if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { - AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); - - if (Visibility.check(event.getChannel(), c.getVisibility())) { - if (c.needAdmin()) { - if (!UserFunction.isAdmin(event.getMember())) { - return; - } - } - - if (c.canBeExecutedBy(event.getGuild(), event.getMember())) { - c.execute(event, args); - } - } - } - } else { - MessageFunction.checkBlacklist(event.getGuild().getId(), event.getMessage(), event.getTextChannel(), msg); - } - } -} diff --git a/src/main/java/netneutrality/handler/ServerJoinHandler.java b/src/main/java/netneutrality/handler/ServerJoinHandler.java index ccffa70..a498130 100644 --- a/src/main/java/netneutrality/handler/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/ServerJoinHandler.java @@ -8,6 +8,7 @@ package netneutrality.handler; */ import net.dv8tion.jda.api.events.guild.GuildJoinEvent; +import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.db.DBController; import netneutrality.db.controllers.DBGuild; @@ -16,11 +17,14 @@ import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { @Override - public void onGuildJoin(@NotNull GuildJoinEvent event){ - if (!DBController.get().exists("guilds", "guild_id", event.getGuild().getId())) { - ((DBGuild) DBController.get("guild")).insertGuildInDB(event.getGuild()); - } + public void onGuildJoin(@NotNull GuildJoinEvent event) { + ((DBGuild) DBController.get("guild")).insertGuildInDB(event.getGuild()); + } + + @Override + public void onGuildLeave(@NotNull GuildLeaveEvent event) { + ((DBGuild) DBController.get("guild")).removeGuildInDB(event.getGuild()); } } diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index 7f76ce5..688fb46 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -3,7 +3,8 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; @@ -18,29 +19,29 @@ import java.nio.ByteBuffer; * provide20MsAudio(). */ public class AudioPlayerSendHandler implements AudioSendHandler { - private final AudioPlayer audioPlayer; - private AudioFrame lastFrame; + private final AudioPlayer audioPlayer; + private AudioFrame lastFrame; - /** - * @param audioPlayer Audio player to wrap. - */ - public AudioPlayerSendHandler(AudioPlayer audioPlayer) { - this.audioPlayer = audioPlayer; - } + /** + * @param audioPlayer Audio player to wrap. + */ + public AudioPlayerSendHandler(AudioPlayer audioPlayer) { + this.audioPlayer = audioPlayer; + } - @Override - public boolean canProvide() { - lastFrame = audioPlayer.provide(); - return lastFrame != null; - } + @Override + public boolean canProvide() { + lastFrame = audioPlayer.provide(); + return lastFrame != null; + } - @Override - public ByteBuffer provide20MsAudio() { - return ByteBuffer.wrap(lastFrame.getData()); - } + @Override + public ByteBuffer provide20MsAudio() { + return ByteBuffer.wrap(lastFrame.getData()); + } - @Override - public boolean isOpus() { - return true; - } + @Override + public boolean isOpus() { + return true; + } } diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java index 56aab6c..22c3a6a 100644 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -1,4 +1,5 @@ -package netneutrality.music;/* +package netneutrality.music; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -37,15 +38,15 @@ public class LoadResultHandler implements AudioLoadResultHandler { } scheduler.queue(audioTrack); - } @Override public void playlistLoaded(AudioPlaylist audioPlaylist) { + if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, identifier)).queue(); + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); scheduler.queue(track); } else { channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); @@ -62,6 +63,7 @@ public class LoadResultHandler implements AudioLoadResultHandler { @Override public void loadFailed(FriendlyException e) { + channel.sendMessage(e.getMessage()).queue(); LogHandler.log(e); } } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 9231760..8104d5c 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -3,7 +3,8 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; @@ -11,14 +12,17 @@ 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.track.AudioTrack; -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.ThreadManager; +import netneutrality.command.CommandContext; +import netneutrality.exceptions.CommandErrorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; @@ -70,8 +74,10 @@ public class MusicManager { leave(); } }, 120, 120, TimeUnit.SECONDS); - } else + } else { logger.error("Error connecting!"); + } + } public boolean isConnected() { @@ -100,18 +106,36 @@ public class MusicManager { } } - public synchronized void play(String url, TextChannel channel, Member user, boolean silent) { + public void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { + Member member = context.getGuildUser(); + TextChannel channel = context.getChannel(); + + if (member.getVoiceState() == null) { + return; + } + + if (!member.getVoiceState().inVoiceChannel()) { + throw new CommandErrorException("You are not in a voice channel", context, null); + } + + VoiceChannel vChannel = member.getVoiceState().getChannel(); + + if (needToBeConnected && !isConnectedTo(vChannel)) { + throw new CommandErrorException("Not in your voice channel", context, null); + } + + if (!isConnectedTo(vChannel)) { + connect(vChannel); + } String identifier = SourceFinder.getIdentifier(url); logger.debug(identifier); scheduler.setTextChannel(channel); if (identifier != null) { - playerManager.loadItem(identifier, new LoadResultHandler(identifier, channel, user, scheduler, silent)); - + playerManager.loadItem(identifier, new LoadResultHandler(identifier, channel, member, scheduler, silent)); } else { - channel.sendMessage("No source found to play the given url").queue(); - leave(); + throw new CommandErrorException("No source found to play the given url", context, null); } } diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index 2a09d40..7c45c6a 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -1,15 +1,15 @@ package netneutrality.music; -import net.dv8tion.jda.api.entities.TextChannel; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + enum SourceEnum { Youtube, Soundcloud, @@ -22,7 +22,7 @@ enum SourceEnum { public class SourceFinder { private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&\\?]{12,}))?", Pattern.CASE_INSENSITIVE); - private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); + private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); private static Matcher youtubeMatcher; private static Matcher soundcloudMatcher; private static Matcher BandcampMatcher; @@ -45,23 +45,12 @@ public class SourceFinder { } public static String getIdentifier(String url) { - String identifier = null; - - switch (getSource(url)) { - - case Youtube: - identifier = url; - break; - case Soundcloud: - identifier = url; - break; - case YTSearch: - identifier = "ytsearch:" + url; - break; - case Nothing: - identifier = null; - break; - } + String identifier = switch (getSource(url)) { + case Youtube, Soundcloud -> url; + case YTSearch -> "ytsearch:" + url; + case Nothing -> null; + default -> null; + }; return identifier; } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index ebc6031..c60b2e1 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -3,7 +3,8 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; @@ -28,12 +29,11 @@ public class TrackScheduler extends AudioEventAdapter { this.queue = new LinkedBlockingQueue<>(); } - public synchronized void queue(AudioTrack track) { + public void queue(AudioTrack track) { // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. boolean start = player.startTrack(track, true); - //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); if (!start) { queue.offer(track); @@ -43,8 +43,8 @@ public class TrackScheduler extends AudioEventAdapter { public void setTextChannel(TextChannel channel) { this.channel = channel; - if (this.topic == null) { - this.topic = channel.getTopic(); + if (topic == null) { + topic = channel.getTopic(); } } @@ -58,11 +58,11 @@ public class TrackScheduler extends AudioEventAdapter { } public void resetTopic() { - if (this.channel != null) { - //this.channel.getManager().setTopic(this.topic).queue(); + if (channel != null && (topic != null && !topic.equals(""))) { + //channel.getManager().setTopic(topic).queue(); } - this.topic = ""; + topic = ""; } /** @@ -73,11 +73,7 @@ public class TrackScheduler extends AudioEventAdapter { // giving null to startTrack, which is a valid argument and will simply stop the player. AudioTrack track = queue.poll(); if (track != null) { - //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); player.startTrack(track, false); - } else { - //channel.getManager().setTopic(topic).queue(); - } } @@ -95,10 +91,13 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { // A track started playing + //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { + resetTopic(); + if (endReason.mayStartNext) { nextTrack(); } @@ -113,11 +112,13 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { + resetTopic(); channel.sendMessage("Error while playing track: " + track.getInfo().title).queue(); } @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { + resetTopic(); nextTrack(); } } diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index 19b67d3..a859f9e 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -41,7 +41,7 @@ public class ChannelFunction { private synchronized static void deleteFromList(List messages, TextChannel channel) { try { channel.deleteMessages(messages).complete(); - logger.debug("Deleted " + messages.size() + " messages from channel ["+ channel.getName() + "] in guild [" + channel.getGuild().getName() + "]"); + logger.debug("Deleted {} messages from channel [{}] in guild [{}]", messages.size(), channel.getName(), channel.getGuild().getName()); } catch (IllegalArgumentException e) { messages.forEach(m -> { diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index a1159af..aa2684b 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -3,7 +3,8 @@ package netneutrality.utils; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import java.awt.*; @@ -16,6 +17,7 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; @@ -58,7 +60,7 @@ public class MessageFunction { return false; } - public synchronized static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager, Member user) { + public static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager, Member user) { AudioTrack current = manager.getCurrentlyPlaying(); EmbedBuilder message = new EmbedBuilder(); @@ -74,7 +76,7 @@ public class MessageFunction { return message.build(); } - public synchronized static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user, String identifier) { + public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user, String identifier) { EmbedBuilder message = new EmbedBuilder(); message.setAuthor("Link to track", identifier); message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); @@ -88,7 +90,7 @@ public class MessageFunction { return message.build(); } - public synchronized static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user, String identifier) { + public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user, String identifier) { EmbedBuilder message = new EmbedBuilder(); message.setAuthor("Link to playlist", identifier); message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier())); @@ -124,40 +126,60 @@ public class MessageFunction { return message.build(); } - public static MessageEmbed buildHelpMessage(HashMap commands, HashMap alias) { - EmbedBuilder message = new EmbedBuilder(); - message.setTitle("Commands for Net Neutrality"); - message.setColor(Color.green); + public static ArrayList buildHelpMessage(HashMap commands, HashMap alias, boolean admin) { SortedSet keys = new TreeSet<>(commands.keySet()); - for (String key : keys) { - AbstractCommand command = commands.get(key); + HashMap help = new HashMap<>(); + + for (String commandName : keys) { + AbstractCommand command = commands.get(commandName); + if (command.getType() == null) + continue; + String usage = "None"; String description = "No description yet"; - if (command.isEnabled()) { + if (command.isEnabled() && command.getType() != CommandType.UNLISTED) { + if (command.getType() == CommandType.ADMINISTRATION && !admin) + continue; + if (command.getUsage() != null) usage = command.getUsage(); if (command.getDescription() != null) description = command.getDescription(); + EmbedBuilder message; + if (help.containsKey(command.getType())) { + message = help.get(command.getType()); + } else { + help.put(command.getType(), message = new EmbedBuilder()); + } + + if (message.isEmpty()) { + message.setTitle(command.getType().getDescription() + " commands for NetNeutrality"); + message.setColor(Color.GREEN); + } + + message.addField(Settings.getInstance().get("BOT_PREFIX") + command.getCommand() + " - Arguments: " + usage, description, false); } - message.addField(Settings.getInstance().get("BOT_PREFIX") + command.getCommand() + " - Arguments: " + usage, description, false); } - return message.build(); + ArrayList messages = new ArrayList<>(); + help.values().forEach(embedBuilder -> messages.add(embedBuilder.build())); + + return messages; } - public static void checkBlacklist(String guildId, Message message, TextChannel channel, String msg) { + public static void checkBlacklist(Guild guild, Message message, TextChannel channel) { - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guildId, mBlacklists -> { + ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guild.getId(), mBlacklists -> { if (!mBlacklists.isEmpty()) { boolean found = false; for (MBlacklist aBlacklist : mBlacklists) { - if (msg.toLowerCase().contains(aBlacklist.getWord())) { + if (message.getContentRaw().toLowerCase().contains(aBlacklist.getWord())) { found = true; break; } diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java new file mode 100644 index 0000000..2a83e44 --- /dev/null +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -0,0 +1,34 @@ +package netneutrality.utils;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.VoiceChannel; +import netneutrality.command.CommandContext; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.music.MusicManager; + +public class MusicUtils { + + public static void checkIfConnected(MusicManager manager, CommandContext context) { + if (context.getGuildUser().getVoiceState() == null) { + throw new CommandExecutionException("Voice state is null", context, null); + } + + if (!context.getGuildUser().getVoiceState().inVoiceChannel()) { + throw new CommandErrorException("You are not in a voice channel", context, null); + } + + VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); + if (!manager.isConnected()) { + throw new CommandErrorException("Player is not in a voice channel", context, null); + } + + if (!manager.isConnectedTo(vChannel)) { + throw new CommandErrorException("Player is not in your voice channel", context, null); + } + } +} From dbf6fd549c906066d2566860409882b993a35412 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 25 Jan 2022 23:52:10 -0500 Subject: [PATCH 061/155] Fix parsing of arguments --- .../netneutrality/command/CommandContext.java | 16 ++++++++++------ .../java/netneutrality/music/MusicManager.java | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java index 6e120f1..ba03f25 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -11,8 +11,10 @@ import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import netneutrality.ThreadManager; import netneutrality.handler.LogHandler; +import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; +import java.util.Arrays; import java.util.concurrent.ExecutorService; public class CommandContext { @@ -48,9 +50,10 @@ public class CommandContext { } public String[] getArgumentsAsArray() { - String text = message.getContentRaw().trim(); - String cmd = text.split(" ", 2)[0]; - String[] args = text.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); + String msg = message.getContentDisplay().trim(); + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + String cmd = msg.split(" ", 2)[0]; + String[] args = msg.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); if (args.length == 1 && args[0].isEmpty()) args = new String[0]; @@ -59,10 +62,11 @@ public class CommandContext { } public String getMessageText() { - String text = message.getContentRaw().trim(); - String cmd = text.split(" ", 2)[0]; + String msg = message.getContentDisplay().trim(); + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + String cmd = msg.split(" ", 2)[0]; - return text.replaceFirst("(" + cmd + ")(\s)?", ""); + return msg.replaceFirst("(" + cmd + ")(\s)?", ""); } public Message getMessage() { diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 8104d5c..f33eaec 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -45,7 +45,7 @@ public class MusicManager { this.scheduler = new TrackScheduler(player); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); - player.setVolume(30); + player.setVolume(15); AudioSourceManagers.registerRemoteSources(playerManager); AudioSourceManagers.registerLocalSource(playerManager); From 048b645e61ff7c6ae8799381b43ecac80f74e736 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 8 Feb 2022 18:34:06 -0500 Subject: [PATCH 062/155] Add voteskip command and update music player --- pom.xml | 266 +++++++++--------- src/main/java/netneutrality/GuildManager.java | 57 +++- src/main/java/netneutrality/MusicBot.java | 25 +- .../java/netneutrality/ThreadManager.java | 28 +- .../command/AbstractMusicCommand.java | 12 +- .../netneutrality/command/CommandContext.java | 45 ++- .../netneutrality/command/CommandUsage.java | 49 ++++ .../command/basic/HelpCommand.java | 4 +- .../command/basic/PingCommand.java | 2 +- .../command/crypto/BitcoinPriceCommand.java | 2 +- .../command/crypto/CryptoPriceCommand.java | 2 +- .../command/crypto/EthereumPriceCommand.java | 2 +- .../command/crypto/LitecoinPriceCommand.java | 2 +- .../command/music/DeleteQueueCommand.java | 2 +- .../command/music/JoinCommand.java | 2 +- .../command/music/LeaveCommand.java | 2 +- .../command/music/PlayCommand.java | 6 +- .../command/music/SkipCommand.java | 12 +- .../command/music/StopCommand.java | 16 +- .../command/music/ViewQueueCommand.java | 8 +- .../command/music/VolumeCommand.java | 7 +- .../command/music/VoteSkipCommand.java | 11 +- .../java/netneutrality/db/DBController.java | 2 +- .../db/controllers/DBBlacklist.java | 17 +- .../db/entities/AbstractEntity.java | 4 +- .../netneutrality/db/models/MRowModel.java | 20 ++ .../netneutrality/db/models/MTableModel.java | 6 + .../netneutrality/handler/LogHandler.java | 2 +- .../handler/{ => message}/EditHandler.java | 17 +- .../{ => message}/MessageReceivedHandler.java | 4 +- .../http/server/ActionHandler.java | 37 ++- .../http/server/GuildHandler.java | 60 +++- .../netneutrality/http/server/WebApi.java | 4 +- .../music/LoadResultHandler.java | 18 +- .../netneutrality/music/MusicManager.java | 85 ++++-- .../netneutrality/music/TrackScheduler.java | 121 ++++++-- ...BaseThread.java => BaseThreadFactory.java} | 4 +- .../netneutrality/thread/ShutdownThread.java | 28 ++ .../netneutrality/utils/ChannelFunction.java | 2 +- .../netneutrality/utils/MessageFunction.java | 32 ++- .../netneutrality/utils/UnsafeShutdown.java | 62 ++++ 41 files changed, 779 insertions(+), 308 deletions(-) create mode 100644 src/main/java/netneutrality/command/CommandUsage.java rename src/main/java/netneutrality/handler/{ => message}/EditHandler.java (71%) rename src/main/java/netneutrality/handler/{ => message}/MessageReceivedHandler.java (94%) rename src/main/java/netneutrality/thread/{BaseThread.java => BaseThreadFactory.java} (87%) create mode 100644 src/main/java/netneutrality/thread/ShutdownThread.java create mode 100644 src/main/java/netneutrality/utils/UnsafeShutdown.java diff --git a/pom.xml b/pom.xml index 50dbbea..06f5297 100644 --- a/pom.xml +++ b/pom.xml @@ -1,151 +1,155 @@ + + - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - com.xtremcommunity.discord - netneutrality - 1.0.0 - netneutrality-discord-bot - Discord bot - jar + com.xtremcommunity.discord + netneutrality + 1.0.0 + netneutrality-discord-bot + Discord bot + jar - - 17 - UTF-8 - + + 17 + UTF-8 + 17 + 17 + - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 17 - UTF-8 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 17 + UTF-8 17 17 - - - - org.apache.maven.plugins - maven-jar-plugin - 3.2.0 - - - - true - lib/ - netneutrality.MusicBot - - - - + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + lib/ + netneutrality.MusicBot + + + + - - maven-assembly-plugin - 3.3.0 - - - - netneutrality.MusicBot - true - true - - - true - - - - jar-with-dependencies - - netneutrality - - - - make-assembly - package - - single - - - - - - + + maven-assembly-plugin + 3.3.0 + + + + netneutrality.MusicBot + true + true + + + true + + + + jar-with-dependencies + + netneutrality + + + + make-assembly + package + + single + + + + + + - - - central - https://repo.maven.apache.org/maven2 - + + + central + https://repo.maven.apache.org/maven2 + - - dv8tion - m2-dv8tion - https://m2.dv8tion.net/releases - + + dv8tion + m2-dv8tion + https://m2.dv8tion.net/releases + - + - - - net.dv8tion - JDA - 4.4.0_350 - + + + net.dv8tion + JDA + 4.4.0_350 + - - com.squareup.okhttp3 - okhttp - 4.9.3 - + + com.squareup.okhttp3 + okhttp + 4.9.3 + - - - org.json - json - 20210307 - + + + org.json + json + 20210307 + - - org.reflections - reflections - 0.10.2 - + + org.reflections + reflections + 0.10.2 + - - mysql - mysql-connector-java - 8.0.27 - - - org.apache.logging.log4j - log4j-api - 2.17.0 - - - org.apache.logging.log4j - log4j-core - 2.17.0 - - - org.apache.logging.log4j - log4j-slf4j-impl - 2.17.0 - + + mysql + mysql-connector-java + 8.0.27 + + + org.apache.logging.log4j + log4j-api + 2.17.0 + + + org.apache.logging.log4j + log4j-core + 2.17.0 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.17.0 + - - org.apache.commons - commons-lang3 - 3.12.0 - - - com.sedmelluq - lavaplayer - 1.3.78 - + + org.apache.commons + commons-lang3 + 3.12.0 + + + com.sedmelluq + lavaplayer + 1.3.78 + junit junit diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 53a29bd..e657422 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -10,8 +10,6 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OGuild; import netneutrality.handler.ratelimiter.IMessageRateLimiter; import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; @@ -24,17 +22,30 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { - public enum GuildSettings { - MUSIC_ROLE("muisc.role"), MUSIC_CHANNEL("music.channel"), BLACKLIST_CHANNELS("blacklist.exclude.channels"); + public enum GuildSetting { + MUSIC_ROLE("music.role", null), MUSIC_CHANNEL("music.channel", null), BLACKLIST_CHANNELS("blacklist.exclude.channels", null); private final String setting; + private final String defaultValue; - GuildSettings(String setting) { + GuildSetting(String setting, String defaultValue) { this.setting = setting; + this.defaultValue = defaultValue; + } + + public String getSetting() { + return setting; + } + + public String getDefaultValue() { + return defaultValue; } @Override public String toString() { + if (setting == null) + return defaultValue; + return setting; } } @@ -61,6 +72,36 @@ public class GuildManager { } } + public static GuildManager getManager(String guildId) { + return managers.getOrDefault(guildId, null); + } + + public static Map getManagers() { + return managers; + } + + public static boolean reloadSettingsForGuild(String guildId) { + if (managers.containsKey(guildId)) { + GuildManager manager = managers.get(guildId); + manager.reloadSettings(); + + return true; + } + + return false; + } + + public static boolean reloadSettingsForGuild(Guild guild) { + if (managers.containsKey(guild.getId())) { + GuildManager manager = GuildManager.getManager(guild.getId()); + manager.reloadSettings(); + + return true; + } + + return false; + } + public void checkAndLogMessage(Message message, Member member, TextChannel channel) { //((DBMessage) DBController.get("message")).log(guild, channel, member, message); } @@ -74,10 +115,14 @@ public class GuildManager { return guildEntity.getSettings().getSettingByKey(key); } - public String getSetting(GuildSettings key) { + public String getSetting(GuildSetting key) { return guildEntity.getSettings().getSettingByKey(key.toString()); } + public Map getSettings() { + return guildEntity.getSettings().getSettings(); + } + public void reloadSettings() { guildEntity.reloadSettings(); } diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 3f4a025..6ee210f 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -7,16 +7,15 @@ import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.command.CommandManager; import netneutrality.db.DBController; -import netneutrality.handler.EditHandler; -import netneutrality.handler.MessageReceivedHandler; +import netneutrality.handler.message.EditHandler; +import netneutrality.handler.message.MessageReceivedHandler; import netneutrality.handler.ServerJoinHandler; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; +import netneutrality.thread.BaseThreadFactory; +import netneutrality.thread.ShutdownThread; import netneutrality.utils.Settings; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,28 +32,20 @@ public class MusicBot { initJDA(); CommandManager.init(); + MusicManager.registerSources(); jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); new WebApi(); jda.getPresence().setActivity(Activity.watching("you")); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - if( LogManager.getContext() instanceof LoggerContext) { - logger.debug("Shutting down log4j2"); - Configurator.shutdown((LoggerContext)LogManager.getContext()); - } - - MusicBot.shutdown(); - })); + Runtime.getRuntime().addShutdownHook(new BaseThreadFactory("shutdown").newThread(new ShutdownThread())); } public static void initJDA() { try { - jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")) - .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) - .build(); + jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")).enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES).build(); jda.awaitReady(); } catch (LoginException | IllegalArgumentException | InterruptedException e) { logger.error(e.getMessage()); @@ -77,7 +68,7 @@ public class MusicBot { private static void disconnect() { if (jda != null) { - jda.shutdownNow(); + jda.shutdown(); } } diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index d16b4a4..03fbb15 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -1,6 +1,6 @@ package netneutrality; -import netneutrality.thread.BaseThread; +import netneutrality.thread.BaseThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +17,7 @@ public class ThreadManager { private final static Logger logger = LoggerFactory.getLogger(ThreadManager.class); public static ExecutorService getExecutor(String name) { - return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); + return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); } @@ -26,36 +26,18 @@ public class ThreadManager { switch (type) { case FIXED: - executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(5, new BaseThread(name))); + executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); break; case SCHEDULED: - executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(5, new BaseThread(name))); + executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); break; default: - executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); + executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); } return executor; } - public static ExecutorService getExecutor(String name, ExecutorType type, Integer poolSize) { - ExecutorService executor; - - switch (type) { - case FIXED: - executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(poolSize, new BaseThread(name))); - break; - case SCHEDULED: - executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(poolSize, new BaseThread(name))); - break; - default: - executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); - } - - return executor; - } - - public static Future dispatch(ExecutorService executor, Runnable task) { return executor.submit(task); } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 91a2136..8ea1990 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -1,4 +1,5 @@ -package netneutrality.command;/* +package netneutrality.command; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -10,6 +11,8 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import netneutrality.GuildManager; +import java.util.List; + public abstract class AbstractMusicCommand extends AbstractCommand { @Override @@ -24,14 +27,15 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSettings.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + boolean can = true; //System.out.println(roleDb); if (roleDb != null && !roleDb.isEmpty()) { Role neededRole = guild.getRoleById(roleDb); - return member.getRoles().contains(neededRole); + can = member.getRoles().contains(neededRole); } - return true; + return can; } } diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java index ba03f25..0655d4e 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -15,11 +15,12 @@ import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; import java.util.Arrays; +import java.util.Collection; import java.util.concurrent.ExecutorService; public class CommandContext { - private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED, 10); + private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED); private AbstractCommand command; private final Message message; @@ -49,11 +50,15 @@ public class CommandContext { return new CommandContext(message, member, user, guild, channel, jda); } + public String getArg(int index) { + return getArgumentsAsArray()[index]; + } + public String[] getArgumentsAsArray() { String msg = message.getContentDisplay().trim(); msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); String cmd = msg.split(" ", 2)[0]; - String[] args = msg.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); + String[] args = msg.replaceFirst("(" + cmd + ")(\\s+)?", "").split("\s"); if (args.length == 1 && args[0].isEmpty()) args = new String[0]; @@ -97,6 +102,42 @@ public class CommandContext { return command; } + public void reply(String msg) { + if (channel != null) { + channel.sendMessage(msg).queue(); + } + } + + public void reply(Message msg) { + if (channel != null) { + channel.sendMessage(msg).queue(); + } + } + + public void reply(MessageEmbed embed, MessageEmbed... embeds) { + if (channel != null) { + channel.sendMessageEmbeds(embed, embeds).queue(); + } + } + + public void reply(Collection embeds) { + if (channel != null) { + channel.sendMessageEmbeds(embeds).queue(); + } + } + + public void replyPrivate(String msg) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + } + + public void replyPrivate(Message msg) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + } + + public void replyPrivate(Collection embeds) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); + } + public void dispatch(AbstractCommand command) { this.command = command; //TODO: Add usage check diff --git a/src/main/java/netneutrality/command/CommandUsage.java b/src/main/java/netneutrality/command/CommandUsage.java new file mode 100644 index 0000000..956b946 --- /dev/null +++ b/src/main/java/netneutrality/command/CommandUsage.java @@ -0,0 +1,49 @@ +package netneutrality.command;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class CommandUsage { + + public static class Argument { + public enum Type { + OPTIONAL, REQUIRED + } + + private final Type type; + private final String description; + + public Argument(Type t, String desc) { + this.type = t; + this.description = desc; + } + + public String getDescription() { + return description; + } + + public Type getType() { + return type; + } + } + + private final Set args = new HashSet<>(); + + public CommandUsage(Argument... arguments) { + Collections.addAll(args, arguments); + } + + public static CommandUsage create(Argument... arguments) { + return new CommandUsage(arguments); + } + + public Set getArguments() { + return args; + } +} diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index cf53ca5..d5e0395 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -58,7 +58,7 @@ public class HelpCommand extends AbstractCommand { public void execute(CommandContext context) { List help = MessageFunction.buildHelpMessage(CommandManager.commands, CommandManager.commandsAlias, UserFunction.isAdmin(context.getGuildUser())); - context.getChannel().sendMessage(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()).queue(); - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessageEmbeds(help).queue()); + context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); + context.replyPrivate(help); } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index c6c6633..de9a442 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -51,7 +51,7 @@ public class PingCommand extends AbstractCommand { @Override public void execute(CommandContext context) { if (context.getArgumentsAsArray().length == 0) - context.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); + context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); } } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 375167d..68a9414 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -88,7 +88,7 @@ public class BitcoinPriceCommand extends AbstractCommand { throw new CommandExecutionException("Error during web request", context, e); } - t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index d63703b..3855472 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -44,7 +44,7 @@ public class CryptoPriceCommand extends AbstractCommand { @Override public String getUsage() { - return " "; + return " "; } @Override diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 29b8d64..2a17447 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -88,7 +88,7 @@ public class EthereumPriceCommand extends AbstractCommand { throw new CommandExecutionException("Error during web request", context, e); } - t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index cc4439c..eb8e3b7 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -88,7 +88,7 @@ public class LitecoinPriceCommand extends AbstractCommand { throw new CommandExecutionException("Error during web request", context, e); } - t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 14bdd20..44fc51f 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -40,7 +40,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Deletes the music queue"; } @Override diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 3a2290a..1242f7e 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -37,7 +37,7 @@ public class JoinCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Make the bot join the current voice channel (if no music is playing, bot will disconnect automatically)"; } @Override diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 0c18e89..71b578b 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -40,7 +40,7 @@ public class LeaveCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Make the bot leave the voice channel"; } @Override diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 3df9ac4..52c4b81 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -35,19 +35,19 @@ public class PlayCommand extends AbstractMusicCommand { @Override public String getDescription() { - return "Get the party going"; + return "Get the party going!"; } @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); + context.getMessage().delete().queue(); if (context.getArgumentsAsArray().length > 0) { - context.getMessage().delete().queue(); player.play(context.getMessageText(), context, false, false); } else { - context.getChannel().sendMessage("No url provided").queue(); + context.reply("No url provided"); } } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 42818dc..257d58b 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -35,12 +35,12 @@ public class SkipCommand extends AbstractMusicCommand { @Override public String getUsage() { - return null; + return ""; } @Override public String getDescription() { - return null; + return "Used to skip to the next track in the queue (requires admin privileges)"; } @Override @@ -48,6 +48,12 @@ public class SkipCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - player.skip(); + if (context.getArgumentsAsArray().length > 0) { + int skips = Integer.parseInt(context.getArg(0)); + player.skip(skips); + } else { + player.skip(1); + } + } } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index e4cad4b..b8cc556 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -11,12 +11,9 @@ import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; +import netneutrality.utils.UserFunction; public class StopCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { @@ -40,7 +37,7 @@ public class StopCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Stop the music player, deleting the queue in the process"; } @Override @@ -48,6 +45,13 @@ public class StopCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - player.leave(); + if (UserFunction.isAdmin(context.getGuildUser())) { + player.leave(); + return; + } + + if (context.getGuildUser().getId().equals(player.getRequesterOfCurrentTrack().getId())) { + player.leave(); + } } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 580112e..0eaa4fb 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -32,7 +32,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { @Override public String[] getAlias() { - return new String[]{"viewq"}; + return new String[]{"viewq", "queue"}; } @Override @@ -42,7 +42,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Get the current queue for the music player"; } @Override @@ -53,9 +53,9 @@ public class ViewQueueCommand extends AbstractMusicCommand { int queueSize = player.getScheduler().getQueue().size(); if (queueSize > 0) { - context.getChannel().sendMessageEmbeds(MessageFunction.buildViewQueueMessage(player, member)).queue(); + context.reply(MessageFunction.buildViewQueueMessage(player, member)); } else { - context.getChannel().sendMessage("Queue is empty!").queue(); + context.reply("Queue is empty!"); } } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 576cac6..35a7fe2 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -31,17 +32,17 @@ public class VolumeCommand extends AbstractMusicCommand { @Override public String[] getAlias() { - return new String[0]; + return new String[] { "vol" }; } @Override public String getUsage() { - return null; + return ""; } @Override public String getDescription() { - return null; + return "Sets the volume for the music player"; } @Override diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index 54df3dc..d8ace4e 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -8,17 +8,19 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class VoteSkipCommand extends AbstractMusicCommand { @Override public boolean isEnabled() { - return false; + return true; } @Override public String getCommand() { - return null; + return "voteskip"; } @Override @@ -33,11 +35,14 @@ public class VoteSkipCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Cast a vote to skip the currently playing track"; } @Override public void execute(CommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(manager, context); + manager.voteSkip(context); } } diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 19d0041..5168658 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -71,7 +71,7 @@ public class DBController { if (controllers.isEmpty()) loadControllers(); - ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { + ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED)).scheduleWithFixedDelay(() -> { DBController.get().query("SELECT 1;"); }, 0, 120, TimeUnit.SECONDS); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index c78d662..04a2d0e 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -26,6 +26,8 @@ public class DBBlacklist extends AbstractController { } + + public void delete(String word, String serverId, Consumer success) { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { @@ -119,18 +121,13 @@ public class DBBlacklist extends AbstractController { return output; } - @Deprecated private boolean isAlreadyBlacklisted(String word, String serverId) { - AtomicBoolean result = new AtomicBoolean(); + MTableModel table = database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).blocking(); + if (!table.isEmpty()) { + return ((int) table.getRowModel(0).getItem(0)) != 0; + } - database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(table -> { - if (!table.isEmpty()) { - result.set((int) table.getRowModel(0).getItem(0) != 0); - } - }); - - - return result.get(); + return false; } private void isAlreadyBlacklisted(String word, String serverId, Consumer result) { diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java index 3a4d96a..0831784 100644 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -30,13 +30,13 @@ public abstract class AbstractEntity implements EntityInterface { for (String pk : getPrimaryKeys()) { whereClause.append(pk + " = ?"); + //TODO: Fix last and if (getPrimaryKeys().length > 1) whereClause.append(" AND "); } - String sql = "SELECT * FROM " + getTableName() + " WHERE " + whereClause; - MusicBot.logger.debug(sql + " - pk: " + primaryKey); + // MusicBot.logger.debug(sql + " - pk: " + primaryKey); if (this.primaryKeys.length > 0) this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey, this.primaryKeys).blocking(); diff --git a/src/main/java/netneutrality/db/models/MRowModel.java b/src/main/java/netneutrality/db/models/MRowModel.java index a277bee..025d055 100644 --- a/src/main/java/netneutrality/db/models/MRowModel.java +++ b/src/main/java/netneutrality/db/models/MRowModel.java @@ -32,14 +32,34 @@ public class MRowModel { return rowIndex; } + /** + * Add an item to the row. No checks are made to match the table itself + * @param obj Object to add to the row + */ public void addColumnToRow(Object obj) { row.add(obj); } + /** + * Get a list of all objects in the row. + * @return List of objects + */ public List getRow() { return row; } + /** + *
+     * Get an item at the specified index.
+     *
+     * Example:
+     * SQL:   SELECT first,    second,    third
+     * Index:        0         1          2
+     * 
+ * + * @param index Index + * @return The object + */ public Object getItem(int index) { try { return row.get(index); diff --git a/src/main/java/netneutrality/db/models/MTableModel.java b/src/main/java/netneutrality/db/models/MTableModel.java index e69d5a4..4766908 100644 --- a/src/main/java/netneutrality/db/models/MTableModel.java +++ b/src/main/java/netneutrality/db/models/MTableModel.java @@ -67,6 +67,12 @@ public class MTableModel { return null; } + /** + * Represent a row in a table + * + * @param rowIndex The index of the row + * @return A row model + */ public MRowModel getRowModel(int rowIndex) { if (getNbRows() != 0) return rows.getRowModel(rowIndex); diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index 99bc553..15585e9 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -45,6 +45,6 @@ public class LogHandler { private static void sendMessageToChannel(CommandErrorException error) { CommandContext context = error.getCommandContext(); - context.getChannel().sendMessage(error.getMessage()).queue(); + context.reply(error.getMessage()); } } diff --git a/src/main/java/netneutrality/handler/EditHandler.java b/src/main/java/netneutrality/handler/message/EditHandler.java similarity index 71% rename from src/main/java/netneutrality/handler/EditHandler.java rename to src/main/java/netneutrality/handler/message/EditHandler.java index ad59f9a..ff3f80d 100644 --- a/src/main/java/netneutrality/handler/EditHandler.java +++ b/src/main/java/netneutrality/handler/message/EditHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler; +package netneutrality.handler.message; /* * Copyright (c) anthorob @@ -25,10 +25,12 @@ public class EditHandler extends ListenerAdapter { if (event.getAuthor().isBot()) return; - MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); + MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id, guild_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); Object logChannel = table.getRowModel(0).getItem(0); - if (logChannel != null) { + Object guild = table.getRowModel(0).getItem(1); + + if (logChannel != null && guild != null) { String originalMessage = ((DBMessage) DBController.get("message")).getMessageString(event.getMessage().getId()); ((DBMessage) DBController.get("message")).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); @@ -38,18 +40,19 @@ public class EditHandler extends ListenerAdapter { try { editEmbed.addField("Original message", (originalMessage == null ? "Not available" : originalMessage), false); } catch (IllegalArgumentException ex) { - editEmbed.addField("Original message :", "Message too long. Check db for full message", false); + editEmbed.addField("Original message:", "Message too long.", false); } try { - editEmbed.addField("Edited to :", event.getMessage().getContentDisplay(), false); + editEmbed.addField("Edited to:", event.getMessage().getContentDisplay(), false); } catch (IllegalArgumentException ex) { - editEmbed.addField("Edited to :", "Message too long. Check db for full message", false); + editEmbed.addField("Edited to:", "Message too long.", false); } editEmbed.setFooter("ID : " + event.getMessageId(), null); editEmbed.setTimestamp(event.getMessage().getTimeCreated()); - event.getJDA().getTextChannelById(logChannel.toString()).sendMessageEmbeds(editEmbed.build()).queue(); + + event.getJDA().getGuildById((String) guild).getTextChannelById((String) logChannel).sendMessageEmbeds(editEmbed.build()).queue(); } diff --git a/src/main/java/netneutrality/handler/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/message/MessageReceivedHandler.java similarity index 94% rename from src/main/java/netneutrality/handler/MessageReceivedHandler.java rename to src/main/java/netneutrality/handler/message/MessageReceivedHandler.java index 5ac58d1..f4a99a1 100644 --- a/src/main/java/netneutrality/handler/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/message/MessageReceivedHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler; +package netneutrality.handler.message; /* * Copyright (c) anthorob * @@ -7,6 +7,7 @@ package netneutrality.handler; */ import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.GuildManager; @@ -51,5 +52,4 @@ public class MessageReceivedHandler extends ListenerAdapter { GuildManager.getManager(guild).checkBlacklist(message, member, channel); } } - } diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index fc77d85..8a2a5b5 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -6,13 +6,13 @@ package netneutrality.http.server;/* */ import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; +import netneutrality.GuildManager; import netneutrality.MusicBot; import netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; +import org.json.JSONObject; import java.io.IOException; -import java.io.OutputStream; import java.util.Map; import java.util.TreeMap; @@ -25,6 +25,8 @@ public class ActionHandler extends AbstractHandler { if (path.equals("/actions/shutdown")) { LogManager.getLogger(MusicBot.class).info("Request to shutdown received"); sendStringResponse(exchange, "Shutting down.."); + MusicBot.shutdown(); + System.exit(0); return; } @@ -38,6 +40,37 @@ public class ActionHandler extends AbstractHandler { return; } + if (path.startsWith("/actions/settings/current/")) { + JSONObject json = new JSONObject(); + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + + GuildManager manager = GuildManager.getManager(MusicBot.getJDA().getGuildById(guild)); + if (manager != null) { + Map settings = manager.getSettings(); + JSONObject setting = new JSONObject(settings); + + json.put("status", "ok"); + json.put("settings", setting); + } else { + json.put("status", "error"); + } + + sendJsonResponse(exchange, json.toString()); + return; + } + + if (path.startsWith("/actions/settings/reload/")) { + TreeMap json = new TreeMap<>(); + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + + json.put("status", String.valueOf(GuildManager.reloadSettingsForGuild(MusicBot.getJDA().getGuildById(guild)))); + sendJsonResponse(exchange, WebModule.createJson(json)); + + return; + } + sendStringResponse(exchange, path); } diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/netneutrality/http/server/GuildHandler.java index 525684b..616d4f4 100644 --- a/src/main/java/netneutrality/http/server/GuildHandler.java +++ b/src/main/java/netneutrality/http/server/GuildHandler.java @@ -14,6 +14,8 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import netneutrality.MusicBot; import netneutrality.http.WebModule; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; @@ -28,15 +30,67 @@ public class GuildHandler extends AbstractHandler { if (path.equals("/guilds/owner")) { - TreeMap owners = new TreeMap<>(); + JSONArray array = new JSONArray(); JDA jda = MusicBot.getJDA(); jda.getGuilds().forEach(guild -> { - owners.put(guild.getId(), guild.getOwnerId()); + JSONObject obj = new JSONObject(); + obj.put("guild_id", guild.getId()); + obj.put("owner_id", guild.getOwnerId()); + array.put(obj); }); - sendJsonResponse(exchange, WebModule.createJsonArray(owners)); + sendJsonResponse(exchange, array.toString()); + return; + + } + + if (path.startsWith("/guilds/channels/")) { + + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + JSONArray array = new JSONArray(); + + JDA jda = MusicBot.getJDA(); + + if (jda.getGuildById(guild) == null) { + sendStringResponse(exchange, path); + return; + } + + jda.getGuildById(guild).getTextChannels().forEach(channel -> { + JSONObject obj = new JSONObject(); + obj.put("channel_id", channel.getId()); + obj.put("channel_name", channel.getName()); + array.put(obj); + }); + + sendJsonResponse(exchange, array.toString()); + return; + + } + + if (path.startsWith("/guilds/roles/")) { + + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + JSONArray array = new JSONArray(); + JDA jda = MusicBot.getJDA(); + + if (jda.getGuildById(guild) == null) { + sendStringResponse(exchange, path); + return; + } + + jda.getGuildById(guild).getRoles().forEach(role -> { + JSONObject obj = new JSONObject(); + obj.put("channel_id", role.getId()); + obj.put("channel_name", role.getName()); + array.put(obj); + }); + + sendJsonResponse(exchange, array.toString()); return; } diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 13da7b1..9d4c268 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -8,7 +8,7 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpServer; -import netneutrality.thread.BaseThread; +import netneutrality.thread.BaseThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +21,7 @@ import java.util.concurrent.Executors; public class WebApi { private final static Logger logger = LoggerFactory.getLogger(WebApi.class); - private final ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThread("web-api")); + private final ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThreadFactory("web-api")); private final int port = 9000; private HttpServer server; diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java index 22c3a6a..de6456d 100644 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -24,11 +24,16 @@ public class LoadResultHandler implements AudioLoadResultHandler { private final boolean silent; public LoadResultHandler(String identifier, TextChannel channel, Member user, TrackScheduler scheduler, boolean silent) { + if (user == null) + silent = true; + this.identifier = identifier; this.channel = channel; this.user = user; this.scheduler = scheduler; this.silent = silent; + + } @Override @@ -37,7 +42,7 @@ public class LoadResultHandler implements AudioLoadResultHandler { channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, user, identifier)).queue(); } - scheduler.queue(audioTrack); + scheduler.queue(audioTrack, user); } @Override @@ -46,12 +51,15 @@ public class LoadResultHandler implements AudioLoadResultHandler { if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); - scheduler.queue(track); + if (!silent) + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); + + scheduler.queue(track, user); } else { - channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); + if (!silent) + channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); for (AudioTrack track : audioPlaylist.getTracks()) { - scheduler.queue(track); + scheduler.queue(track, user); } } } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index f33eaec..77424b8 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -23,8 +23,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.concurrent.BlockingQueue; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -32,8 +33,9 @@ import java.util.concurrent.TimeUnit; public class MusicManager { private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); - private final Guild guild; private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + + private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; private final static Map managers = new ConcurrentHashMap<>(); @@ -47,9 +49,6 @@ public class MusicManager { player.addListener(scheduler); player.setVolume(15); - AudioSourceManagers.registerRemoteSources(playerManager); - AudioSourceManagers.registerLocalSource(playerManager); - managers.put(guild.getId(), this); } @@ -61,6 +60,10 @@ public class MusicManager { } } + public static void registerSources() { + AudioSourceManagers.registerRemoteSources(playerManager); + } + public boolean isConnectedTo(VoiceChannel vChannel) { return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); } @@ -69,7 +72,7 @@ public class MusicManager { if (vChannel != null && !isConnectedTo(vChannel)) { guild.getAudioManager().openAudioConnection(vChannel); - ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { + ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED)).scheduleWithFixedDelay(() -> { if ((getCurrentlyPlaying() == null && scheduler.getQueue().isEmpty()) || vChannel.getMembers().size() == 0) { leave(); } @@ -84,18 +87,23 @@ public class MusicManager { return guild != null && guild.getAudioManager().getConnectedChannel() != null; } - public synchronized AudioTrack getCurrentlyPlaying() { + public AudioTrack getCurrentlyPlaying() { return player.getPlayingTrack(); } - public synchronized void leave() { + public Member getRequesterOfCurrentTrack() { + TrackScheduler.TrackInfo info = scheduler.getQueue().peek(); + return info.getRequester(); + } + + public void leave() { if (isConnected()) { player.stopTrack(); guild.getAudioManager().closeAudioConnection(); } scheduler.resetTopic(); - + System.out.println(scheduler.getQueue().size()); } public static void disconnectPlayers() { @@ -106,6 +114,12 @@ public class MusicManager { } } + public boolean restoreQueue(List track) { + + + return false; + } + public void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); TextChannel channel = context.getChannel(); @@ -139,15 +153,49 @@ public class MusicManager { } } - public synchronized void skip() { + public void skip(int nbTrack) { if (!scheduler.getQueue().isEmpty()) { - scheduler.nextTrack(); + if (nbTrack >= scheduler.getQueue().size()) { + nbTrack = 1; + } + + scheduler.skipAndPlay(nbTrack); } else { leave(); } } - public synchronized void setVolume(int volume) { + public void voteSkip(CommandContext context) { + Queue queue = scheduler.getQueue(); + VoiceChannel voiceChannel = guild.getAudioManager().getConnectedChannel(); + + if (getCurrentlyPlaying() == null) { + return; + } + + // Minus the bot itself + int connected = voiceChannel.getMembers().size() - 1; + if (connected > 2) { + TrackScheduler.TrackInfo info = queue.peek(); + + double needed = connected / 2.1; + + if (info != null) { + info.toggleSkip(context.getGuildUser()); + + if (info.getSkips().size() > needed) { + skip(1); + } else { + context.reply(String.format("Current skips: %d/%f", info.getSkips().size(), Math.ceil(needed))); + } + } + + } else { + skip(1); + } + } + + public void setVolume(int volume) { player.setVolume(volume); } @@ -155,14 +203,11 @@ public class MusicManager { return scheduler; } - public ArrayList getAllQueuedTrack() { - ArrayList queuedTracks = new ArrayList<>(); - BlockingQueue queue = scheduler.getQueue(); + public ArrayList getAllQueuedTrack() { + ArrayList tracks = new ArrayList<>(); + Queue queue = scheduler.getQueue(); - queue.forEach((a) -> { - queuedTracks.add(a.getInfo().title); - }); - - return queuedTracks; + queue.forEach(trackInfo -> tracks.add(trackInfo.getTrack())); + return tracks; } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index c60b2e1..ce17c4b 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -12,68 +12,131 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; +import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; -import java.util.concurrent.BlockingQueue; +import java.util.*; import java.util.concurrent.LinkedBlockingQueue; public class TrackScheduler extends AudioEventAdapter { + class TrackInfo { + + private final AudioTrack track; + private final Member member; + private final Set skips; + + public TrackInfo(AudioTrack track, Member member) { + this.track = track; + this.member = member; + this.skips = new HashSet<>(); + } + + public AudioTrack getTrack() { + return track; + } + + public Set getSkips() { + return skips; + } + + public void toggleSkip(Member member) { + if (!hasSkip(member)) + skips.add(member.getId()); + else + skips.remove(member.getId()); + } + + public boolean hasSkip(Member member) { + return skips.contains(member.getId()); + } + + public Member getRequester() { + return member; + } + } + + private final Object topicLock = new Object(); private final AudioPlayer player; + private final Queue queue; private TextChannel channel; - private final BlockingQueue queue; - public String topic; + private String originalTopic; public TrackScheduler(AudioPlayer player) { this.player = player; this.queue = new LinkedBlockingQueue<>(); } - public void queue(AudioTrack track) { + public void queue(AudioTrack track, Member member) { // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. - boolean start = player.startTrack(track, true); + queue.offer(new TrackInfo(track, member)); - if (!start) { - queue.offer(track); + if (player.getPlayingTrack() == null) { + player.startTrack(track, true); } } - public void setTextChannel(TextChannel channel) { - this.channel = channel; - - if (topic == null) { - topic = channel.getTopic(); + public String getOriginalTopic() { + synchronized (topicLock) { + return originalTopic; } - } public TextChannel getTextChannel() { return channel; } - public BlockingQueue getQueue() { + public void setTextChannel(TextChannel channel) { + this.channel = channel; + + synchronized (topicLock) { + if (originalTopic == null) { + originalTopic = channel.getTopic(); + } + } + + } + + public void resetTextChannel() { + this.channel = null; + } + + public Queue getQueue() { return queue; } public void resetTopic() { - if (channel != null && (topic != null && !topic.equals(""))) { - //channel.getManager().setTopic(topic).queue(); + synchronized (topicLock) { + if (channel != null && (originalTopic != null && !originalTopic.equals(""))) { + //channel.getManager().setTopic(topic).queue(); + } + + originalTopic = null; } - topic = ""; } - /** - * Start the next track, stopping the current one if it is playing. - */ - public void nextTrack() { - // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are - // giving null to startTrack, which is a valid argument and will simply stop the player. - AudioTrack track = queue.poll(); - if (track != null) { - player.startTrack(track, false); + public void nextTrack(AudioPlayer player) { + TrackInfo last = queue.poll(); + + if (queue.peek() != null) { + player.startTrack(queue.peek().getTrack(), false); + } + } + + public void skipAndPlay(int nb) { + if (nb == 0) + return; + + for (int i = 0; i < nb; i++) { + TrackInfo last = queue.poll(); + } + + TrackInfo current = queue.peek(); + if (current != null) { + player.startTrack(current.getTrack(), false); } } @@ -99,7 +162,9 @@ public class TrackScheduler extends AudioEventAdapter { resetTopic(); if (endReason.mayStartNext) { - nextTrack(); + nextTrack(player); + } else { + queue.poll(); } // endReason == FINISHED: A track finished or died by an exception (mayStartNext = true). @@ -119,6 +184,6 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { resetTopic(); - nextTrack(); + nextTrack(player); } } diff --git a/src/main/java/netneutrality/thread/BaseThread.java b/src/main/java/netneutrality/thread/BaseThreadFactory.java similarity index 87% rename from src/main/java/netneutrality/thread/BaseThread.java rename to src/main/java/netneutrality/thread/BaseThreadFactory.java index 0c00b7f..75a6f5a 100644 --- a/src/main/java/netneutrality/thread/BaseThread.java +++ b/src/main/java/netneutrality/thread/BaseThreadFactory.java @@ -11,12 +11,12 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; -public class BaseThread implements ThreadFactory { +public class BaseThreadFactory implements ThreadFactory { private final AtomicLong threadId = new AtomicLong(1); private final String name; - public BaseThread(String name) { + public BaseThreadFactory(String name) { this.name = name; } diff --git a/src/main/java/netneutrality/thread/ShutdownThread.java b/src/main/java/netneutrality/thread/ShutdownThread.java new file mode 100644 index 0000000..34b92ba --- /dev/null +++ b/src/main/java/netneutrality/thread/ShutdownThread.java @@ -0,0 +1,28 @@ +package netneutrality.thread;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.MusicBot; +import netneutrality.utils.UnsafeShutdown; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configurator; + +public class ShutdownThread implements Runnable { + + @Override + public void run() { + if (LogManager.getContext() instanceof LoggerContext) { + System.out.println("Shutting down log4j2"); + Configurator.shutdown((LoggerContext) LogManager.getContext()); + } + + MusicBot.shutdown(); + if (!UnsafeShutdown.SAFE) { + //UnsafeShutdown.saveState(); + } + } +} diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index a859f9e..4cb37b1 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -17,7 +17,7 @@ public class ChannelFunction { if (toDelete >= 2500) return; - ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED, 5).submit(() -> { + ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { int toDeleteFinal = toDelete + 1; int iteration = toDeleteFinal / 100; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index aa2684b..d198d13 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -69,6 +69,7 @@ public class MessageFunction { message.setTitle("Currently playing:"); message.setColor(Color.BLUE); message.addField("Track title: ", current.getInfo().title, false); + message.addField("Uploaded by: ", current.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); @@ -83,6 +84,7 @@ public class MessageFunction { message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); message.addField("Track title: ", track.getInfo().title, false); + message.addField("Uploaded by: ", track.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); @@ -105,17 +107,20 @@ public class MessageFunction { } public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user) { - ArrayList tracks = manager.getAllQueuedTrack(); + ArrayList tracks = manager.getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); EmbedBuilder message = new EmbedBuilder(); message.setTitle("Current queue (showing max 10 items):"); message.setColor(Color.BLUE); - message.addField("Track #1 (Currently playing)", current.getInfo().title, false); - int index = 1; - for (String track: tracks) { - message.addField("Track #" + ++index, track, false); + int index = 0; + for (AudioTrack track: tracks) { + if (track.getInfo().title.equals(current.getInfo().title)) { + message.addField("Track #" + ++index + " (Currently playing)", track.getInfo().title, false); + } else { + message.addField("Track #" + ++index, track.getInfo().title, false); + } if (index == 10) break; } @@ -136,8 +141,9 @@ public class MessageFunction { if (command.getType() == null) continue; - String usage = "None"; + String usage = "(no arguments required)"; String description = "No description yet"; + StringBuilder availAlias = new StringBuilder(); if (command.isEnabled() && command.getType() != CommandType.UNLISTED) { if (command.getType() == CommandType.ADMINISTRATION && !admin) @@ -149,6 +155,18 @@ public class MessageFunction { if (command.getDescription() != null) description = command.getDescription(); + if (command.getAlias() != null && command.getAlias().length > 0) { + availAlias.append("("); + for (String str : command.getAlias()) { + availAlias.append(str).append(","); + } + + if (!availAlias.isEmpty()) { + availAlias.deleteCharAt(availAlias.lastIndexOf(",")); + availAlias.append(")"); + } + } + EmbedBuilder message; if (help.containsKey(command.getType())) { message = help.get(command.getType()); @@ -161,7 +179,7 @@ public class MessageFunction { message.setColor(Color.GREEN); } - message.addField(Settings.getInstance().get("BOT_PREFIX") + command.getCommand() + " - Arguments: " + usage, description, false); + message.addField(String.format("%s%s %s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommand(), availAlias, usage), description, false); } } diff --git a/src/main/java/netneutrality/utils/UnsafeShutdown.java b/src/main/java/netneutrality/utils/UnsafeShutdown.java new file mode 100644 index 0000000..1b2d719 --- /dev/null +++ b/src/main/java/netneutrality/utils/UnsafeShutdown.java @@ -0,0 +1,62 @@ +package netneutrality.utils;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import netneutrality.GuildManager; +import netneutrality.music.MusicManager; +import netneutrality.music.TrackScheduler; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Map; + +public class UnsafeShutdown { + public static boolean SAFE = false; + + //TODO: finish + private static void saveGuildsState() { + Map managers = GuildManager.getManagers(); + + for (GuildManager manager : managers.values()) { + File state = new File("state.json"); + + try { + if (!state.exists()) { + state.createNewFile(); + } + + FileWriter writer = new FileWriter(state); + JSONArray array = new JSONArray(); + + + + MusicManager musicManager = MusicManager.get(manager.getGuild()); + TrackScheduler trackScheduler = musicManager.getScheduler(); + + JSONObject music = new JSONObject(); + + music.put("current_channel", ""); + music.put("current_topic", ""); + music.put("current_topic", ""); + } catch (IOException e) { + e.printStackTrace(); + } + + + + + } + } + + public static void saveState() { + saveGuildsState(); + } +} From d849b80b7b469b52cd3e54af5714dbe1acb45682 Mon Sep 17 00:00:00 2001 From: anthorob Date: Thu, 17 Feb 2022 20:09:41 -0500 Subject: [PATCH 063/155] Use a fork of lavaplayer to play age-restricted content on Youtube --- bot.config.example | 4 +- pom.xml | 20 +++- sql/add_debug_field_to_guilds_table.sql | 1 + src/main/java/netneutrality/GuildManager.java | 73 ++++++++++----- src/main/java/netneutrality/MusicBot.java | 15 ++- .../java/netneutrality/ThreadManager.java | 19 +--- .../command/AbstractCommand.java | 2 +- .../netneutrality/command/CommandContext.java | 28 +++--- .../netneutrality/command/CommandManager.java | 4 +- .../command/basic/HelpCommand.java | 2 +- .../command/basic/PingCommand.java | 2 +- .../command/bot/ConfigureCommand.java | 2 +- .../command/crypto/BitcoinPriceCommand.java | 2 +- .../command/crypto/CryptoPriceCommand.java | 2 +- .../command/crypto/EthereumPriceCommand.java | 2 +- .../command/crypto/LitecoinPriceCommand.java | 2 +- .../command/message/BlacklistCommand.java | 58 ++++++------ .../command/message/PruneCommand.java | 2 +- .../command/music/BitconnectCommand.java | 2 +- .../music/CurrentlyPlayingCommand.java | 2 +- .../command/music/DeleteQueueCommand.java | 2 +- .../command/music/JoinCommand.java | 17 +++- .../command/music/LeaveCommand.java | 2 +- .../command/music/PlayCommand.java | 2 +- .../command/music/SkipCommand.java | 2 +- .../command/music/StopCommand.java | 2 +- .../command/music/ViewQueueCommand.java | 2 +- .../command/music/VolumeCommand.java | 2 +- .../command/music/VoteSkipCommand.java | 2 +- .../command/specific/DatabaseCommand.java | 2 +- .../command/specific/EvalMethod.java | 2 +- .../command/specific/LoggingCommand.java | 2 +- .../command/specific/SellyCommand.java | 2 +- .../command/specific/TestCommand.java | 2 +- .../netneutrality/db/AsyncMySqlAction.java | 72 ++++---------- .../java/netneutrality/db/MysqlDatabase.java | 73 +++++++++------ .../db/controllers/DBBlacklist.java | 93 ++++--------------- .../db/entities/AbstractEntity.java | 11 ++- .../netneutrality/db/entities/OGuild.java | 20 +++- .../db/entities/OGuildSetting.java | 4 +- .../netneutrality/db/models/MTableModel.java | 45 ++++++--- .../netneutrality/handler/ConsoleHandler.java | 34 ------- .../netneutrality/handler/LogHandler.java | 37 +++++++- .../{ => hooks/guilds}/ServerJoinHandler.java | 11 +-- .../{ => hooks}/message/EditHandler.java | 2 +- .../message/MessageReceivedHandler.java | 6 +- .../netneutrality/music/MusicManager.java | 51 +++++----- .../MusicPlayerAutoDisconnectThread.java | 41 ++++++++ .../netneutrality/utils/MessageFunction.java | 21 ++++- .../java/netneutrality/utils/Settings.java | 9 -- 50 files changed, 441 insertions(+), 376 deletions(-) create mode 100644 sql/add_debug_field_to_guilds_table.sql delete mode 100644 src/main/java/netneutrality/handler/ConsoleHandler.java rename src/main/java/netneutrality/handler/{ => hooks/guilds}/ServerJoinHandler.java (65%) rename src/main/java/netneutrality/handler/{ => hooks}/message/EditHandler.java (98%) rename src/main/java/netneutrality/handler/{ => hooks}/message/MessageReceivedHandler.java (97%) create mode 100644 src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java diff --git a/bot.config.example b/bot.config.example index 5495ed4..f6fe2c0 100644 --- a/bot.config.example +++ b/bot.config.example @@ -1,8 +1,8 @@ BOT_TOKEN= BOT_PREFIX= BOT_OWNER= -BOT_OWNERGUILD= -BOT_ERRORCHANNEL= +BOT_PAPISID= +BOT_PSID= MYSQL_HOST= MYSQL_USER= diff --git a/pom.xml b/pom.xml index 06f5297..0742d6d 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,11 @@ https://m2.dv8tion.net/releases + + jitpack + https://jitpack.io + + @@ -99,6 +104,16 @@ JDA 4.4.0_350 + + + + + + + com.github.walkyst + lavaplayer-fork + 1.3.97 + com.squareup.okhttp3 @@ -145,11 +160,6 @@ commons-lang3 3.12.0 - - com.sedmelluq - lavaplayer - 1.3.78 - junit junit diff --git a/sql/add_debug_field_to_guilds_table.sql b/sql/add_debug_field_to_guilds_table.sql new file mode 100644 index 0000000..accb099 --- /dev/null +++ b/sql/add_debug_field_to_guilds_table.sql @@ -0,0 +1 @@ +ALTER TABLE `guilds` ADD `debug` BOOLEAN NOT NULL DEFAULT '1' AFTER `logging`; \ No newline at end of file diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index e657422..8d1b5a0 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -10,6 +10,8 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.db.DBController; +import netneutrality.db.controllers.DBGuild; import netneutrality.db.entities.OGuild; import netneutrality.handler.ratelimiter.IMessageRateLimiter; import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; @@ -23,7 +25,9 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { public enum GuildSetting { - MUSIC_ROLE("music.role", null), MUSIC_CHANNEL("music.channel", null), BLACKLIST_CHANNELS("blacklist.exclude.channels", null); + MUSIC_ROLE("music.role", null), + MUSIC_CHANNEL("music.channel", null), + BLACKLIST_CHANNELS("blacklist.exclude.channels", null); private final String setting; private final String defaultValue; @@ -58,6 +62,8 @@ public class GuildManager { private GuildManager(Guild guild) { this.guild = guild; + handleJoinEvent(); + this.guildEntity = new OGuild(guild.getId()); this.rateLimiter = new MessageRateLimiterImpl(); @@ -72,14 +78,40 @@ public class GuildManager { } } + // Getter + public static Map getManagers() { + return managers; + } + public static GuildManager getManager(String guildId) { return managers.getOrDefault(guildId, null); } - public static Map getManagers() { - return managers; + public String getSetting(GuildSetting key) { + return guildEntity.getSettings().getSettingByKey(key.toString()); } + public boolean isLoggingEnabled() { + return guildEntity.isLogging(); + } + + public boolean isDebugEnabled() { + return guildEntity.isDebug(); + } + + public Map getSettings() { + return guildEntity.getSettings().getSettings(); + } + + public IMessageRateLimiter getRateLimiter() { + return rateLimiter; + } + + public Guild getGuild() { + return guild; + } + + public static boolean reloadSettingsForGuild(String guildId) { if (managers.containsKey(guildId)) { GuildManager manager = managers.get(guildId); @@ -111,33 +143,28 @@ public class GuildManager { MessageFunction.checkBlacklist(guild, message, channel); } - public String getSetting(String key) { - return guildEntity.getSettings().getSettingByKey(key); - } - - public String getSetting(GuildSetting key) { - return guildEntity.getSettings().getSettingByKey(key.toString()); - } - - public Map getSettings() { - return guildEntity.getSettings().getSettings(); + public boolean existInDb() { + return DBController.get().exists("guilds", "guild_id", guild.getId()); } public void reloadSettings() { guildEntity.reloadSettings(); } - public IMessageRateLimiter getRateLimiter() { - return rateLimiter; - } + public void handleJoinEvent() { + if (!existInDb()) { + ((DBGuild) DBController.get("guild")).insertGuildInDB(guild); - public Guild getGuild() { - return guild; - } - - - - private void load() { + guild.getTextChannels() + .stream() + .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .forEach(textChannel -> textChannel.sendMessage("Error logging enabled on channel " + textChannel.getAsMention()).queue()); + } } + + public void removeFromDB() { + ((DBGuild) DBController.get("guild")).removeGuildInDB(guild); + } + } diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 6ee210f..e16870c 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -3,13 +3,14 @@ package netneutrality; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.command.CommandManager; import netneutrality.db.DBController; -import netneutrality.handler.message.EditHandler; -import netneutrality.handler.message.MessageReceivedHandler; -import netneutrality.handler.ServerJoinHandler; +import netneutrality.handler.hooks.message.EditHandler; +import netneutrality.handler.hooks.message.MessageReceivedHandler; +import netneutrality.handler.hooks.guilds.ServerJoinHandler; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; import netneutrality.thread.BaseThreadFactory; @@ -29,10 +30,11 @@ public class MusicBot { public static void main(String[] args) { DBController.init(); + initJDA(); CommandManager.init(); - MusicManager.registerSources(); + MusicManager.initPlayerManager(); jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); @@ -66,6 +68,11 @@ public class MusicBot { return jda; } + public static User getSelf() { + return jda.getSelfUser(); + + } + private static void disconnect() { if (jda != null) { jda.shutdown(); diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 03fbb15..2530aae 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -25,27 +25,14 @@ public class ThreadManager { ExecutorService executor; switch (type) { - case FIXED: - executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); - break; - case SCHEDULED: - executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); - break; - default: - executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); + case FIXED -> executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); + case SCHEDULED -> executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); + default -> executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); } return executor; } - public static Future dispatch(ExecutorService executor, Runnable task) { - return executor.submit(task); - } - - public static Future dispatch(ExecutorService executor, Callable task) { - return executor.submit(task); - } - public static void shutdownExecutor() { System.out.println("[Executor] Shutting down..."); diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 0b13e68..2bceb6d 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -20,7 +20,7 @@ public abstract class AbstractCommand implements ICommand { * * @return the name of the command. */ - public abstract String getCommand(); + public abstract String getCommandName(); /** * @return all the aliases the command has diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java index 0655d4e..1695a55 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -10,6 +10,8 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import netneutrality.ThreadManager; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; import netneutrality.handler.LogHandler; import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; @@ -51,7 +53,7 @@ public class CommandContext { } public String getArg(int index) { - return getArgumentsAsArray()[index]; + return getArgumentsAsArray()[index]; } public String[] getArgumentsAsArray() { @@ -108,6 +110,10 @@ public class CommandContext { } } + public void reply(String format, Object... arguments) { + reply(String.format(format, arguments)); + } + public void reply(Message msg) { if (channel != null) { channel.sendMessage(msg).queue(); @@ -142,20 +148,20 @@ public class CommandContext { this.command = command; //TODO: Add usage check - if (command.needAdmin()) { - if (!UserFunction.isAdmin(member)) { - return; + try { + if (command.needAdmin()) { + if (!UserFunction.isAdmin(member)) { + return; + } } - } - if (command.canBeExecutedBy(guild, member)) { - - try { + if (command.canBeExecutedBy(guild, member)) { command.execute(this); - } catch (Exception e) { - LogHandler.log(e); } - + } catch (CommandErrorException | CommandExecutionException e) { + LogHandler.log(e); + } catch (Exception e) { + LogHandler.log(new CommandExecutionException("Error during command execution", this, e)); } } } diff --git a/src/main/java/netneutrality/command/CommandManager.java b/src/main/java/netneutrality/command/CommandManager.java index bf683bd..faf4ddc 100644 --- a/src/main/java/netneutrality/command/CommandManager.java +++ b/src/main/java/netneutrality/command/CommandManager.java @@ -44,8 +44,8 @@ public class CommandManager { if (!command.isEnabled()) continue; - if (!commands.containsKey(command.getCommand())) { - commands.put(command.getCommand(), command); + if (!commands.containsKey(command.getCommandName())) { + commands.put(command.getCommandName(), command); } } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index d5e0395..4b94212 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -30,7 +30,7 @@ public class HelpCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "help"; } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index de9a442..be1ecd8 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -24,7 +24,7 @@ public class PingCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "ping"; } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 56051b3..7616b68 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -22,7 +22,7 @@ public class ConfigureCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "configure"; } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 68a9414..7eb25cd 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -34,7 +34,7 @@ public class BitcoinPriceCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "bitcoin"; } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 3855472..84ca8af 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -33,7 +33,7 @@ public class CryptoPriceCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "crypto"; } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 2a17447..dacf593 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -34,7 +34,7 @@ public class EthereumPriceCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "ethereum"; } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index eb8e3b7..2d5e70b 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -34,7 +34,7 @@ public class LitecoinPriceCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "litecoin"; } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index b160d53..040556a 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -12,6 +12,7 @@ import netneutrality.command.CommandType; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; +import netneutrality.exceptions.CommandExecutionException; public class BlacklistCommand extends AbstractCommand { @@ -26,7 +27,7 @@ public class BlacklistCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "blacklist"; } @@ -53,6 +54,11 @@ public class BlacklistCommand extends AbstractCommand { @Override public void execute(CommandContext context) { String[] args = context.getArgumentsAsArray(); + DBBlacklist controller = ((DBBlacklist) DBController.get("blacklist")); + + if (controller == null) { + throw new CommandExecutionException("Error getting database controller", context, null); + } if (args.length > 0 && args.length < 3) { String word = (args.length == 2 ? args[1] : ""); @@ -63,7 +69,7 @@ public class BlacklistCommand extends AbstractCommand { context.getChannel().sendMessage("Retrieving list, please wait...").queue(t -> { StringBuilder sb = new StringBuilder(); - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(context.getGuild().getId(), mBlacklists -> { + controller.getBlacklistFromServer(context.getGuild().getId(), mBlacklists -> { for (MBlacklist bl : mBlacklists) { sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); } @@ -77,48 +83,40 @@ public class BlacklistCommand extends AbstractCommand { case "add": - ((DBBlacklist) DBController.get("blacklist")).add(new MBlacklist(word, true, context.getDiscordUser().getId(), context.getGuild().getId()), response -> { - if (response) { - context.getChannel().sendMessage("Added the word \"" + word + "\" to the blacklist.").queue(); - } else { - context.getChannel().sendMessage("Error adding \"" + word + "\" to the blacklist. It's already blacklisted!").queue(); - } - }); + if (controller.add(new MBlacklist(word, true, context.getDiscordUser().getId(), context.getGuild().getId()))) { + context.reply(String.format("Added the word [%s] to the blacklist.", word)); + } else { + context.reply(String.format("Error adding [%s] to the blacklist. It's already blacklisted!", word)); + } break; case "remove": - ((DBBlacklist) DBController.get("blacklist")).delete(word, context.getGuild().getId(), success -> { - if (success) { - context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } else { - context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); - } - }); + if (controller.delete(word, context.getGuild().getId())) { + context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + } break; case "disable": - ((DBBlacklist) DBController.get("blacklist")).disable(word, context.getGuild().getId(), success -> { - if (success) { - context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } else { - context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); - } - }); + if (controller.disable(word, context.getGuild().getId())) { + context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + } break; case "enable": - ((DBBlacklist) DBController.get("blacklist")).enable(word, context.getGuild().getId(), success -> { - if (success) { - context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); - } else { - context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); - } - }); + if (controller.enable(word, context.getGuild().getId())) { + context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + } else { + context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + } break; diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index 94ae9cd..dda3d85 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -24,7 +24,7 @@ public class PruneCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "prune"; } diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 713ff74..6701413 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -20,7 +20,7 @@ public class BitconnectCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "bitconnect"; } diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index 995b7f2..0af4460 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -22,7 +22,7 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "playing"; } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 44fc51f..b340dad 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -24,7 +24,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "deletequeue"; } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 1242f7e..39f8832 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -10,6 +10,8 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -21,7 +23,7 @@ public class JoinCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "join"; } @@ -43,7 +45,18 @@ public class JoinCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + + if (context.getGuildUser().getVoiceState() == null) { + throw new CommandExecutionException("Voice state is null", context, null); + } + + if (!context.getGuildUser().getVoiceState().inVoiceChannel()) { + throw new CommandErrorException("You are not in a voice channel", context, null); + } + + if (player.isConnected()) { + throw new CommandErrorException("Player is already in a voice channel", context, null); + } VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); player.connect(vChannel); diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 71b578b..65a149b 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -24,7 +24,7 @@ public class LeaveCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "leave"; } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 52c4b81..6f6948e 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -19,7 +19,7 @@ public class PlayCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "play"; } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 257d58b..a32964b 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -24,7 +24,7 @@ public class SkipCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "skip"; } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index b8cc556..53747e3 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -21,7 +21,7 @@ public class StopCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "stop"; } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 0eaa4fb..9c51f90 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -26,7 +26,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "viewqueue"; } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 35a7fe2..4c2cf75 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -26,7 +26,7 @@ public class VolumeCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "volume"; } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index d8ace4e..8e33acd 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -19,7 +19,7 @@ public class VoteSkipCommand extends AbstractMusicCommand { } @Override - public String getCommand() { + public String getCommandName() { return "voteskip"; } diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index e5bd4b0..e5ac876 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -34,7 +34,7 @@ public class DatabaseCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "database"; } diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java index 21bbeaf..d9ba04a 100644 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ b/src/main/java/netneutrality/command/specific/EvalMethod.java @@ -31,7 +31,7 @@ public class EvalMethod extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "evaluate"; } diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index 22f275e..8e53884 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -23,7 +23,7 @@ public class LoggingCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "logging"; } diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java index d629432..b538018 100644 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ b/src/main/java/netneutrality/command/specific/SellyCommand.java @@ -30,7 +30,7 @@ public class SellyCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "selly"; } diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java index 9d7ef72..2407c6e 100644 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ b/src/main/java/netneutrality/command/specific/TestCommand.java @@ -24,7 +24,7 @@ public class TestCommand extends AbstractCommand { } @Override - public String getCommand() { + public String getCommandName() { return "test"; } diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java index 6370575..eea1256 100644 --- a/src/main/java/netneutrality/db/AsyncMySqlAction.java +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -37,70 +37,34 @@ public class AsyncMySqlAction { } public void async(Consumer success) { + switch (type) { - case INSERT: - ThreadManager.dispatch(executor, () -> { - db.insert(this.sqlString, this.params); - }); - break; - case UPDATE: - ThreadManager.dispatch(executor, () -> { - db.update(this.sqlString, this.params); - }); - break; + case INSERT -> executor.submit(() -> success.accept(new MTableModel(db.insert(this.sqlString, this.params)))); + case UPDATE -> executor.submit(() -> success.accept(new MTableModel(db.update(this.sqlString, this.params)))); + case DELETE -> executor.submit(() -> success.accept(new MTableModel(db.delete(this.sqlString, this.params)))); + case SELECT -> executor.submit(() -> { + ResultSet result = db.prepareAndExecute(this.sqlString, this.params); - case DELETE: - ThreadManager.dispatch(executor, () -> { - db.delete(this.sqlString, this.params); - }); - break; - - case SELECT: - ThreadManager.dispatch(executor, () -> { - ResultSet result = db.prepareAndExecute(this.sqlString, this.params); - MTableModel table = MysqlDatabase.convertToTableModel(result, tableName); - - success.accept(table); - }); - break; + success.accept(MysqlDatabase.convertToTableModel(result, tableName)); + }); } } public MTableModel blocking() { + MTableModel table = new MTableModel(); + try { - switch (type) { - case INSERT: - ThreadManager.dispatch(executor, () -> { - db.insert(this.sqlString, this.params); - }).get(); - - case UPDATE: - ThreadManager.dispatch(executor, () -> { - db.update(this.sqlString, this.params); - }).get(); - - case DELETE: - ThreadManager.dispatch(executor, () -> { - db.delete(this.sqlString, this.params); - }).get(); - - case SELECT: - Callable task = () -> { - ResultSet result = db.prepareAndExecute(this.sqlString, this.params); - MTableModel table = MysqlDatabase.convertToTableModel(result, tableName); - - return table; - }; - - Future future = ThreadManager.dispatch(executor, task); - return future.get(); - } + table = switch (type) { + case INSERT -> executor.submit(() -> new MTableModel(db.insert(this.sqlString, this.params))).get(); + case UPDATE -> executor.submit(() -> new MTableModel(db.update(this.sqlString, this.params))).get(); + case DELETE -> executor.submit(() -> new MTableModel(db.delete(this.sqlString, this.params))).get(); + case SELECT -> executor.submit(() -> db.prepareAndExecute(this.sqlString, this.tableName, this.params)).get(); + }; } catch (InterruptedException | ExecutionException e) { - return null; + return table; } - return null; + return table; } - } diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 43592de..55afafa 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -10,11 +10,10 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Calendar; -import netneutrality.MusicBot; -import netneutrality.db.entities.EntityInterface; import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; import netneutrality.exceptions.UnimplementedParameterException; +import netneutrality.handler.LogHandler; import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,6 +21,7 @@ import org.slf4j.LoggerFactory; public class MysqlDatabase { private final static Logger logger = LoggerFactory.getLogger(MysqlDatabase.class); + private final static Object dmlLock = new Object(); protected Connection connection; private final String dbName; @@ -37,8 +37,11 @@ public class MysqlDatabase { public static CommandType stringToType(String str) { return CommandType.valueOf(str); } - } + public String getType() { + return type; + } + } protected MysqlDatabase(String dbName) { this.dbName = dbName; @@ -51,7 +54,7 @@ public class MysqlDatabase { connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); } catch (SQLException e) { logger.error("Error connecting to database. Shutting down..", e); - System.exit(0); + System.exit(-1); } } @@ -68,7 +71,7 @@ public class MysqlDatabase { stmt = connection.createStatement(); return stmt.executeQuery(query); } catch (SQLException e) { - logger.error(e.toString()); + LogHandler.log(e); } return null; @@ -80,9 +83,8 @@ public class MysqlDatabase { * * @param sql The SQL query to execute * @param params The parameters to include in the query - * @return an integer of how many row were affected */ - protected synchronized int update(String sql, Object... params) { + protected int update(String sql, Object... params) { return executeUpdate(sql, params); } @@ -94,7 +96,7 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - protected synchronized int insert(String sql, Object... params) { + protected int insert(String sql, Object... params) { return executeUpdate(sql, params); } @@ -106,27 +108,29 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return an integer of how many row were affected */ - protected synchronized int delete(String sql, Object... params) { + protected int delete(String sql, Object... params) { return executeUpdate(sql, params); } - public boolean exists(String table, String key, String value) { - return prepareAndExecuteAsync("SELECT 1 FROM " + table + " WHERE " + key + " = ?", value).blocking().isEmpty(); + private int executeUpdate(String sql, Object[] params) { + logger.debug("Query: " + sql); + + synchronized (dmlLock) { + try { + PreparedStatement query = connection.prepareStatement(sql); + resolveParameters(query, params); + return query.executeUpdate(); + } catch (SQLException e) { + LogHandler.log(e); + } + + return -1; + } } - private synchronized int executeUpdate(String sql, Object[] params) { - logger.debug("Query: " + sql); - - try { - PreparedStatement query = connection.prepareStatement(sql); - resolveParameters(query, params); - return query.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - - return -1; + public boolean exists(String table, String key, String value) { + return !prepareAndExecuteAsync(String.format("SELECT 1 FROM %s WHERE %s = ?", table, key), value).blocking().isEmpty(); } /** @@ -137,13 +141,12 @@ public class MysqlDatabase { * @param params The parameters to include in the query * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet, String)} */ - protected synchronized ResultSet prepareAndExecute(String sql, Object... params) { + protected ResultSet prepareAndExecute(String sql, Object... params) { try { PreparedStatement query = connection.prepareStatement(sql); resolveParameters(query, params); - ResultSet rs = query.executeQuery(); - return rs; + return query.executeQuery(); } catch (SQLException e) { logger.error(e.getMessage(), e); } @@ -151,6 +154,19 @@ public class MysqlDatabase { return null; } + protected MTableModel prepareAndExecute(String sql, String tableName, Object... params) { + + try { + PreparedStatement query = connection.prepareStatement(sql); + resolveParameters(query, params); + return convertToTableModel(query.executeQuery(), tableName); + } catch (SQLException e) { + logger.error(e.getMessage(), e); + } + + return null; + } + /** * Execute a SELECT statement with the specified parameters. * In the SQL query, where there is a parameter to be included, you need to replace it with ? @@ -206,8 +222,6 @@ public class MysqlDatabase { /** * Close the MySQL connection - * - * @throws SQLException */ public void close() throws SQLException { System.out.println("Closing database..."); @@ -249,8 +263,7 @@ public class MysqlDatabase { * @return a {@link MTableModel} with the appropriate column and rows */ protected static MTableModel convertToTableModel(ResultSet rs, String tableName) { - MTableModel table = new MTableModel(); - table.setName(tableName); + MTableModel table = new MTableModel(tableName); try { ResultSetMetaData metadata = rs.getMetaData(); diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 04a2d0e..d6d0207 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -14,77 +14,36 @@ public class DBBlacklist extends AbstractController { private final Logger logger = LoggerFactory.getLogger(DBBlacklist.class); - public void add(MBlacklist obj, Consumer success) { - isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> { - if (blacklisted == 0) { - database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getServerId(), obj.getWord(), obj.isEnabled(), obj.getCreatorId()).async(); - success.accept(true); - } else { - success.accept(false); - } - }); + public boolean add(MBlacklist obj) { + if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { + return database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getServerId(), obj.getWord(), obj.isEnabled(), obj.getCreatorId()).blocking().isSuccess(); + } + return false; } + public boolean delete(String word, String serverId) { + if (isAlreadyBlacklisted(word, serverId)) { + return database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).blocking().isSuccess(); + } - - public void delete(String word, String serverId, Consumer success) { - isAlreadyBlacklisted(word, serverId, blacklisted -> { - if (blacklisted >= 1) { - database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(); - logger.debug("removed word from blacklist"); - success.accept(true); - } else { - logger.info("not blacklisted"); - success.accept(false); - } - }); - + return false; } - public void enable(String word, String serverId, Consumer success) { - - isAlreadyBlacklisted(word, serverId, blacklisted -> { - if (blacklisted >= 1) { - database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 1 WHERE word = ? AND guild_id = ?", word, serverId).async(); - logger.info("enabled"); - success.accept(true); - } else { - logger.info("error enabling"); - success.accept(false); - } - }); + public boolean enable(String word, String serverId) { + if (isAlreadyBlacklisted(word, serverId)) { + return database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 1 WHERE word = ? AND guild_id = ?", word, serverId).blocking().isSuccess(); + } + return false; } - public void disable(String word, String serverId, Consumer success) { - - isAlreadyBlacklisted(word, serverId, blacklisted -> { - if (blacklisted >= 1) { - database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 0 WHERE word = ? AND guild_id = ?", word, serverId).async(); - logger.info("disabled"); - success.accept(true); - } else { - logger.info("error disabling"); - success.accept(false); - } - }); - - } - - @Deprecated - public void getBlacklistForWord(String word, String serverId, Consumer success) { - - database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async((table -> { - MBlacklist blacklisted = null; - - if (table.getNbRows() > 0) { - blacklisted = new MBlacklist(table.getRow(0)); - } - success.accept(blacklisted); - - })); + public boolean disable(String word, String serverId) { + if (isAlreadyBlacklisted(word, serverId)) { + return database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 0 WHERE word = ? AND guild_id = ?", word, serverId).blocking().isSuccess(); + } + return false; } public void getBlacklistFromServer(String serverId, Consumer> success) { @@ -104,7 +63,6 @@ public class DBBlacklist extends AbstractController { } - @Deprecated public ArrayList getBlacklistFromServer(String serverId) { MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE guild_id = ? AND enabled = 1", serverId).blocking(); @@ -130,17 +88,6 @@ public class DBBlacklist extends AbstractController { return false; } - private void isAlreadyBlacklisted(String word, String serverId, Consumer result) { - - database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(table -> { - if (!table.isEmpty()) { - int count = Integer.parseInt(table.getRowModel(0).getItem(0).toString()); - - result.accept(count); - } - }); - } - @Override public String getControllerName() { return "blacklist"; diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java index 0831784..05767d3 100644 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -8,6 +8,7 @@ package netneutrality.db.entities;/* import netneutrality.MusicBot; import netneutrality.db.DBController; import netneutrality.db.models.MTableModel; +import netneutrality.handler.LogHandler; public abstract class AbstractEntity implements EntityInterface { private final String primaryKey; @@ -21,14 +22,18 @@ public abstract class AbstractEntity implements EntityInterface { fillTableModel(); - if (!table.isEmpty()) - convertFromTableModel(table); + try { + if (!table.isEmpty()) + convertFromTableModel(table); + } catch (NullPointerException e) { + LogHandler.log("Table structure does not match expected variables", e); + } } private void fillTableModel() throws ArrayIndexOutOfBoundsException { StringBuilder whereClause = new StringBuilder(); for (String pk : getPrimaryKeys()) { - whereClause.append(pk + " = ?"); + whereClause.append(pk).append(" = ?"); //TODO: Fix last and if (getPrimaryKeys().length > 1) diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java index 557dab0..14158b2 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -12,8 +12,9 @@ import netneutrality.db.models.MTableModel; public class OGuild extends AbstractEntity { private String guildID; - public boolean logging; - public String logchannel; + private boolean logging; + private boolean debug; + private String logchannel; private OGuildSetting settings; @@ -23,6 +24,18 @@ public class OGuild extends AbstractEntity { this.settings = new OGuildSetting(this); } + public boolean isLogging() { + return logging; + } + + public boolean isDebug() { + return debug; + } + + public String getLogchannel() { + return logchannel; + } + public void reloadSettings() { GuildManager.logger.debug("Reloading settings for guild: " + guildID); this.settings = new OGuildSetting(this); @@ -56,7 +69,8 @@ public class OGuild extends AbstractEntity { public void convertFromTableModel(MTableModel table) { this.guildID = (String) table.getRow(0).get(0); this.logging = ((Integer) table.getRow(0).get(1)) == 1; - this.logchannel = (String) table.getRow(0).get(2); + this.debug = ((Boolean) table.getRow(0).get(2)); + this.logchannel = (String) table.getRow(0).get(3); } } diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java index c463c73..1c4aaf1 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -8,9 +8,7 @@ package netneutrality.db.entities;/* import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class OGuildSetting extends AbstractEntity { private final OGuild guild; diff --git a/src/main/java/netneutrality/db/models/MTableModel.java b/src/main/java/netneutrality/db/models/MTableModel.java index 4766908..420f275 100644 --- a/src/main/java/netneutrality/db/models/MTableModel.java +++ b/src/main/java/netneutrality/db/models/MTableModel.java @@ -7,53 +7,69 @@ package netneutrality.db.models; * https://discord.gg/CdFcyQ */ -import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; public class MTableModel { - private String name; + private final boolean emptyResult; + private final boolean success; + private final String name; private final List column; private final MRowsModel rows; - public MTableModel() { + this.emptyResult = true; + this.success = false; + this.name = null; + this.column = new LinkedList<>(); + this.rows = new MRowsModel(); + } + + public MTableModel(int success) { + this.emptyResult = true; + this.success = success > 0; this.name = null; this.column = new LinkedList<>(); this.rows = new MRowsModel(); } public MTableModel(String tableName) { + this.emptyResult = false; + this.success = true; this.name = tableName; this.column = new LinkedList<>(); this.rows = new MRowsModel(); } public MTableModel(String... columns) { + this.emptyResult = false; + this.success = true; this.name = null; this.column = new LinkedList<>(); this.rows = new MRowsModel(); - this.column.addAll(Arrays.asList(columns)); + Collections.addAll(column, columns); + } + + public boolean isEmptyResult() { + return emptyResult; + } + + public boolean isSuccess() { + return success; } public String getName() { return name; } - public void setName(String name) { - if (this.name != null) - this.name = name; - } - - public MTableModel addColumn(String name) { + public void addColumn(String name) { column.add(name); - return this; } - public MTableModel addRow(MRowModel row) { + public void addRow(MRowModel row) { rows.addRow(row); - return this; } public MRowsModel getRows() { @@ -96,4 +112,7 @@ public class MTableModel { public String toString() { return "Column: " + column + ", Rows (" + getNbRows() + "): " + rows; } + + + } diff --git a/src/main/java/netneutrality/handler/ConsoleHandler.java b/src/main/java/netneutrality/handler/ConsoleHandler.java deleted file mode 100644 index 6a489e0..0000000 --- a/src/main/java/netneutrality/handler/ConsoleHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package netneutrality.handler; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -//TODO: To be replaced by HTTP API actions -public class ConsoleHandler { - - - private final static Logger logger = LoggerFactory.getLogger(ConsoleHandler.class); - public ConsoleHandler() { - logger.info("Console input ready!"); - } - - public String init() { - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - - String input = ""; - do { - System.out.print(">"); - try { - input = br.readLine(); - } catch (IOException e) { - e.printStackTrace(); - } - } while (!input.equalsIgnoreCase("quit")); - - return input; - } -} diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index 15585e9..2484813 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -6,12 +6,17 @@ package netneutrality.handler; * https://discord.gg/CdFcyQ */ +import netneutrality.GuildManager; +import netneutrality.MusicBot; import netneutrality.command.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; +import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.sql.SQLException; + public class LogHandler { private final static Logger logger = LoggerFactory.getLogger(LogHandler.class); @@ -27,24 +32,52 @@ public class LogHandler { sendMessageToChannel((CommandErrorException) e); } else if (e instanceof CommandExecutionException) { logInternally((CommandExecutionException) e); + tryLogToDebugChannel((CommandExecutionException) e); + } else if (e instanceof SQLException) { + logger.error(e.getMessage(), e); } else { logger.error(e.getMessage(), e); } } + public static void log(String s, Exception e) { + logger.error(s, e); + } + public static void logThread(Thread t, Throwable e) { - logger.error("Exception thrown in thread {}", t); + logger.error("Uncaught exception thrown in thread {}", t); log((Exception) e); } private static void logInternally(CommandExecutionException error) { CommandContext context = error.getCommandContext(); - logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommand(), context.getGuild().getId(), error.getMessage(), error); + logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage(), error); + } + + private static void tryLogToAllChannels(SQLException error) { + + + } + + private static void tryLogToDebugChannel(CommandExecutionException error) { + CommandContext context = error.getCommandContext(); + + if (context.getGuild() != null) { + if (GuildManager.getManager(context.getGuild()).isDebugEnabled()) { + context.getGuild() + .getTextChannels() + .stream() + .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, error)).queue()); + } + } + } private static void sendMessageToChannel(CommandErrorException error) { CommandContext context = error.getCommandContext(); + logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage()); context.reply(error.getMessage()); } } diff --git a/src/main/java/netneutrality/handler/ServerJoinHandler.java b/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java similarity index 65% rename from src/main/java/netneutrality/handler/ServerJoinHandler.java rename to src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java index a498130..a015db9 100644 --- a/src/main/java/netneutrality/handler/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler; +package netneutrality.handler.hooks.guilds; /* * Copyright (c) anthorob @@ -10,21 +10,18 @@ package netneutrality.handler; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBGuild; +import netneutrality.GuildManager; import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { @Override public void onGuildJoin(@NotNull GuildJoinEvent event) { - ((DBGuild) DBController.get("guild")).insertGuildInDB(event.getGuild()); - + GuildManager.getManager(event.getGuild()).handleJoinEvent(); } @Override public void onGuildLeave(@NotNull GuildLeaveEvent event) { - ((DBGuild) DBController.get("guild")).removeGuildInDB(event.getGuild()); - + GuildManager.getManager(event.getGuild()).removeFromDB(); } } diff --git a/src/main/java/netneutrality/handler/message/EditHandler.java b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java similarity index 98% rename from src/main/java/netneutrality/handler/message/EditHandler.java rename to src/main/java/netneutrality/handler/hooks/message/EditHandler.java index ff3f80d..c680058 100644 --- a/src/main/java/netneutrality/handler/message/EditHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler.message; +package netneutrality.handler.hooks.message; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/handler/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java similarity index 97% rename from src/main/java/netneutrality/handler/message/MessageReceivedHandler.java rename to src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index f4a99a1..3e798b9 100644 --- a/src/main/java/netneutrality/handler/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler.message; +package netneutrality.handler.hooks.message; /* * Copyright (c) anthorob * @@ -30,11 +30,11 @@ public class MessageReceivedHandler extends ListenerAdapter { if (user.isBot()) return; if (event.isWebhookMessage()) return; + CommandContext context = CommandContext.createContext(event); + GuildManager.getManager(guild).getRateLimiter().check(member, message, channel); GuildManager.getManager(guild).checkAndLogMessage(message, member, channel); - CommandContext context = CommandContext.createContext(event); - String msg = message.getContentDisplay().trim(); if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 77424b8..368cfd7 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -11,6 +11,7 @@ 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.youtube.YoutubeHttpContextFilter; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -19,6 +20,8 @@ import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.ThreadManager; import netneutrality.command.CommandContext; import netneutrality.exceptions.CommandErrorException; +import netneutrality.thread.MusicPlayerAutoDisconnectThread; +import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,11 +37,12 @@ public class MusicManager { private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + private final static Map managers = new ConcurrentHashMap<>(); private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; - private final static Map managers = new ConcurrentHashMap<>(); + ScheduledExecutorService autoDisconnectThread; private MusicManager(Guild guild) { @@ -48,6 +52,8 @@ public class MusicManager { guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); player.setVolume(15); + autoDisconnectThread = (ScheduledExecutorService) ThreadManager.getExecutor("music-disconnect", ThreadManager.ExecutorType.SCHEDULED); + autoDisconnectThread.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 120, 120, TimeUnit.SECONDS); managers.put(guild.getId(), this); } @@ -60,25 +66,22 @@ public class MusicManager { } } - public static void registerSources() { + public static void initPlayerManager() { AudioSourceManagers.registerRemoteSources(playerManager); + + YoutubeHttpContextFilter.setPAPISID(Settings.getInstance().get("BOT_PAPISID", "")); + YoutubeHttpContextFilter.setPSID(Settings.getInstance().get("BOT_PSID", "")); } public boolean isConnectedTo(VoiceChannel vChannel) { return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); } - public synchronized void connect(VoiceChannel vChannel) { + public void connect(VoiceChannel vChannel) { if (vChannel != null && !isConnectedTo(vChannel)) { guild.getAudioManager().openAudioConnection(vChannel); - - ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED)).scheduleWithFixedDelay(() -> { - if ((getCurrentlyPlaying() == null && scheduler.getQueue().isEmpty()) || vChannel.getMembers().size() == 0) { - leave(); - } - }, 120, 120, TimeUnit.SECONDS); } else { - logger.error("Error connecting!"); + throw new RuntimeException("Error connecting to voice channel"); } } @@ -96,6 +99,10 @@ public class MusicManager { return info.getRequester(); } + public Guild getGuild() { + return guild; + } + public void leave() { if (isConnected()) { player.stopTrack(); @@ -103,7 +110,6 @@ public class MusicManager { } scheduler.resetTopic(); - System.out.println(scheduler.getQueue().size()); } public static void disconnectPlayers() { @@ -133,7 +139,6 @@ public class MusicManager { } VoiceChannel vChannel = member.getVoiceState().getChannel(); - if (needToBeConnected && !isConnectedTo(vChannel)) { throw new CommandErrorException("Not in your voice channel", context, null); } @@ -168,29 +173,33 @@ public class MusicManager { public void voteSkip(CommandContext context) { Queue queue = scheduler.getQueue(); VoiceChannel voiceChannel = guild.getAudioManager().getConnectedChannel(); + TrackScheduler.TrackInfo info = queue.peek(); if (getCurrentlyPlaying() == null) { return; } + if (info == null) { + return; + } + // Minus the bot itself int connected = voiceChannel.getMembers().size() - 1; - if (connected > 2) { - TrackScheduler.TrackInfo info = queue.peek(); + if (connected > 2) { double needed = connected / 2.1; - if (info != null) { - info.toggleSkip(context.getGuildUser()); + info.toggleSkip(context.getGuildUser()); - if (info.getSkips().size() > needed) { - skip(1); - } else { - context.reply(String.format("Current skips: %d/%f", info.getSkips().size(), Math.ceil(needed))); - } + if (info.getSkips().size() > needed) { + context.reply("Skipping current track: %s", info.getTrack().getInfo().title); + skip(1); + } else { + context.reply("Current skips: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); } } else { + context.reply("Skipping current track since not enough people are connected to the voice channel."); skip(1); } } diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java new file mode 100644 index 0000000..9c19ba3 --- /dev/null +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -0,0 +1,41 @@ +package netneutrality.thread;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.VoiceChannel; +import netneutrality.MusicBot; +import netneutrality.music.MusicManager; + +import java.util.List; + +public class MusicPlayerAutoDisconnectThread implements Runnable { + + MusicManager manager; + + public MusicPlayerAutoDisconnectThread(MusicManager musicManager) { + manager = musicManager; + } + + @Override + public void run() { + Guild guild = manager.getGuild(); + VoiceChannel channel = guild.getAudioManager().getConnectedChannel(); + + if (manager.getCurrentlyPlaying() == null && manager.getScheduler().getQueue().isEmpty()) { + manager.leave(); + return; + } + + if (channel != null) { + List members = channel.getMembers().stream().filter(member -> !member.getId().equals(MusicBot.getSelf().getId())).toList(); + + if (members.size() == 0) + manager.leave(); + } + } +} diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index d198d13..18d13ea 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -17,10 +17,12 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; +import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; @@ -179,7 +181,7 @@ public class MessageFunction { message.setColor(Color.GREEN); } - message.addField(String.format("%s%s %s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommand(), availAlias, usage), description, false); + message.addField(String.format("%s%s %s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommandName(), availAlias, usage), description, false); } } @@ -190,6 +192,21 @@ public class MessageFunction { return messages; } + public static MessageEmbed buildDebugMessage(CommandContext context, CommandExecutionException error) { + EmbedBuilder message = new EmbedBuilder(); + message.setColor(Color.RED); + message.setTitle(":warning: Exception in command execution"); + message.addField("Caused by command:", context.getCommand().getCommandName(), false); + message.addField("Exception:", error.getMessage(), false); + if (error.getCause() != null) { + message.addField("Caused by:", error.getCause().getMessage(), false); + } + message.setFooter("Requested by " + context.getDiscordUser().getName(), context.getDiscordUser().getAvatarUrl()); + message.setTimestamp(OffsetDateTime.now()); + + return message.build(); + } + public static void checkBlacklist(Guild guild, Message message, TextChannel channel) { ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guild.getId(), mBlacklists -> { @@ -211,4 +228,6 @@ public class MessageFunction { }); } + + } diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index fad2544..0179810 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -67,13 +67,4 @@ public class Settings { return get("BOT_OWNER"); } - public String getOwnerGuild() { - return get("BOT_OWNERGUILD"); - } - - public String getLogChannel() { - return get("BOT_ERRORCHANNEL"); - } - - } From f68d778c0c0bb96604be87731414bb9b2d3f980d Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 18 Feb 2022 17:18:59 -0500 Subject: [PATCH 064/155] Command usage done, start implementing configure command, refactor music manager --- src/main/java/netneutrality/GuildManager.java | 22 +++--- .../command/AbstractCommand.java | 28 ------- .../netneutrality/command/CommandContext.java | 7 +- .../netneutrality/command/CommandUsage.java | 43 ++++++++++- .../java/netneutrality/command/ICommand.java | 28 +++++++ .../command/basic/HelpCommand.java | 34 ++++++-- .../command/bot/ConfigureCommand.java | 42 ++++++++++ .../command/message/BlacklistCommand.java | 9 ++- .../command/music/SkipCommand.java | 16 ++-- .../netneutrality/db/AsyncMySqlAction.java | 18 ++--- .../db/controllers/DBBlacklist.java | 17 ---- .../db/controllers/DBLogging.java | 21 +---- .../db/controllers/DBMessage.java | 38 +++------ .../db/controllers/DBSettings.java | 13 ---- .../db/entities/OGuildSetting.java | 2 +- .../hooks/voice/VoiceEventHandler.java | 37 +++++++++ .../http/server/ActionHandler.java | 12 ++- .../music/LoadResultHandler.java | 77 ------------------- .../netneutrality/music/MusicManager.java | 57 +++++++++++++- .../netneutrality/music/TrackScheduler.java | 2 + .../netneutrality/thread/ShutdownThread.java | 6 +- .../netneutrality/utils/MessageFunction.java | 28 ++++--- 22 files changed, 310 insertions(+), 247 deletions(-) create mode 100644 src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java delete mode 100644 src/main/java/netneutrality/music/LoadResultHandler.java diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 8d1b5a0..7e898a1 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -25,9 +25,9 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { public enum GuildSetting { - MUSIC_ROLE("music.role", null), - MUSIC_CHANNEL("music.channel", null), - BLACKLIST_CHANNELS("blacklist.exclude.channels", null); + MUSIC_ROLE("MUSIC_ROLE", ""), + MUSIC_CHANNEL("MUSIC_CHANNEL", ""), + BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); private final String setting; private final String defaultValue; @@ -57,7 +57,7 @@ public class GuildManager { public static final Logger logger = LoggerFactory.getLogger(GuildManager.class); private static final Map managers = new ConcurrentHashMap<>(); private final Guild guild; - private final OGuild guildEntity; + private OGuild guildEntity; private final IMessageRateLimiter rateLimiter; private GuildManager(Guild guild) { @@ -65,7 +65,6 @@ public class GuildManager { handleJoinEvent(); this.guildEntity = new OGuild(guild.getId()); - this.rateLimiter = new MessageRateLimiterImpl(); managers.put(guild.getId(), this); } @@ -124,14 +123,10 @@ public class GuildManager { } public static boolean reloadSettingsForGuild(Guild guild) { - if (managers.containsKey(guild.getId())) { - GuildManager manager = GuildManager.getManager(guild.getId()); - manager.reloadSettings(); + GuildManager manager = GuildManager.getManager(guild.getId()); + manager.reloadSettings(); - return true; - } - - return false; + return true; } public void checkAndLogMessage(Message message, Member member, TextChannel channel) { @@ -148,7 +143,8 @@ public class GuildManager { } public void reloadSettings() { - guildEntity.reloadSettings(); + logger.debug("Reloading guild entity: " + guild.getId()); + this.guildEntity = new OGuild(guild.getId()); } public void handleJoinEvent() { diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 2bceb6d..071264a 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -5,34 +5,6 @@ import net.dv8tion.jda.api.entities.Member; public abstract class AbstractCommand implements ICommand { - /** - * @return if the command needs administrator privilege - */ - public abstract boolean needAdmin(); - - /** - * @return if the command should be loaded at runtime - */ - public abstract boolean isEnabled(); - - /** - * The command name that a user will write in a channel - * - * @return the name of the command. - */ - public abstract String getCommandName(); - - /** - * @return all the aliases the command has - */ - public abstract String[] getAlias(); - - public abstract String getUsage(); - - public abstract String getDescription(); - - public abstract CommandType getType(); - @Override public boolean canBeExecutedBy(Guild guild, Member member) { return true; diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java index 1695a55..51e19b3 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -7,6 +7,7 @@ package netneutrality.command; */ import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import netneutrality.ThreadManager; @@ -133,13 +134,17 @@ public class CommandContext { } public void replyPrivate(String msg) { - user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + replyPrivate(new MessageBuilder().append(msg).build()); } public void replyPrivate(Message msg) { user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); } + public void replyPrivate(MessageEmbed embed, MessageEmbed... embeds) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embed, embeds)).queue(); + } + public void replyPrivate(Collection embeds) { user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); } diff --git a/src/main/java/netneutrality/command/CommandUsage.java b/src/main/java/netneutrality/command/CommandUsage.java index 956b946..db48cc8 100644 --- a/src/main/java/netneutrality/command/CommandUsage.java +++ b/src/main/java/netneutrality/command/CommandUsage.java @@ -5,6 +5,7 @@ package netneutrality.command;/* * https://discord.gg/CdFcyQ */ +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -17,13 +18,25 @@ public class CommandUsage { } private final Type type; + private final String[] values; private final String description; - public Argument(Type t, String desc) { + public Argument(Type t, String[] values, String desc) { + if (t == Type.REQUIRED && (values == null || values.length == 0)) + throw new IllegalArgumentException("Command usage: values can't be null if type is required"); + + if (t == Type.OPTIONAL && (desc == null || desc.isEmpty())) + throw new IllegalArgumentException("Command usage: description can't be null if type is optional"); + this.type = t; + this.values = values; this.description = desc; } + public String[] getValues() { + return values; + } + public String getDescription() { return description; } @@ -39,11 +52,35 @@ public class CommandUsage { Collections.addAll(args, arguments); } + public CommandUsage addArgument(Argument argument) { + args.add(argument); + return this; + } + public static CommandUsage create(Argument... arguments) { return new CommandUsage(arguments); } - public Set getArguments() { - return args; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Available arguments: ").append(args.size()).append("\n"); + for (Argument arg : args) { + sb.append("<"); + if (arg.getType() == Argument.Type.OPTIONAL) + sb.append("Optional argument: ").append(arg.getDescription()); + + if (arg.getType() == Argument.Type.REQUIRED) { + sb.append("required: ").append(Arrays.toString(arg.getValues())); + + if (arg.getDescription() != null && !arg.getDescription().isEmpty()) + sb.append(": ").append(arg.getDescription()); + } + + sb.append("> "); + } + + return sb.toString(); } } diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 6af6385..caae58b 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -12,6 +12,34 @@ import netneutrality.exceptions.CommandExecutionException; public interface ICommand { + /** + * @return if the command needs administrator privilege + */ + boolean needAdmin(); + + /** + * @return if the command should be loaded at runtime + */ + boolean isEnabled(); + + /** + * The command name that a user will write in a channel + * + * @return the name of the command. + */ + String getCommandName(); + + /** + * @return all the aliases the command has + */ + String[] getAlias(); + + String getUsage(); + + String getDescription(); + + CommandType getType(); + boolean canBeExecutedBy(Guild guild, Member member); /** diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 4b94212..b2bab1e 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -8,10 +8,7 @@ package netneutrality.command.basic; import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; -import netneutrality.command.CommandManager; -import netneutrality.command.CommandType; +import netneutrality.command.*; import netneutrality.utils.MessageFunction; import netneutrality.utils.UserFunction; @@ -56,9 +53,32 @@ public class HelpCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - List help = MessageFunction.buildHelpMessage(CommandManager.commands, CommandManager.commandsAlias, UserFunction.isAdmin(context.getGuildUser())); + if (context.getArgumentsAsArray().length == 0) { + List help = MessageFunction.buildHelpMessage(CommandManager.commands, UserFunction.isAdmin(context.getGuildUser())); + + context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); + context.replyPrivate(help); + } + + if (context.getArgumentsAsArray().length == 1) { + String cmd = context.getArg(0); + + if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { + AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); + + if (c.needAdmin() && !UserFunction.isAdmin(context.getGuildUser())) { + context.replyPrivate("Command [" + c.getCommandName() + "] requires admin privileges"); + } + + System.out.println(CommandUsage.create(new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"get", "add"}, ""))); + + MessageEmbed help = MessageFunction.buildHelpMessage(c); + context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); + context.replyPrivate(help); + } + } + + - context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); - context.replyPrivate(help); } } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 7616b68..104f522 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -6,9 +6,15 @@ package netneutrality.command.bot; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.entities.Role; +import netneutrality.GuildManager; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.db.DBController; +import netneutrality.db.MysqlDatabase; + +import java.util.List; public class ConfigureCommand extends AbstractCommand { @Override @@ -48,6 +54,42 @@ public class ConfigureCommand extends AbstractCommand { @Override public void execute(CommandContext context) { + String[] args = context.getArgumentsAsArray(); + MysqlDatabase database = DBController.get(); + if (args.length > 0) { + + if (context.getArg(0).equals("musicrole")) { + + if (args.length == 1) { + String roleDb = GuildManager.getManager(context.getGuild()).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + Role role = null; + if (!roleDb.isEmpty()) { + role = context.getGuild().getRoleById(roleDb); + } + + context.reply("Current role needed to use music commands (default is anyone): %s", (role == null ? "Everyone" : role.getName())); + } + + if (args.length == 2) { + List roles = context.getMessage().getMentionedRoles(); + + if (roles.size() == 1) { + Role role = roles.get(0); + if (role.getGuild().getId().equals(context.getGuild().getId())) { + database.prepareAndExecuteAsync("UPDATE guild_settings SET music_role = ? WHERE guild_id = ?", role.getId(), context.getGuild().getId()).blocking(); + context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); + } + } + + if (context.getArg(1).equals("reset")) { + database.prepareAndExecuteAsync("UPDATE guild_settings SET music_role = null WHERE guild_id = ?", context.getGuild().getId()).blocking(); + context.reply("Successful reset of the role"); + } + } + } + + + } } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 040556a..986ae79 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -14,6 +14,8 @@ import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; import netneutrality.exceptions.CommandExecutionException; +import java.util.ArrayList; + public class BlacklistCommand extends AbstractCommand { @Override @@ -69,13 +71,12 @@ public class BlacklistCommand extends AbstractCommand { context.getChannel().sendMessage("Retrieving list, please wait...").queue(t -> { StringBuilder sb = new StringBuilder(); - controller.getBlacklistFromServer(context.getGuild().getId(), mBlacklists -> { - for (MBlacklist bl : mBlacklists) { + ArrayList blacklists = controller.getBlacklistFromServer(context.getGuild().getId()); + for (MBlacklist bl : blacklists) { sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); } - t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (mBlacklists.isEmpty() ? "No word found" : sb.toString())).queue(); - }); + t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (blacklists.isEmpty() ? "No word found" : sb.toString())).queue(); }); diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index a32964b..7a092e9 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -11,13 +11,9 @@ import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; +import netneutrality.utils.UserFunction; public class SkipCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } - @Override public boolean isEnabled() { return true; @@ -40,7 +36,7 @@ public class SkipCommand extends AbstractMusicCommand { @Override public String getDescription() { - return "Used to skip to the next track in the queue (requires admin privileges)"; + return "Used to skip to the next track in the queue (if no admin privileges, vote skip instead)"; } @Override @@ -48,11 +44,15 @@ public class SkipCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - if (context.getArgumentsAsArray().length > 0) { + // Combined fonctionality of vote skip + if (context.getArgumentsAsArray().length > 0 && UserFunction.isAdmin(context.getGuildUser())) { int skips = Integer.parseInt(context.getArg(0)); player.skip(skips); } else { - player.skip(1); + if (UserFunction.isAdmin(context.getGuildUser())) + player.skip(1); + else + player.voteSkip(context); } } diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java index eea1256..283abdb 100644 --- a/src/main/java/netneutrality/db/AsyncMySqlAction.java +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -51,18 +51,14 @@ public class AsyncMySqlAction { } public MTableModel blocking() { - MTableModel table = new MTableModel(); + MTableModel table; - try { - table = switch (type) { - case INSERT -> executor.submit(() -> new MTableModel(db.insert(this.sqlString, this.params))).get(); - case UPDATE -> executor.submit(() -> new MTableModel(db.update(this.sqlString, this.params))).get(); - case DELETE -> executor.submit(() -> new MTableModel(db.delete(this.sqlString, this.params))).get(); - case SELECT -> executor.submit(() -> db.prepareAndExecute(this.sqlString, this.tableName, this.params)).get(); - }; - } catch (InterruptedException | ExecutionException e) { - return table; - } + table = switch (type) { + case INSERT -> new MTableModel(db.insert(this.sqlString, this.params)); + case UPDATE -> new MTableModel(db.update(this.sqlString, this.params)); + case DELETE -> new MTableModel(db.delete(this.sqlString, this.params)); + case SELECT -> db.prepareAndExecute(this.sqlString, this.tableName, this.params); + }; return table; } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index d6d0207..9aefc9d 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -46,23 +46,6 @@ public class DBBlacklist extends AbstractController { return false; } - public void getBlacklistFromServer(String serverId, Consumer> success) { - database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE guild_id = ? AND enabled = 1", serverId).async(model -> { - ArrayList output = new ArrayList<>(); - - if (model.getNbRows() > 0) { - - for (int row = 0; row < model.getNbRows(); row++) { - MBlacklist bl = new MBlacklist(model.getRow(row)); - output.add(bl); - } - } - - success.accept(output); - }); - - } - public ArrayList getBlacklistFromServer(String serverId) { MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE guild_id = ? AND enabled = 1", serverId).blocking(); diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java index f874553..bb2b93d 100644 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ b/src/main/java/netneutrality/db/controllers/DBLogging.java @@ -7,30 +7,11 @@ package netneutrality.db.controllers; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.MusicBot; -import netneutrality.ThreadManager; import netneutrality.db.AbstractController; -import netneutrality.db.DBController; import netneutrality.db.models.MTableModel; -import netneutrality.handler.LogHandler; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.function.Consumer; public class DBLogging extends AbstractController { - public void getLoggingChannel(String serverId, Consumer success) { - database.prepareAndExecuteAsync("SELECT channelId FROM logging WHERE guild_id = ?", serverId).async((table) -> { - TextChannel txt = MusicBot.getJDA().getGuildById(serverId).getTextChannelById((String) table.getRow(0).get(0)); - - success.accept(txt); - }); - - } - public void setupLog(String serverId, String channelId) { database.prepareAndExecuteAsync("INSERT INTO logging VALUES(?,?,?)", serverId, channelId, true).blocking(); } @@ -42,7 +23,7 @@ public class DBLogging extends AbstractController { public boolean isLoggingEnabled(String serverId, String channelId) { MTableModel table = database.prepareAndExecuteAsync("SELECT enabled FROM logging WHERE guild_id = ? AND channelId = ?", serverId, channelId).blocking(); - return Boolean.parseBoolean((String) table.getRow(0).get(0)); + return (Boolean) table.getRow(0).get(0); } @Override diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index c360293..22fa677 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -28,18 +28,18 @@ public class DBMessage extends AbstractController { } public void log(Guild guild, TextChannel channel, Member author, Message message) { - String serverid = guild.getId(); - String channelid = channel.getId(); - String userid = author.getId(); - Date datesent = new Date(message.getTimeCreated().toInstant().toEpochMilli()); - String messageid = message.getId(); - String msg = message.getContentRaw().trim(); + String guildId = guild.getId(); + String channelId = channel.getId(); + String authorId = author.getId(); + Date dateSent = new Date(message.getTimeCreated().toInstant().toEpochMilli()); + String messageId = message.getId(); + String msg = message.getContentRaw().trim(); - database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", serverid, channelid, userid, datesent, messageid, msg, null).async(); + database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", guildId, channelId, authorId, dateSent, messageId, msg, null).blocking(); } public void logEdit(String messageId, String newMessage) { - database.prepareAndExecuteAsync("UPDATE log_message SET edited_message = ? WHERE message_id = ?", newMessage, messageId).async(); + database.prepareAndExecuteAsync("UPDATE log_message SET edited_message = ? WHERE message_id = ?", newMessage, messageId).blocking(); } @@ -52,26 +52,10 @@ public class DBMessage extends AbstractController { return null; } - public void getMessagesFromUser(String username, String serverName, int max, Consumer> success) { - database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE user_id = ? AND server_id = ? ORDER BY dateSent DESC LIMIT ?", username, serverName, max).async(table -> { - ArrayList messages = new ArrayList<>(); - - if (table.getNbRows() > 0) { - for (int row = 0; row < max; row++) { - messages.add(new MMessage(table.getRowModel(row))); - } - } - - success.accept(messages); - }); - - } - - @Deprecated public ArrayList getMessagesFromUser(String username, String serverName, int max) { ArrayList messages = new ArrayList<>(); - MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE user_id = ? AND server_id = ? ORDER BY date_sent DESC LIMIT ?", username, serverName, max).blocking();; + MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE user_id = ? AND guild_id = ? ORDER BY date_sent DESC LIMIT ?", username, serverName, max).blocking(); if (table.getNbRows() > 0) { for (int row = 0; row < max; row++) { messages.add(new MMessage(table.getRowModel(row))); @@ -82,9 +66,9 @@ public class DBMessage extends AbstractController { } public String getMessageString(String messageId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT message FROM log_message WHERE message_id = ?", messageId).blocking(); + MTableModel table = database.prepareAndExecuteAsync("SELECT message FROM log_message WHERE message_id = ?", messageId).blocking(); - return (String) table.getRowModel(0).getItem(0); + return (String) table.getRowModel(0).getItem(0); } diff --git a/src/main/java/netneutrality/db/controllers/DBSettings.java b/src/main/java/netneutrality/db/controllers/DBSettings.java index a8e1fe9..0e7c81d 100644 --- a/src/main/java/netneutrality/db/controllers/DBSettings.java +++ b/src/main/java/netneutrality/db/controllers/DBSettings.java @@ -8,19 +8,6 @@ import netneutrality.db.models.MTableModel; public class DBSettings extends AbstractController { - public void getSettingsByKey(String key, Consumer success) { - - database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).async(table -> { - Object value = null; - - if (table.getNbRows() == 1) { - value = table.getRowModel(0).getItem(0); - } - - success.accept(value); - }); - } - @Deprecated public String getSettingsByKey(String key) { diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java index 1c4aaf1..dc9dea1 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -61,7 +61,7 @@ public class OGuildSetting extends AbstractEntity { for (int i = 0; i < columns.size(); i++) { if (i == 0) continue; - String key = columns.get(i).replace('_', '.'); + String key = columns.get(i).toUpperCase(); String value = (row.getItem(i) == null ? "" : row.getItem(i).toString()); settings.put(key, value); diff --git a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java b/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java new file mode 100644 index 0000000..338977e --- /dev/null +++ b/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java @@ -0,0 +1,37 @@ +package netneutrality.handler.hooks.voice;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +public class VoiceEventHandler extends ListenerAdapter { + + @Override + public void onGuildVoiceJoin(@NotNull GuildVoiceJoinEvent event) { + super.onGuildVoiceJoin(event); + } + + @Override + public void onGuildVoiceMove(@NotNull GuildVoiceMoveEvent event) { + super.onGuildVoiceMove(event); + } + + @Override + public void onGuildVoiceLeave(@NotNull GuildVoiceLeaveEvent event) { + super.onGuildVoiceLeave(event); + } +} diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 8a2a5b5..5aa8106 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -6,6 +6,7 @@ package netneutrality.http.server;/* */ import com.sun.net.httpserver.HttpExchange; +import net.dv8tion.jda.api.entities.Guild; import netneutrality.GuildManager; import netneutrality.MusicBot; import netneutrality.http.WebModule; @@ -63,9 +64,16 @@ public class ActionHandler extends AbstractHandler { if (path.startsWith("/actions/settings/reload/")) { TreeMap json = new TreeMap<>(); String[] args = exchange.getRequestURI().toString().split("/"); - String guild = args[args.length - 1]; + String guildId = args[args.length - 1]; - json.put("status", String.valueOf(GuildManager.reloadSettingsForGuild(MusicBot.getJDA().getGuildById(guild)))); + Guild guild = MusicBot.getJDA().getGuildById(guildId); + boolean ok; + if (guild == null) + ok = GuildManager.reloadSettingsForGuild(guildId); + else + ok = GuildManager.reloadSettingsForGuild(guild); + + json.put("status", String.valueOf(ok)); sendJsonResponse(exchange, WebModule.createJson(json)); return; diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java deleted file mode 100644 index de6456d..0000000 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -package netneutrality.music; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; -import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; -import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.handler.LogHandler; -import netneutrality.utils.MessageFunction; - -public class LoadResultHandler implements AudioLoadResultHandler { - - private final TextChannel channel; - private final Member user; - private final TrackScheduler scheduler; - private final String identifier; - private final boolean silent; - - public LoadResultHandler(String identifier, TextChannel channel, Member user, TrackScheduler scheduler, boolean silent) { - if (user == null) - silent = true; - - this.identifier = identifier; - this.channel = channel; - this.user = user; - this.scheduler = scheduler; - this.silent = silent; - - - } - - @Override - public void trackLoaded(AudioTrack audioTrack) { - if (!silent) { - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, user, identifier)).queue(); - } - - scheduler.queue(audioTrack, user); - } - - @Override - public void playlistLoaded(AudioPlaylist audioPlaylist) { - - if (identifier.startsWith("ytsearch:")) { - AudioTrack track = audioPlaylist.getTracks().get(0); - - if (!silent) - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); - - scheduler.queue(track, user); - } else { - if (!silent) - channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); - for (AudioTrack track : audioPlaylist.getTracks()) { - scheduler.queue(track, user); - } - } - } - - @Override - public void noMatches() { - channel.sendMessage("No matches found").queue(); - } - - @Override - public void loadFailed(FriendlyException e) { - channel.sendMessage(e.getMessage()).queue(); - LogHandler.log(e); - } -} diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 368cfd7..486ee30 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -7,11 +7,14 @@ package netneutrality.music; * https://discord.gg/CdFcyQ */ +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.source.youtube.YoutubeHttpContextFilter; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -20,7 +23,9 @@ import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.ThreadManager; import netneutrality.command.CommandContext; import netneutrality.exceptions.CommandErrorException; +import netneutrality.handler.LogHandler; import netneutrality.thread.MusicPlayerAutoDisconnectThread; +import netneutrality.utils.MessageFunction; import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -96,6 +101,10 @@ public class MusicManager { public Member getRequesterOfCurrentTrack() { TrackScheduler.TrackInfo info = scheduler.getQueue().peek(); + + if (info == null) + return null; + return info.getRequester(); } @@ -148,11 +157,55 @@ public class MusicManager { } String identifier = SourceFinder.getIdentifier(url); - logger.debug(identifier); scheduler.setTextChannel(channel); if (identifier != null) { - playerManager.loadItem(identifier, new LoadResultHandler(identifier, channel, member, scheduler, silent)); + playerManager.loadItem(identifier, new AudioLoadResultHandler() { + + @Override + public void trackLoaded(AudioTrack audioTrack) { + logger.debug("Starting track on guild {}: {}", guild.getId(), identifier); + + if (!silent) { + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)).queue(); + } + + scheduler.queue(audioTrack, member); + } + + @Override + public void playlistLoaded(AudioPlaylist audioPlaylist) { + if (identifier.startsWith("ytsearch:")) { + AudioTrack track = audioPlaylist.getTracks().get(0); + logger.debug("Starting track on guild {}: {}", guild.getId(), identifier); + + if (!silent) + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); + + scheduler.queue(track, member); + } else { + logger.debug("Starting playlist on guild {}: {}", guild.getId(), identifier); + + if (!silent) + channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)).queue(); + for (AudioTrack track : audioPlaylist.getTracks()) { + scheduler.queue(track, member); + } + } + } + + @Override + public void noMatches() { + context.reply("No matches found"); + } + + @Override + public void loadFailed(FriendlyException e) { + context.reply("Failed to load track: " + e.getMessage()); + LogHandler.log(e); + } + + }); } else { throw new CommandErrorException("No source found to play the given url", context, null); } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index ce17c4b..a780531 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -137,6 +137,8 @@ public class TrackScheduler extends AudioEventAdapter { TrackInfo current = queue.peek(); if (current != null) { player.startTrack(current.getTrack(), false); + } else { + player.stopTrack(); } } diff --git a/src/main/java/netneutrality/thread/ShutdownThread.java b/src/main/java/netneutrality/thread/ShutdownThread.java index 34b92ba..34e1e1a 100644 --- a/src/main/java/netneutrality/thread/ShutdownThread.java +++ b/src/main/java/netneutrality/thread/ShutdownThread.java @@ -20,9 +20,9 @@ public class ShutdownThread implements Runnable { Configurator.shutdown((LoggerContext) LogManager.getContext()); } - MusicBot.shutdown(); - if (!UnsafeShutdown.SAFE) { - //UnsafeShutdown.saveState(); + if (MusicBot.getJDA() != null) { + MusicBot.shutdown(); } + } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 18d13ea..34881f4 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -64,6 +64,7 @@ public class MessageFunction { public static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager, Member user) { AudioTrack current = manager.getCurrentlyPlaying(); + Member requester = (manager.getRequesterOfCurrentTrack() == null ? user : manager.getRequesterOfCurrentTrack()); EmbedBuilder message = new EmbedBuilder(); message.setAuthor("Link to track", String.format("https://youtu.be/%s", current.getIdentifier())); @@ -73,7 +74,7 @@ public class MessageFunction { message.addField("Track title: ", current.getInfo().title, false); message.addField("Uploaded by: ", current.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); - message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setFooter("Requested by " + requester.getEffectiveName(), requester.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); @@ -133,7 +134,19 @@ public class MessageFunction { return message.build(); } - public static ArrayList buildHelpMessage(HashMap commands, HashMap alias, boolean admin) { + public static MessageEmbed buildHelpMessage(AbstractCommand command) { + EmbedBuilder message = new EmbedBuilder(); + message.setTitle(":information_source: Help for command " + command.getCommandName()); + message.setColor(Color.BLUE); + message.addField("Command", command.getCommandName(), false); + message.addField("Description", command.getDescription(), false); + message.addField("Aliases", ((command.getAlias() == null || command.getAlias().length == 0) ? "None": Arrays.toString(command.getAlias()).replaceAll("[\\[\\]]", "")), false); + message.addField("Usage", (command.getUsage() == null ? "No arguments defined" : command.getUsage()), false); + + return message.build(); + } + + public static ArrayList buildHelpMessage(HashMap commands, boolean admin) { SortedSet keys = new TreeSet<>(commands.keySet()); HashMap help = new HashMap<>(); @@ -143,7 +156,6 @@ public class MessageFunction { if (command.getType() == null) continue; - String usage = "(no arguments required)"; String description = "No description yet"; StringBuilder availAlias = new StringBuilder(); @@ -151,9 +163,6 @@ public class MessageFunction { if (command.getType() == CommandType.ADMINISTRATION && !admin) continue; - if (command.getUsage() != null) - usage = command.getUsage(); - if (command.getDescription() != null) description = command.getDescription(); @@ -178,10 +187,10 @@ public class MessageFunction { if (message.isEmpty()) { message.setTitle(command.getType().getDescription() + " commands for NetNeutrality"); - message.setColor(Color.GREEN); + message.setColor(Color.BLUE); } - message.addField(String.format("%s%s %s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommandName(), availAlias, usage), description, false); + message.addField(String.format("%s%s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommandName(), availAlias), description, false); } } @@ -209,7 +218,7 @@ public class MessageFunction { public static void checkBlacklist(Guild guild, Message message, TextChannel channel) { - ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guild.getId(), mBlacklists -> { + ArrayList mBlacklists = ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guild.getId()); if (!mBlacklists.isEmpty()) { boolean found = false; @@ -225,7 +234,6 @@ public class MessageFunction { channel.sendMessage("Not in my christian server").queue(); } } - }); } From 496d6cc362ab436396b64b91ab46c733a6664de5 Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 18 Feb 2022 17:29:42 -0500 Subject: [PATCH 065/155] Small refactor of music perm --- src/main/java/netneutrality/command/AbstractMusicCommand.java | 4 ++++ src/main/java/netneutrality/command/bot/ConfigureCommand.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 8ea1990..8e585df 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import netneutrality.GuildManager; +import netneutrality.utils.UserFunction; import java.util.List; @@ -36,6 +37,9 @@ public abstract class AbstractMusicCommand extends AbstractCommand { can = member.getRoles().contains(neededRole); } + if (UserFunction.isAdmin(member)) + can = true; + return can; } } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 104f522..826f17a 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -68,7 +68,7 @@ public class ConfigureCommand extends AbstractCommand { role = context.getGuild().getRoleById(roleDb); } - context.reply("Current role needed to use music commands (default is anyone): %s", (role == null ? "Everyone" : role.getName())); + context.reply("Current role needed to use music commands (default is everyone): %s", (role == null ? "Everyone" : role.getAsMention())); } if (args.length == 2) { From 8638b7525854d049e0fb6afe62b1c751dbb00fda Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 18 Feb 2022 17:33:29 -0500 Subject: [PATCH 066/155] oopsy --- .../java/netneutrality/command/bot/ConfigureCommand.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 826f17a..27ef02e 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -56,13 +56,14 @@ public class ConfigureCommand extends AbstractCommand { public void execute(CommandContext context) { String[] args = context.getArgumentsAsArray(); MysqlDatabase database = DBController.get(); + GuildManager guildManager = GuildManager.getManager(context.getGuild()); if (args.length > 0) { if (context.getArg(0).equals("musicrole")) { if (args.length == 1) { - String roleDb = GuildManager.getManager(context.getGuild()).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + String roleDb = guildManager.getSetting(GuildManager.GuildSetting.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -78,12 +79,14 @@ public class ConfigureCommand extends AbstractCommand { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { database.prepareAndExecuteAsync("UPDATE guild_settings SET music_role = ? WHERE guild_id = ?", role.getId(), context.getGuild().getId()).blocking(); + guildManager.reloadSettings(); context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } if (context.getArg(1).equals("reset")) { database.prepareAndExecuteAsync("UPDATE guild_settings SET music_role = null WHERE guild_id = ?", context.getGuild().getId()).blocking(); + guildManager.reloadSettings(); context.reply("Successful reset of the role"); } } From e0767ed31a16d0f0560ab8e71abe65d5e6a342f2 Mon Sep 17 00:00:00 2001 From: anthorob Date: Mon, 21 Feb 2022 01:29:08 -0500 Subject: [PATCH 067/155] Fix SQL query --- src/main/java/netneutrality/GuildManager.java | 5 ++++- src/main/java/netneutrality/db/controllers/DBGuild.java | 4 ++-- src/main/java/netneutrality/handler/LogHandler.java | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 7e898a1..16c075d 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -12,6 +12,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.db.DBController; import netneutrality.db.controllers.DBGuild; +import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OGuild; import netneutrality.handler.ratelimiter.IMessageRateLimiter; import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; @@ -130,7 +131,9 @@ public class GuildManager { } public void checkAndLogMessage(Message message, Member member, TextChannel channel) { - //((DBMessage) DBController.get("message")).log(guild, channel, member, message); + if (guildEntity.isLogging()) { + ((DBMessage) DBController.get("message")).log(guild, channel, member, message); + } } public void checkBlacklist(Message message, Member member, TextChannel channel) { diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java index 7dbc6a6..b954a75 100644 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -12,13 +12,13 @@ public class DBGuild extends AbstractController { public void insertGuildInDB(Guild g) { if (!database.exists("guilds", "guild_id", g.getId())) { - database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), "0", null).blocking(); + database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?, ?)", g.getId(), "0", null, null).blocking(); } } public void removeGuildInDB(Guild g) { if (database.exists("guilds", "guild_id", g.getId())) { - database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?)", g.getId(), "0", null).blocking(); + database.prepareAndExecuteAsync("DELETE FROM guilds WHERE guild_id = ?", g.getId()).blocking(); } } diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index 2484813..a4ecec4 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -6,6 +6,7 @@ package netneutrality.handler; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.GuildManager; import netneutrality.MusicBot; import netneutrality.command.CommandContext; @@ -69,6 +70,7 @@ public class LogHandler { .getTextChannels() .stream() .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .filter(TextChannel::canTalk) .forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, error)).queue()); } } From 3b7d8bc6b9f64796d986fdb0a4c0007cb871e9d3 Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 27 Feb 2022 14:17:24 -0500 Subject: [PATCH 068/155] Add command usage to commands, add configurable base volume, improve music player to be thread-safe, rework delete queue command --- sql/add_volume_field_to_settings_table.sql | 2 + src/main/java/netneutrality/GuildManager.java | 29 +++---- .../command/AbstractMusicCommand.java | 4 +- .../netneutrality/command/CommandContext.java | 17 ++-- .../netneutrality/command/CommandManager.java | 4 +- .../netneutrality/command/CommandUsage.java | 29 +++++-- .../java/netneutrality/command/ICommand.java | 5 +- .../command/basic/HelpCommand.java | 8 +- .../command/basic/PingCommand.java | 4 +- .../command/bot/ConfigureCommand.java | 34 +++++++- .../command/crypto/BitcoinPriceCommand.java | 9 +- .../command/crypto/CryptoPriceCommand.java | 10 ++- .../command/crypto/EthereumPriceCommand.java | 9 +- .../command/crypto/LitecoinPriceCommand.java | 9 +- .../netneutrality/command/custom/.gitignore | 1 + .../command/message/BlacklistCommand.java | 15 ++-- .../command/message/PruneCommand.java | 7 +- .../command/music/BitconnectCommand.java | 3 +- .../music/CurrentlyPlayingCommand.java | 7 +- .../command/music/DeleteQueueCommand.java | 56 +++++++++--- .../command/music/JoinCommand.java | 4 +- .../command/music/LeaveCommand.java | 3 +- .../command/music/PlayCommand.java | 10 ++- .../command/music/SkipCommand.java | 6 +- .../command/music/StopCommand.java | 12 +-- .../command/music/ViewQueueCommand.java | 5 +- .../command/music/VolumeCommand.java | 5 +- .../command/music/VoteSkipCommand.java | 3 +- .../command/specific/DatabaseCommand.java | 7 +- .../command/specific/EvalMethod.java | 87 ------------------- .../command/specific/LoggingCommand.java | 3 +- .../command/specific/SellyCommand.java | 86 ------------------ .../command/specific/TestCommand.java | 55 ------------ .../db/controllers/DBSettings.java | 28 ------ .../db/entities/OGuildSetting.java | 15 ++-- .../netneutrality/db/models/MBlacklist.java | 35 +++----- .../http/server/ActionHandler.java | 2 +- .../netneutrality/music/MusicManager.java | 70 ++++++++++----- .../netneutrality/music/SourceFinder.java | 13 ++- .../netneutrality/music/TrackScheduler.java | 68 +++++++++------ .../MusicPlayerAutoDisconnectThread.java | 2 +- .../netneutrality/utils/MessageFunction.java | 15 +++- .../netneutrality/utils/YoutubeClass.java | 35 -------- 43 files changed, 341 insertions(+), 490 deletions(-) create mode 100644 sql/add_volume_field_to_settings_table.sql create mode 100644 src/main/java/netneutrality/command/custom/.gitignore delete mode 100644 src/main/java/netneutrality/command/specific/EvalMethod.java delete mode 100644 src/main/java/netneutrality/command/specific/SellyCommand.java delete mode 100644 src/main/java/netneutrality/command/specific/TestCommand.java delete mode 100644 src/main/java/netneutrality/db/controllers/DBSettings.java delete mode 100644 src/main/java/netneutrality/utils/YoutubeClass.java diff --git a/sql/add_volume_field_to_settings_table.sql b/sql/add_volume_field_to_settings_table.sql new file mode 100644 index 0000000..a5b018b --- /dev/null +++ b/sql/add_volume_field_to_settings_table.sql @@ -0,0 +1,2 @@ +ALTER TABLE `guild_settings` ADD `music_volume` INT NOT NULL DEFAULT '30' AFTER `music_channel`; + diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 16c075d..62bae03 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -28,31 +28,24 @@ public class GuildManager { public enum GuildSetting { MUSIC_ROLE("MUSIC_ROLE", ""), MUSIC_CHANNEL("MUSIC_CHANNEL", ""), + MUSIC_VOLUME("MUSIC_VOLUME", 30), BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); - private final String setting; - private final String defaultValue; + private final String name; + private final Object defaultValue; - GuildSetting(String setting, String defaultValue) { - this.setting = setting; + GuildSetting(String name, Object defaultValue) { + this.name = name; this.defaultValue = defaultValue; } - public String getSetting() { - return setting; + public String getName() { + return name; } - public String getDefaultValue() { + public Object getDefaultValue() { return defaultValue; } - - @Override - public String toString() { - if (setting == null) - return defaultValue; - - return setting; - } } public static final Logger logger = LoggerFactory.getLogger(GuildManager.class); @@ -87,8 +80,8 @@ public class GuildManager { return managers.getOrDefault(guildId, null); } - public String getSetting(GuildSetting key) { - return guildEntity.getSettings().getSettingByKey(key.toString()); + public Object getSetting(GuildSetting key) { + return guildEntity.getSettings().getSettingByKey(key); } public boolean isLoggingEnabled() { @@ -99,7 +92,7 @@ public class GuildManager { return guildEntity.isDebug(); } - public Map getSettings() { + public Map getSettings() { return guildEntity.getSettings().getSettings(); } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 8e585df..66c4b99 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -12,8 +12,6 @@ import net.dv8tion.jda.api.entities.Role; import netneutrality.GuildManager; import netneutrality.utils.UserFunction; -import java.util.List; - public abstract class AbstractMusicCommand extends AbstractCommand { @Override @@ -28,7 +26,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + String roleDb = (String) GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); boolean can = true; //System.out.println(roleDb); diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java index 51e19b3..e52b711 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -17,7 +17,6 @@ import netneutrality.handler.LogHandler; import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; -import java.util.Arrays; import java.util.Collection; import java.util.concurrent.ExecutorService; @@ -105,10 +104,12 @@ public class CommandContext { return command; } + public void reply(CommandUsage usage) { + reply(new MessageBuilder(usage.toString()).build()); + } + public void reply(String msg) { - if (channel != null) { - channel.sendMessage(msg).queue(); - } + reply(new MessageBuilder(msg).build()); } public void reply(String format, Object... arguments) { @@ -116,25 +117,25 @@ public class CommandContext { } public void reply(Message msg) { - if (channel != null) { + if (channel != null && channel.canTalk()) { channel.sendMessage(msg).queue(); } } public void reply(MessageEmbed embed, MessageEmbed... embeds) { - if (channel != null) { + if (channel != null && channel.canTalk()) { channel.sendMessageEmbeds(embed, embeds).queue(); } } public void reply(Collection embeds) { - if (channel != null) { + if (channel != null && channel.canTalk()) { channel.sendMessageEmbeds(embeds).queue(); } } public void replyPrivate(String msg) { - replyPrivate(new MessageBuilder().append(msg).build()); + replyPrivate(new MessageBuilder(msg).build()); } public void replyPrivate(Message msg) { diff --git a/src/main/java/netneutrality/command/CommandManager.java b/src/main/java/netneutrality/command/CommandManager.java index faf4ddc..f0dfb74 100644 --- a/src/main/java/netneutrality/command/CommandManager.java +++ b/src/main/java/netneutrality/command/CommandManager.java @@ -19,8 +19,8 @@ import java.util.Set; public class CommandManager { private final static Logger logger = LoggerFactory.getLogger(CommandManager.class); - public static HashMap commands = new HashMap<>(); - public static HashMap commandsAlias = new HashMap<>(); + public static final HashMap commands = new HashMap<>(); + public static final HashMap commandsAlias = new HashMap<>(); public static void init() { initCommands(); diff --git a/src/main/java/netneutrality/command/CommandUsage.java b/src/main/java/netneutrality/command/CommandUsage.java index db48cc8..b5b82dc 100644 --- a/src/main/java/netneutrality/command/CommandUsage.java +++ b/src/main/java/netneutrality/command/CommandUsage.java @@ -1,4 +1,5 @@ -package netneutrality.command;/* +package netneutrality.command; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -46,9 +47,11 @@ public class CommandUsage { } } + private final AbstractCommand command; private final Set args = new HashSet<>(); - public CommandUsage(Argument... arguments) { + public CommandUsage(AbstractCommand command, Argument... arguments) { + this.command = command; Collections.addAll(args, arguments); } @@ -57,19 +60,33 @@ public class CommandUsage { return this; } - public static CommandUsage create(Argument... arguments) { - return new CommandUsage(arguments); + public static CommandUsage create(AbstractCommand command, Argument... arguments) { + return new CommandUsage(command, arguments); } + public AbstractCommand getCommand() { + return command; + } + + public int getRequiredArguments() { + return args.size(); + } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Available arguments: ").append(args.size()).append("\n"); + sb.append(command.getCommandName()).append(" "); for (Argument arg : args) { sb.append("<"); - if (arg.getType() == Argument.Type.OPTIONAL) - sb.append("Optional argument: ").append(arg.getDescription()); + if (arg.getType() == Argument.Type.OPTIONAL) { + sb.append("optional: "); + + if (arg.getValues() != null || arg.getValues().length != 0) + sb.append(Arrays.toString(arg.getValues())).append(": "); + + sb.append(arg.getDescription()); + } if (arg.getType() == Argument.Type.REQUIRED) { sb.append("required: ").append(Arrays.toString(arg.getValues())); diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index caae58b..9a35a21 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -1,4 +1,5 @@ -package netneutrality.command;/* +package netneutrality.command; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -34,7 +35,7 @@ public interface ICommand { */ String[] getAlias(); - String getUsage(); + CommandUsage getUsage(); String getDescription(); diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index b2bab1e..f97db14 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -37,8 +37,10 @@ public class HelpCommand extends AbstractCommand { } @Override - public String getUsage() { - return null; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"command"}, "Name of command to get help with") + ); } @Override @@ -70,7 +72,7 @@ public class HelpCommand extends AbstractCommand { context.replyPrivate("Command [" + c.getCommandName() + "] requires admin privileges"); } - System.out.println(CommandUsage.create(new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"get", "add"}, ""))); + System.out.println(CommandUsage.create(c, new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"get", "add"}, ""))); MessageEmbed help = MessageFunction.buildHelpMessage(c); context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index be1ecd8..b70afde 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -6,10 +6,10 @@ package netneutrality.command.basic; * https://discord.gg/CdFcyQ */ -import netneutrality.MusicBot; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; public class PingCommand extends AbstractCommand { @@ -34,7 +34,7 @@ public class PingCommand extends AbstractCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 27ef02e..a5abe27 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -11,8 +11,11 @@ import netneutrality.GuildManager; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.db.DBController; import netneutrality.db.MysqlDatabase; +import netneutrality.exceptions.CommandErrorException; +import netneutrality.music.MusicManager; import java.util.List; @@ -38,8 +41,10 @@ public class ConfigureCommand extends AbstractCommand { } @Override - public String getUsage() { - return null; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"musicrole", "musicvolume"}, "") + ); } @Override @@ -63,7 +68,7 @@ public class ConfigureCommand extends AbstractCommand { if (context.getArg(0).equals("musicrole")) { if (args.length == 1) { - String roleDb = guildManager.getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + String roleDb = (String) guildManager.getSetting(GuildManager.GuildSetting.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -92,7 +97,30 @@ public class ConfigureCommand extends AbstractCommand { } } + if (context.getArg(0).equals("musicvolume")) { + if (args.length == 1) { + int volume = (int) guildManager.getSetting(GuildManager.GuildSetting.MUSIC_VOLUME); + context.reply("Default volume for music player: " + volume); + } + + if (args.length == 2) { + try { + int volume = Integer.parseInt(args[1]); + + database.prepareAndExecuteAsync("UPDATE guild_settings SET music_volume = ? WHERE guild_id = ?", volume, context.getGuild().getId()).blocking(); + guildManager.reloadSettings(); + MusicManager.get(context.getGuild()).setVolume(volume); + context.reply("Default volume for music player is now %d", volume); + } catch (NumberFormatException e) { + throw new CommandErrorException("Not a value between 0 and 100", context, e); + } + + + } + } + } else { + context.reply(getUsage()); } } } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 7eb25cd..87b57e9 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.crypto; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.http.WebModule; @@ -44,8 +45,10 @@ public class BitcoinPriceCommand extends AbstractCommand { } @Override - public String getUsage() { - return null; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") + ); } @Override @@ -74,7 +77,7 @@ public class BitcoinPriceCommand extends AbstractCommand { String finalCurrency = currency; context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price = "0"; + String price; Locale usa = new Locale("en", "US"); NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); dollarFormat.setMaximumFractionDigits(24); diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 84ca8af..96dd62f 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.crypto; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.http.WebModule; @@ -43,8 +44,11 @@ public class CryptoPriceCommand extends AbstractCommand { } @Override - public String getUsage() { - return " "; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"crypto"}, "Symbol of crypto"), + new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") + ); } @Override @@ -76,7 +80,7 @@ public class CryptoPriceCommand extends AbstractCommand { String crypto = args[0].toUpperCase(); String finalCurrency = currency; context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price = "0"; + String price; Locale usa = new Locale("en", "US"); NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); dollarFormat.setMaximumFractionDigits(24); diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index dacf593..625005a 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.crypto; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.http.WebModule; @@ -44,8 +45,10 @@ public class EthereumPriceCommand extends AbstractCommand { } @Override - public String getUsage() { - return null; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") + ); } @Override @@ -74,7 +77,7 @@ public class EthereumPriceCommand extends AbstractCommand { String finalCurrency = currency; context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price = "0"; + String price; Locale usa = new Locale("en", "US"); NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); dollarFormat.setMaximumFractionDigits(24); diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 2d5e70b..954a75c 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.crypto; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.http.WebModule; @@ -44,8 +45,10 @@ public class LitecoinPriceCommand extends AbstractCommand { } @Override - public String getUsage() { - return null; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") + ); } @Override @@ -74,7 +77,7 @@ public class LitecoinPriceCommand extends AbstractCommand { String finalCurrency = currency; context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price = "0"; + String price; Locale usa = new Locale("en", "US"); NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); dollarFormat.setMaximumFractionDigits(24); diff --git a/src/main/java/netneutrality/command/custom/.gitignore b/src/main/java/netneutrality/command/custom/.gitignore new file mode 100644 index 0000000..2a9bbbd --- /dev/null +++ b/src/main/java/netneutrality/command/custom/.gitignore @@ -0,0 +1 @@ +*.java \ No newline at end of file diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 986ae79..fd98379 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.message; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; import netneutrality.db.models.MBlacklist; @@ -39,7 +40,7 @@ public class BlacklistCommand extends AbstractCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } @@ -94,9 +95,9 @@ public class BlacklistCommand extends AbstractCommand { case "remove": if (controller.delete(word, context.getGuild().getId())) { - context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + context.reply("Removed the word \"" + word + "\" from the blacklist."); } else { - context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + context.reply("Error removing \"" + word + "\" from the blacklist"); } break; @@ -104,9 +105,9 @@ public class BlacklistCommand extends AbstractCommand { case "disable": if (controller.disable(word, context.getGuild().getId())) { - context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + context.reply("Removed the word \"" + word + "\" from the blacklist."); } else { - context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + context.reply("Error removing \"" + word + "\" from the blacklist"); } break; @@ -114,9 +115,9 @@ public class BlacklistCommand extends AbstractCommand { case "enable": if (controller.enable(word, context.getGuild().getId())) { - context.getChannel().sendMessage("Removed the word \"" + word + "\" from the blacklist.").queue(); + context.reply("Removed the word \"" + word + "\" from the blacklist."); } else { - context.getChannel().sendMessage("Error removing \"" + word + "\" from the blacklist").queue(); + context.reply("Error removing \"" + word + "\" from the blacklist"); } break; diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index dda3d85..646bf1d 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.message; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.utils.ChannelFunction; public class PruneCommand extends AbstractCommand { @@ -34,8 +35,10 @@ public class PruneCommand extends AbstractCommand { } @Override - public String getUsage() { - return ""; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"number"}, "Max 2499") + ); } @Override diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 6701413..c98a1d4 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -10,6 +10,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; public class BitconnectCommand extends AbstractMusicCommand { @@ -30,7 +31,7 @@ public class BitconnectCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index 0af4460..abbc959 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -10,6 +10,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; @@ -32,7 +33,7 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } @@ -48,9 +49,9 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { MusicUtils.checkIfConnected(player, context); if (player.getCurrentlyPlaying() != null) { - context.getChannel().sendMessageEmbeds(MessageFunction.buildCurrentlyPlayingMessage(player, member)).queue(); + context.reply(MessageFunction.buildCurrentlyPlayingMessage(player, member)); } else { - context.getChannel().sendMessage("Player is not playing any tracks right now").queue(); + context.reply("Player is not playing any tracks right now"); } } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index b340dad..0cf91d6 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -9,7 +9,10 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; +import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; +import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; public class DeleteQueueCommand extends AbstractMusicCommand { @@ -30,17 +33,19 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public String[] getAlias() { - return new String[]{"delq"}; + return new String[] {"delq", "delqueue"}; } @Override - public String getUsage() { - return null; + public CommandUsage getUsage() { + return CommandUsage.create(this, + new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"track #", "all"}, "") + ); } @Override public String getDescription() { - return "Deletes the music queue"; + return "Empties the music queue"; } @Override @@ -48,13 +53,44 @@ public class DeleteQueueCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - int queueSize = player.getScheduler().getQueue().size(); - if (queueSize > 0) { - player.getScheduler().getQueue().clear(); - context.getChannel().sendMessage("Removed " + queueSize + (queueSize > 1 ? " tracks" : "track") + " from the queue").queue(); - } else { - context.getChannel().sendMessage("Queue is empty!").queue(); + if (context.getArgumentsAsArray().length == 0) { + context.reply("Select the track you want to delete from the queue (track# or all)"); + context.reply(MessageFunction.buildViewQueueMessage(player, context.getGuildUser(), true)); } + if (context.getArgumentsAsArray().length > 0) { + + int queueSize = player.getScheduler().getQueue().size(); + if (context.getArg(0).equals("all")) { + + if (queueSize > 0) { + player.leave(); + player.getScheduler().getQueue().clear(); + context.reply("Removed " + queueSize-- + (queueSize > 1 ? " tracks" : "track") + " from the queue"); + } else { + context.reply("Queue is empty!"); + } + } else { + + try { + int num = Integer.parseInt(context.getArg(0)); + + if (num > 0) { + player.removeFromQueue(num); + context.reply("Removing track #%d from the queue", num); + } else { + context.reply("Number out of range"); + } + + } catch (NumberFormatException e) { + throw new CommandErrorException("Please enter a number", context, e); + } + } + + + + } + + } } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 39f8832..b6cd31a 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -10,10 +10,10 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; public class JoinCommand extends AbstractMusicCommand { @@ -33,7 +33,7 @@ public class JoinCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 65a149b..d2811ce 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -34,7 +35,7 @@ public class LeaveCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 6f6948e..444e9d4 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; public class PlayCommand extends AbstractMusicCommand { @@ -29,8 +30,11 @@ public class PlayCommand extends AbstractMusicCommand { } @Override - public String getUsage() { - return ""; + public CommandUsage getUsage() { + return CommandUsage.create( + this, + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"url"}, "Youtube/Soundcloud link or search string") + ); } @Override @@ -47,7 +51,7 @@ public class PlayCommand extends AbstractMusicCommand { player.play(context.getMessageText(), context, false, false); } else { - context.reply("No url provided"); + context.reply(getUsage()); } } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 7a092e9..5f3960d 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -30,8 +31,8 @@ public class SkipCommand extends AbstractMusicCommand { } @Override - public String getUsage() { - return ""; + public CommandUsage getUsage() { + return CommandUsage.create(this, new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[]{"number"}, "Number of tracks to skip")); } @Override @@ -45,6 +46,7 @@ public class SkipCommand extends AbstractMusicCommand { MusicUtils.checkIfConnected(player, context); // Combined fonctionality of vote skip + //TODO: clean ifs if (context.getArgumentsAsArray().length > 0 && UserFunction.isAdmin(context.getGuildUser())) { int skips = Integer.parseInt(context.getArg(0)); player.skip(skips); diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 53747e3..0347855 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -31,13 +32,13 @@ public class StopCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } @Override public String getDescription() { - return "Stop the music player, deleting the queue in the process"; + return "Stop the music player, emptying the queue in the process"; } @Override @@ -45,12 +46,7 @@ public class StopCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - if (UserFunction.isAdmin(context.getGuildUser())) { - player.leave(); - return; - } - - if (context.getGuildUser().getId().equals(player.getRequesterOfCurrentTrack().getId())) { + if (UserFunction.isAdmin(context.getGuildUser()) || context.getGuildUser().getId().equals(player.getRequesterOfCurrentTrack().getId())) { player.leave(); } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 9c51f90..0d65e64 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -10,6 +10,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; @@ -36,7 +37,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } @@ -53,7 +54,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { int queueSize = player.getScheduler().getQueue().size(); if (queueSize > 0) { - context.reply(MessageFunction.buildViewQueueMessage(player, member)); + context.reply(MessageFunction.buildViewQueueMessage(player, member, true)); } else { context.reply("Queue is empty!"); } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 4c2cf75..f2f1d7b 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -36,8 +36,8 @@ public class VolumeCommand extends AbstractMusicCommand { } @Override - public String getUsage() { - return ""; + public CommandUsage getUsage() { + return CommandUsage.create(this, new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"0-100"}, "")); } @Override @@ -53,6 +53,7 @@ public class VolumeCommand extends AbstractMusicCommand { try { int volume = Integer.parseInt(context.getArgumentsAsArray()[0]); player.setVolume(volume); + context.reply("Volume set to %s", volume); } catch (NumberFormatException e) { throw new CommandErrorException("Please enter a value from 0 to 100", context, null); } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index 8e33acd..6d5037e 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -29,7 +30,7 @@ public class VoteSkipCommand extends AbstractMusicCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index e5ac876..f227415 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.User; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; import netneutrality.db.models.MMessage; @@ -44,7 +45,7 @@ public class DatabaseCommand extends AbstractCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } @@ -84,7 +85,7 @@ public class DatabaseCommand extends AbstractCommand { embed.setDescription( "Message from " + message.getSender() + " on the channel " + message.getChannelName()); embed.addField("Message: ", "" + message.getMessage(), false); - context.getChannel().sendMessageEmbeds(embed.build()).queue(); + context.reply(embed.build()); } else { //TODO: cached user lol xd User user = context.getJDA().getUserById(args[1]); @@ -102,7 +103,7 @@ public class DatabaseCommand extends AbstractCommand { } embed.setFooter("Guild : " + context.getGuild().getName(), null); - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessageEmbeds(embed.build()).queue()); + context.replyPrivate(embed.build()); } } diff --git a/src/main/java/netneutrality/command/specific/EvalMethod.java b/src/main/java/netneutrality/command/specific/EvalMethod.java deleted file mode 100644 index d9ba04a..0000000 --- a/src/main/java/netneutrality/command/specific/EvalMethod.java +++ /dev/null @@ -1,87 +0,0 @@ -package netneutrality.command.specific; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.MessageBuilder; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; -import netneutrality.command.CommandType; -import netneutrality.music.MusicManager; -import netneutrality.utils.Settings; - -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; - -public class EvalMethod extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return false; - } - - @Override - public String getCommandName() { - return "evaluate"; - } - - @Override - public String[] getAlias() { - return new String[]{"eval"}; - } - - @Override - public String getUsage() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @Override - public CommandType getType() { - return CommandType.UNLISTED; - } - - @Override - public void execute(CommandContext context) { - - if (context.getDiscordUser().getId().equals(Settings.getInstance().getCreatorId())) { - ScriptEngine se = new ScriptEngineManager().getEngineByName("Nashorn"); - - MessageBuilder message = new MessageBuilder(); - - try { - se.eval("var imports = new JavaImporter(java.io, java.lang, java.util);"); - se.put("jda", context.getJDA()); - se.put("guild", context.getGuild()); - se.put("channel", context.getChannel()); - se.put("member", context.getGuildUser()); - se.put("music", MusicManager.get(context.getGuild())); - - String script = String.format("( function() { with (imports) { return %s } } )();", context.getMessageText()); - - message.append("Evaluated Successfully:"); - message.appendCodeBlock(se.eval(script).toString(), "java"); - context.getChannel().sendMessage(message.build()).queue(); - - } catch (ScriptException e) { - e.printStackTrace(); - context.getChannel().sendMessage(" An exception was thrown:\n```\n" + e.getMessage() + " ```").queue(); - } - - } - } -} diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index 8e53884..06f0edf 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.specific; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandContext; import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; public class LoggingCommand extends AbstractCommand { @@ -33,7 +34,7 @@ public class LoggingCommand extends AbstractCommand { } @Override - public String getUsage() { + public CommandUsage getUsage() { return null; } diff --git a/src/main/java/netneutrality/command/specific/SellyCommand.java b/src/main/java/netneutrality/command/specific/SellyCommand.java deleted file mode 100644 index b538018..0000000 --- a/src/main/java/netneutrality/command/specific/SellyCommand.java +++ /dev/null @@ -1,86 +0,0 @@ -package netneutrality.command.specific; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; -import netneutrality.command.CommandType; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBSettings; -import netneutrality.db.models.MSellyOrder; -import netneutrality.http.Selly; - -import java.util.Map; - -public class SellyCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "selly"; - } - - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public String getUsage() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @Override - public CommandType getType() { - return CommandType.UNLISTED; - } - - @Override - public void execute(CommandContext context) { - //TODO: delete or move to custom command when implemented - String sellyEmail = ((DBSettings) DBController.get("settings")).getSettingsByKey("selly_email"); - String sellyKey = ((DBSettings) DBController.get("settings")).getSettingsByKey(""); - Selly selly = new Selly(sellyEmail, sellyKey); - - Map orders = selly.getOrders(); - - System.out.println(selly.getProducts().toString()); - - if (context.getArgumentsAsArray().length > 1) { - String email = context.getArgumentsAsArray()[0]; - String id = context.getArgumentsAsArray()[1]; - - if (orders.containsKey(id)) { - MSellyOrder order = orders.get(id); - if (email.equals(order.getEmail())) { - if (order.getStatus() == 100) { - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("success").queue()); - } else - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("not completed").queue()); - } else - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("wrong email").queue()); - } else - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("order doesn't exist").queue()); - } else - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessage("usage : $selly ").queue()); - } -} diff --git a/src/main/java/netneutrality/command/specific/TestCommand.java b/src/main/java/netneutrality/command/specific/TestCommand.java deleted file mode 100644 index 2407c6e..0000000 --- a/src/main/java/netneutrality/command/specific/TestCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package netneutrality.command.specific; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; -import netneutrality.command.CommandType; - -public class TestCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return false; - } - - @Override - public String getCommandName() { - return "test"; - } - - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public String getUsage() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @Override - public CommandType getType() { - return CommandType.UNLISTED; - } - - @Override - public void execute(CommandContext context) { - - } -} diff --git a/src/main/java/netneutrality/db/controllers/DBSettings.java b/src/main/java/netneutrality/db/controllers/DBSettings.java deleted file mode 100644 index 0e7c81d..0000000 --- a/src/main/java/netneutrality/db/controllers/DBSettings.java +++ /dev/null @@ -1,28 +0,0 @@ -package netneutrality.db.controllers; - -import java.util.concurrent.ExecutionException; -import java.util.function.Consumer; - -import netneutrality.db.AbstractController; -import netneutrality.db.models.MTableModel; - -public class DBSettings extends AbstractController { - - @Deprecated - public String getSettingsByKey(String key) { - - MTableModel table = database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).blocking(); - - if (table.getNbRows() == 1) { - return table.getRow(0).get(0).toString(); - } - - return null; - } - - @Override - public String getControllerName() { - return "settings"; - } - -} diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java index dc9dea1..1888fc2 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -5,6 +5,7 @@ package netneutrality.db.entities;/* * https://discord.gg/CdFcyQ */ +import netneutrality.GuildManager; import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; @@ -12,7 +13,7 @@ import java.util.*; public class OGuildSetting extends AbstractEntity { private final OGuild guild; - private Map settings; + private Map settings; public OGuildSetting(OGuild OGuild) { super(OGuild.getGuildID()); @@ -24,16 +25,16 @@ public class OGuildSetting extends AbstractEntity { return guild; } - public Map getSettings() { + public Map getSettings() { return settings; } - public String getSettingByKey(String key) { - if (settings.containsKey(key)) { - return settings.get(key); + public Object getSettingByKey(GuildManager.GuildSetting key) { + if (settings.containsKey(key.getName())) { + return settings.get(key.getName()); } - return null; + return key.getDefaultValue(); } @Override @@ -62,7 +63,7 @@ public class OGuildSetting extends AbstractEntity { if (i == 0) continue; String key = columns.get(i).toUpperCase(); - String value = (row.getItem(i) == null ? "" : row.getItem(i).toString()); + Object value = row.getItem(i); settings.put(key, value); } diff --git a/src/main/java/netneutrality/db/models/MBlacklist.java b/src/main/java/netneutrality/db/models/MBlacklist.java index bc5a61a..1457dc4 100644 --- a/src/main/java/netneutrality/db/models/MBlacklist.java +++ b/src/main/java/netneutrality/db/models/MBlacklist.java @@ -1,13 +1,20 @@ package netneutrality.db.models; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import java.util.List; public class MBlacklist { - protected String word = ""; - protected boolean enabled = false; - protected String creatorId= ""; - protected String serverId; + private final String word; + private final boolean enabled; + private final String creatorId; + private final String serverId; public MBlacklist(String word, boolean enabled, String creatorId, String serverId) { this.word = word; @@ -29,34 +36,18 @@ public class MBlacklist { public String getWord() { return word; } - - public void setWord(String word) { - this.word = word; - } - + public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - public String getCreatorId() { return creatorId; } - - public void setCreatorId(String creatorId) { - this.creatorId = creatorId; - } - + public String getServerId() { return serverId; } - - public void setServerId(String serverId) { - this.serverId = serverId; - } @Override public String toString() { diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 5aa8106..57e9188 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -48,7 +48,7 @@ public class ActionHandler extends AbstractHandler { GuildManager manager = GuildManager.getManager(MusicBot.getJDA().getGuildById(guild)); if (manager != null) { - Map settings = manager.getSettings(); + Map settings = manager.getSettings(); JSONObject setting = new JSONObject(settings); json.put("status", "ok"); diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 486ee30..c6ee655 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -20,6 +20,7 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.VoiceChannel; +import netneutrality.GuildManager; import netneutrality.ThreadManager; import netneutrality.command.CommandContext; import netneutrality.exceptions.CommandErrorException; @@ -36,29 +37,31 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class MusicManager { private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); - private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); private final static Map managers = new ConcurrentHashMap<>(); + private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); private final Guild guild; private final AudioPlayer player; + private final AudioPlayerManager playerManager; private final TrackScheduler scheduler; - ScheduledExecutorService autoDisconnectThread; + private ScheduledFuture autoDisconnectThread; private MusicManager(Guild guild) { - this.guild = guild; + this.playerManager = new DefaultAudioPlayerManager(); this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(player); + + AudioSourceManagers.registerRemoteSources(playerManager); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); - player.setVolume(15); - autoDisconnectThread = (ScheduledExecutorService) ThreadManager.getExecutor("music-disconnect", ThreadManager.ExecutorType.SCHEDULED); - autoDisconnectThread.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 120, 120, TimeUnit.SECONDS); + player.setVolume((Integer) GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_VOLUME)); managers.put(guild.getId(), this); } @@ -72,8 +75,6 @@ public class MusicManager { } public static void initPlayerManager() { - AudioSourceManagers.registerRemoteSources(playerManager); - YoutubeHttpContextFilter.setPAPISID(Settings.getInstance().get("BOT_PAPISID", "")); YoutubeHttpContextFilter.setPSID(Settings.getInstance().get("BOT_PSID", "")); } @@ -82,9 +83,13 @@ public class MusicManager { return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); } - public void connect(VoiceChannel vChannel) { + public synchronized void connect(VoiceChannel vChannel) { if (vChannel != null && !isConnectedTo(vChannel)) { guild.getAudioManager().openAudioConnection(vChannel); + guild.getAudioManager().setSelfDeafened(true); + + if (autoDisconnectThread == null) + autoDisconnectThread = executor.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 120, 120, TimeUnit.SECONDS); } else { throw new RuntimeException("Error connecting to voice channel"); } @@ -95,11 +100,11 @@ public class MusicManager { return guild != null && guild.getAudioManager().getConnectedChannel() != null; } - public AudioTrack getCurrentlyPlaying() { + public synchronized AudioTrack getCurrentlyPlaying() { return player.getPlayingTrack(); } - public Member getRequesterOfCurrentTrack() { + public synchronized Member getRequesterOfCurrentTrack() { TrackScheduler.TrackInfo info = scheduler.getQueue().peek(); if (info == null) @@ -112,13 +117,20 @@ public class MusicManager { return guild; } - public void leave() { + public synchronized void leave() { if (isConnected()) { player.stopTrack(); guild.getAudioManager().closeAudioConnection(); } scheduler.resetTopic(); + + if (autoDisconnectThread != null) { + boolean cancel = autoDisconnectThread.cancel(true); + + if (cancel) + autoDisconnectThread = null; + } } public static void disconnectPlayers() { @@ -135,7 +147,7 @@ public class MusicManager { return false; } - public void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { + public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); TextChannel channel = context.getChannel(); @@ -160,11 +172,12 @@ public class MusicManager { scheduler.setTextChannel(channel); if (identifier != null) { - playerManager.loadItem(identifier, new AudioLoadResultHandler() { + + playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { @Override public void trackLoaded(AudioTrack audioTrack) { - logger.debug("Starting track on guild {}: {}", guild.getId(), identifier); + logger.debug("Found results for identifier: {}", identifier); if (!silent) { channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)).queue(); @@ -177,19 +190,22 @@ public class MusicManager { public void playlistLoaded(AudioPlaylist audioPlaylist) { if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); - logger.debug("Starting track on guild {}: {}", guild.getId(), identifier); + logger.debug("Found results for identifier: {}", identifier); if (!silent) channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); scheduler.queue(track, member); } else { - logger.debug("Starting playlist on guild {}: {}", guild.getId(), identifier); + logger.debug("Found results for playlist identifier: {}", identifier); if (!silent) channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)).queue(); + for (AudioTrack track : audioPlaylist.getTracks()) { - scheduler.queue(track, member); + synchronized (scheduler.getQueue()) { + scheduler.queue(track, member); + } } } } @@ -211,7 +227,15 @@ public class MusicManager { } } - public void skip(int nbTrack) { + public synchronized void removeFromQueue(int num) { + if (num == 1) { + skip(1); + } else { + scheduler.removeFromQueue(num); + } + } + + public synchronized void skip(int nbTrack) { if (!scheduler.getQueue().isEmpty()) { if (nbTrack >= scheduler.getQueue().size()) { nbTrack = 1; @@ -223,12 +247,12 @@ public class MusicManager { } } - public void voteSkip(CommandContext context) { + public synchronized void voteSkip(CommandContext context) { Queue queue = scheduler.getQueue(); VoiceChannel voiceChannel = guild.getAudioManager().getConnectedChannel(); TrackScheduler.TrackInfo info = queue.peek(); - if (getCurrentlyPlaying() == null) { + if (getCurrentlyPlaying() == null || voiceChannel == null) { return; } @@ -257,7 +281,7 @@ public class MusicManager { } } - public void setVolume(int volume) { + public synchronized void setVolume(int volume) { player.setVolume(volume); } @@ -265,7 +289,7 @@ public class MusicManager { return scheduler; } - public ArrayList getAllQueuedTrack() { + public synchronized ArrayList getAllQueuedTrack() { ArrayList tracks = new ArrayList<>(); Queue queue = scheduler.getQueue(); diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index 7c45c6a..6e9328c 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -21,16 +21,14 @@ enum SourceEnum { } public class SourceFinder { - private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&\\?]{12,}))?", Pattern.CASE_INSENSITIVE); + private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); - private static Matcher youtubeMatcher; - private static Matcher soundcloudMatcher; private static Matcher BandcampMatcher; private static Matcher vimeoMatcher; public static SourceEnum getSource(String url) { - youtubeMatcher = youtubePattern.matcher(url); - soundcloudMatcher = soundcloudPattern.matcher(url); + Matcher youtubeMatcher = youtubePattern.matcher(url); + Matcher soundcloudMatcher = soundcloudPattern.matcher(url); if (youtubeMatcher.find()) return SourceEnum.Youtube; @@ -45,10 +43,11 @@ public class SourceFinder { } public static String getIdentifier(String url) { - String identifier = switch (getSource(url)) { + String identifier; + + identifier = switch (getSource(url)) { case Youtube, Soundcloud -> url; case YTSearch -> "ytsearch:" + url; - case Nothing -> null; default -> null; }; diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index a780531..e23380a 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -14,13 +14,15 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.LinkedBlockingQueue; public class TrackScheduler extends AudioEventAdapter { - class TrackInfo { + static class TrackInfo { private final AudioTrack track; private final Member member; @@ -56,7 +58,7 @@ public class TrackScheduler extends AudioEventAdapter { } } - private final Object topicLock = new Object(); + private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class); private final AudioPlayer player; private final Queue queue; private TextChannel channel; @@ -67,7 +69,7 @@ public class TrackScheduler extends AudioEventAdapter { this.queue = new LinkedBlockingQueue<>(); } - public void queue(AudioTrack track, Member member) { + public synchronized void queue(AudioTrack track, Member member) { // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. @@ -76,57 +78,52 @@ public class TrackScheduler extends AudioEventAdapter { if (player.getPlayingTrack() == null) { player.startTrack(track, true); } + } - public String getOriginalTopic() { - synchronized (topicLock) { - return originalTopic; - } + public synchronized String getOriginalTopic() { + return originalTopic; } public TextChannel getTextChannel() { return channel; } - public void setTextChannel(TextChannel channel) { + public synchronized void setTextChannel(TextChannel channel) { this.channel = channel; - synchronized (topicLock) { - if (originalTopic == null) { - originalTopic = channel.getTopic(); - } + if (originalTopic == null) { + originalTopic = channel.getTopic(); } } - public void resetTextChannel() { + public synchronized void resetTextChannel() { this.channel = null; } - public Queue getQueue() { + public synchronized Queue getQueue() { return queue; } - public void resetTopic() { - synchronized (topicLock) { - if (channel != null && (originalTopic != null && !originalTopic.equals(""))) { - //channel.getManager().setTopic(topic).queue(); - } - - originalTopic = null; + public synchronized void resetTopic() { + if (channel != null && (originalTopic != null && !originalTopic.isEmpty())) { + //channel.getManager().setTopic(topic).queue(); } + originalTopic = null; } - public void nextTrack(AudioPlayer player) { + public synchronized void nextTrack(AudioPlayer player) { TrackInfo last = queue.poll(); if (queue.peek() != null) { player.startTrack(queue.peek().getTrack(), false); - } + } else + player.stopTrack(); } - public void skipAndPlay(int nb) { + public synchronized void skipAndPlay(int nb) { if (nb == 0) return; @@ -140,7 +137,14 @@ public class TrackScheduler extends AudioEventAdapter { } else { player.stopTrack(); } + } + protected synchronized void removeFromQueue(int index) { + ArrayList newQueue = new ArrayList<>(queue); + newQueue.remove(index - 1); + + queue.clear(); + queue.addAll(newQueue); } @Override @@ -155,6 +159,7 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { + logger.debug("Starting track on guild {}: {}", channel.getGuild().getId(), track.getIdentifier()); // A track started playing //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); } @@ -163,12 +168,21 @@ public class TrackScheduler extends AudioEventAdapter { public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { resetTopic(); - if (endReason.mayStartNext) { + // check if mayStartNext + if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { + //logger.debug("Queue size before next: " + queue.size()); nextTrack(player); - } else { - queue.poll(); + } + if (endReason == AudioTrackEndReason.STOPPED) { + synchronized (queue) { + queue.poll(); + } + } + + //logger.debug("Queue size after next: " + queue.size()); + // endReason == FINISHED: A track finished or died by an exception (mayStartNext = true). // endReason == LOAD_FAILED: Loading of a track failed (mayStartNext = true). // endReason == STOPPED: The player was stopped. diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index 9c19ba3..eebaf7b 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -15,7 +15,7 @@ import java.util.List; public class MusicPlayerAutoDisconnectThread implements Runnable { - MusicManager manager; + final MusicManager manager; public MusicPlayerAutoDisconnectThread(MusicManager musicManager) { manager = musicManager; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 34881f4..6c77edf 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -109,7 +109,7 @@ public class MessageFunction { return message.build(); } - public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user) { + public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user, boolean currentlyPlaying) { ArrayList tracks = manager.getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); @@ -119,7 +119,7 @@ public class MessageFunction { int index = 0; for (AudioTrack track: tracks) { - if (track.getInfo().title.equals(current.getInfo().title)) { + if (track.getInfo().title.equals(current.getInfo().title) && currentlyPlaying) { message.addField("Track #" + ++index + " (Currently playing)", track.getInfo().title, false); } else { message.addField("Track #" + ++index, track.getInfo().title, false); @@ -141,7 +141,7 @@ public class MessageFunction { message.addField("Command", command.getCommandName(), false); message.addField("Description", command.getDescription(), false); message.addField("Aliases", ((command.getAlias() == null || command.getAlias().length == 0) ? "None": Arrays.toString(command.getAlias()).replaceAll("[\\[\\]]", "")), false); - message.addField("Usage", (command.getUsage() == null ? "No arguments defined" : command.getUsage()), false); + message.addField("Usage", (command.getUsage() == null ? "No arguments defined" : command.getUsage().toString()), false); return message.build(); } @@ -208,8 +208,15 @@ public class MessageFunction { message.addField("Caused by command:", context.getCommand().getCommandName(), false); message.addField("Exception:", error.getMessage(), false); if (error.getCause() != null) { - message.addField("Caused by:", error.getCause().getMessage(), false); + String cause; + if (error.getCause().getMessage() != null && !error.getCause().getMessage().isEmpty()) { + cause = error.getCause().getMessage(); + } else { + cause = error.getCause().getClass().getName(); + } + message.addField("Caused by:", cause, false); } + message.setFooter("Requested by " + context.getDiscordUser().getName(), context.getDiscordUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); diff --git a/src/main/java/netneutrality/utils/YoutubeClass.java b/src/main/java/netneutrality/utils/YoutubeClass.java deleted file mode 100644 index 7335fb6..0000000 --- a/src/main/java/netneutrality/utils/YoutubeClass.java +++ /dev/null @@ -1,35 +0,0 @@ -package netneutrality.utils; - -/* - * Copyright (c) anthorob - * - * This file is closed-source. It should not be distributed or copied in any way or form - */ - -import netneutrality.http.WebModule; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class YoutubeClass { - - public static Pattern urlPattern = Pattern.compile("^(?:https?:\\/\\/)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)\\/.*?(?:embed|e|v|watch.*?v=)?\\/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&\\?]{12,}))?", Pattern.CASE_INSENSITIVE); - private final static Pattern youtubeCode = Pattern.compile("^[A-Za-z0-9_-]{11}$"); - - public static String getCodeFromUrl(String url) { - Matcher matcher = urlPattern.matcher(url); - if (matcher.find()) { - if (matcher.group(1) != null) { - return matcher.group(1); - } - } - return ""; - } - - public static String getVideoTitle(String url) { - WebModule youtube = new WebModule(url).request(); - - return youtube.getTextInHtmlTag(""); - } - -} From 26a0fdc25a266157c0c1b3d0ff55776fc51393e8 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 27 Feb 2022 14:19:54 -0500 Subject: [PATCH 069/155] Clean imports --- pom.xml | 6 +++ src/main/java/netneutrality/MusicBot.java | 2 +- .../netneutrality/command/CommandType.java | 3 +- .../command/PermissionManager.java | 3 +- .../netneutrality/command/Visibility.java | 3 +- .../netneutrality/db/AbstractController.java | 7 ++++ .../java/netneutrality/db/DBController.java | 14 ++++--- .../java/netneutrality/db/MysqlConnector.java | 8 +++- .../java/netneutrality/db/MysqlDatabase.java | 23 ++++++----- .../db/controllers/DBBlacklist.java | 9 ++++- .../netneutrality/db/controllers/DBGuild.java | 4 +- .../db/controllers/DBMessage.java | 8 +++- .../db/entities/AbstractEntity.java | 5 ++- .../db/entities/EntityInterface.java | 4 +- .../netneutrality/db/entities/OGuild.java | 4 +- .../db/entities/OPermission.java | 6 +-- .../netneutrality/db/models/MMessage.java | 7 ++++ .../netneutrality/db/models/MRowModel.java | 3 +- .../netneutrality/db/models/MRowsModel.java | 3 +- .../netneutrality/db/models/MSellyOrder.java | 40 +++++++++---------- .../db/models/MSellyProduct.java | 3 +- .../exceptions/CommandErrorException.java | 4 +- .../exceptions/CommandException.java | 6 ++- .../exceptions/CommandExecutionException.java | 4 +- .../exceptions/ExecutorException.java | 4 +- .../netneutrality/handler/LogHandler.java | 1 - .../handler/hooks/message/EditHandler.java | 2 - .../hooks/message/MessageReceivedHandler.java | 1 - .../ratelimiter/MessageRateLimiterImpl.java | 8 ++-- src/main/java/netneutrality/http/Selly.java | 2 +- .../java/netneutrality/http/WebModule.java | 6 --- .../http/server/ActionHandler.java | 7 ++-- .../http/server/GuildHandler.java | 6 --- .../http/server/RootHandler.java | 2 - .../netneutrality/http/server/WebApi.java | 6 +-- 35 files changed, 137 insertions(+), 87 deletions(-) diff --git a/pom.xml b/pom.xml index 0742d6d..2de6182 100644 --- a/pom.xml +++ b/pom.xml @@ -166,6 +166,12 @@ <version>4.13.2</version> </dependency> + <dependency> + <groupId>org.openjdk.nashorn</groupId> + <artifactId>nashorn-core</artifactId> + <version>15.3</version> + </dependency> + </dependencies> diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index e16870c..3de4827 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -38,7 +38,7 @@ public class MusicBot { jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); - new WebApi(); + new WebApi(9000); jda.getPresence().setActivity(Activity.watching("you")); Runtime.getRuntime().addShutdownHook(new BaseThreadFactory("shutdown").newThread(new ShutdownThread())); diff --git a/src/main/java/netneutrality/command/CommandType.java b/src/main/java/netneutrality/command/CommandType.java index 87b57d5..31c2cfe 100644 --- a/src/main/java/netneutrality/command/CommandType.java +++ b/src/main/java/netneutrality/command/CommandType.java @@ -1,4 +1,5 @@ -package netneutrality.command;/* +package netneutrality.command; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/command/PermissionManager.java b/src/main/java/netneutrality/command/PermissionManager.java index d2c799e..43c4983 100644 --- a/src/main/java/netneutrality/command/PermissionManager.java +++ b/src/main/java/netneutrality/command/PermissionManager.java @@ -1,4 +1,5 @@ -package netneutrality.command;/* +package netneutrality.command; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/command/Visibility.java b/src/main/java/netneutrality/command/Visibility.java index 413f4e0..71b7d73 100644 --- a/src/main/java/netneutrality/command/Visibility.java +++ b/src/main/java/netneutrality/command/Visibility.java @@ -3,7 +3,8 @@ package netneutrality.command; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import net.dv8tion.jda.api.entities.MessageChannel; diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/netneutrality/db/AbstractController.java index e1d33d8..d2c2f47 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/netneutrality/db/AbstractController.java @@ -1,5 +1,12 @@ package netneutrality.db; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + public abstract class AbstractController { protected MysqlDatabase database; diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 5168658..a2eadb9 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -1,5 +1,12 @@ package netneutrality.db; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.sql.SQLException; @@ -8,10 +15,8 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.utils.Settings; -import org.jetbrains.annotations.NotNull; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,9 +76,8 @@ public class DBController { if (controllers.isEmpty()) loadControllers(); - ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED)).scheduleWithFixedDelay(() -> { - DBController.get().query("SELECT 1;"); - }, 0, 120, TimeUnit.SECONDS); + ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED)) + .scheduleWithFixedDelay(() -> DBController.get().query("SELECT 1;"), 0, 120, TimeUnit.SECONDS); } /** diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java index 6f6849c..f1f8ab8 100644 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ b/src/main/java/netneutrality/db/MysqlConnector.java @@ -1,9 +1,15 @@ package netneutrality.db; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import com.mysql.cj.jdbc.MysqlDataSource; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.SQLException; public class MysqlConnector { diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 55afafa..4033f14 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -1,5 +1,12 @@ package netneutrality.db; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -185,7 +192,6 @@ public class MysqlDatabase { * * @param query The PreparedStatement object * @param params The parameters to be included in the prepared statement - * @throws SQLException */ private void resolveParameters(PreparedStatement query, Object... params) throws SQLException { int index = 1; @@ -200,16 +206,13 @@ public class MysqlDatabase { query.setLong(index, (Long) p); } else if (p instanceof Double) { query.setDouble(index, (double) p); - } else if (p instanceof java.sql.Date) { - java.sql.Date d = (java.sql.Date) p; - query.setDate(index, d); - } else if (p instanceof java.util.Date) { - java.util.Date d = (java.util.Date) p; - Timestamp ts = new Timestamp(d.getTime()); + } else if (p instanceof java.sql.Date date) { + query.setDate(index, date); + } else if (p instanceof java.util.Date date) { + Timestamp ts = new Timestamp(date.getTime()); query.setTimestamp(index, ts); - } else if (p instanceof Calendar) { - Calendar cal = (Calendar) p; - Timestamp ts = new Timestamp(cal.getTimeInMillis()); + } else if (p instanceof Calendar cal) { + Timestamp ts = new Timestamp(cal.getTimeInMillis()); query.setTimestamp(index, ts); } else if (p == null) { query.setNull(index, Types.NULL); diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 9aefc9d..f5ebf0f 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -1,8 +1,13 @@ package netneutrality.db.controllers; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; import netneutrality.db.AbstractController; import netneutrality.db.models.MBlacklist; diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java index b954a75..5619d2b 100644 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ b/src/main/java/netneutrality/db/controllers/DBGuild.java @@ -1,4 +1,6 @@ -package netneutrality.db.controllers;/* +package netneutrality.db.controllers; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 22fa677..5690d6f 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -1,8 +1,14 @@ package netneutrality.db.controllers; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import java.util.ArrayList; import java.util.Date; -import java.util.function.Consumer; import net.dv8tion.jda.api.entities.*; import netneutrality.db.AbstractController; diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java index 05767d3..37ea1df 100644 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -1,11 +1,12 @@ -package netneutrality.db.entities;/* +package netneutrality.db.entities; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ * https://discord.gg/CdFcyQ */ -import netneutrality.MusicBot; import netneutrality.db.DBController; import netneutrality.db.models.MTableModel; import netneutrality.handler.LogHandler; diff --git a/src/main/java/netneutrality/db/entities/EntityInterface.java b/src/main/java/netneutrality/db/entities/EntityInterface.java index 98cae86..5f55490 100644 --- a/src/main/java/netneutrality/db/entities/EntityInterface.java +++ b/src/main/java/netneutrality/db/entities/EntityInterface.java @@ -1,4 +1,6 @@ -package netneutrality.db.entities;/* +package netneutrality.db.entities; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java index 14158b2..928b922 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -1,4 +1,6 @@ -package netneutrality.db.entities;/* +package netneutrality.db.entities; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/db/entities/OPermission.java b/src/main/java/netneutrality/db/entities/OPermission.java index 8f35ffe..761dc5f 100644 --- a/src/main/java/netneutrality/db/entities/OPermission.java +++ b/src/main/java/netneutrality/db/entities/OPermission.java @@ -1,4 +1,6 @@ -package netneutrality.db.entities;/* +package netneutrality.db.entities; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -8,8 +10,6 @@ package netneutrality.db.entities;/* import netneutrality.command.CommandType; import netneutrality.db.models.MTableModel; -import java.util.List; - public class OPermission extends AbstractEntity { private final String guild_id; private final String role_id; diff --git a/src/main/java/netneutrality/db/models/MMessage.java b/src/main/java/netneutrality/db/models/MMessage.java index c8a50a8..6684480 100644 --- a/src/main/java/netneutrality/db/models/MMessage.java +++ b/src/main/java/netneutrality/db/models/MMessage.java @@ -1,5 +1,12 @@ package netneutrality.db.models; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + public class MMessage { private final String serverId; diff --git a/src/main/java/netneutrality/db/models/MRowModel.java b/src/main/java/netneutrality/db/models/MRowModel.java index 025d055..69fff35 100644 --- a/src/main/java/netneutrality/db/models/MRowModel.java +++ b/src/main/java/netneutrality/db/models/MRowModel.java @@ -3,7 +3,8 @@ package netneutrality.db.models; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import java.util.ArrayList; diff --git a/src/main/java/netneutrality/db/models/MRowsModel.java b/src/main/java/netneutrality/db/models/MRowsModel.java index fd9da06..e9fd3e8 100644 --- a/src/main/java/netneutrality/db/models/MRowsModel.java +++ b/src/main/java/netneutrality/db/models/MRowsModel.java @@ -3,7 +3,8 @@ package netneutrality.db.models; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ import java.util.ArrayList; diff --git a/src/main/java/netneutrality/db/models/MSellyOrder.java b/src/main/java/netneutrality/db/models/MSellyOrder.java index e3db853..75ea0c8 100644 --- a/src/main/java/netneutrality/db/models/MSellyOrder.java +++ b/src/main/java/netneutrality/db/models/MSellyOrder.java @@ -3,28 +3,29 @@ package netneutrality.db.models; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ public class MSellyOrder { - private String id; - private String product_id; - private String email; - private String ip; - private float value; - private String currency; - private String gateway; - private int risk; - private int status; - private int cryptoValue; - private String cryptoAddress; - private float usdValue; - private String createdAt; + private final String id; + private final String productId; + private final String email; + private final String ip; + private final float value; + private final String currency; + private final String gateway; + private final int risk; + private final int status; + private final int cryptoValue; + private final String cryptoAddress; + private final float usdValue; + private final String createdAt; - public MSellyOrder(String id, String product_id, String email, String ip, float value, String currency, String gateway, int risk, int status, int cryptoValue, String cryptoAddress, float usdValue, String createdAt) { + public MSellyOrder(String id, String productId, String email, String ip, float value, String currency, String gateway, int risk, int status, int cryptoValue, String cryptoAddress, float usdValue, String createdAt) { this.id = id; - this.product_id = product_id; + this.productId = productId; this.email = email; this.ip = ip; this.value = value; @@ -41,12 +42,11 @@ public class MSellyOrder { //TODO: Construct from JSONObject public String getId() { - return id; } - public String getProduct_id() { - return product_id; + public String getProductId() { + return productId; } public String getEmail() { @@ -97,7 +97,7 @@ public class MSellyOrder { public String toString() { return "MSellyOrder{" + "id='" + id + '\'' + - ", product_id='" + product_id + '\'' + + ", product_id='" + productId + '\'' + ", email='" + email + '\'' + ", ip='" + ip + '\'' + ", value='" + value + '\'' + diff --git a/src/main/java/netneutrality/db/models/MSellyProduct.java b/src/main/java/netneutrality/db/models/MSellyProduct.java index 7d72c4a..9ffddfa 100644 --- a/src/main/java/netneutrality/db/models/MSellyProduct.java +++ b/src/main/java/netneutrality/db/models/MSellyProduct.java @@ -3,7 +3,8 @@ package netneutrality.db.models; /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ public class MSellyProduct { diff --git a/src/main/java/netneutrality/exceptions/CommandErrorException.java b/src/main/java/netneutrality/exceptions/CommandErrorException.java index 7debfb4..fe519f9 100644 --- a/src/main/java/netneutrality/exceptions/CommandErrorException.java +++ b/src/main/java/netneutrality/exceptions/CommandErrorException.java @@ -1,4 +1,6 @@ -package netneutrality.exceptions;/* +package netneutrality.exceptions; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/exceptions/CommandException.java b/src/main/java/netneutrality/exceptions/CommandException.java index a9eacde..5a98a85 100644 --- a/src/main/java/netneutrality/exceptions/CommandException.java +++ b/src/main/java/netneutrality/exceptions/CommandException.java @@ -1,4 +1,6 @@ -package netneutrality.exceptions;/* +package netneutrality.exceptions; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -9,7 +11,7 @@ import netneutrality.command.CommandContext; public abstract class CommandException extends RuntimeException { - public static String DEFAULT_MESSAGE = "Unknown error during command execution."; + public static final String DEFAULT_MESSAGE = "Unknown error during command execution."; private final CommandContext context; public CommandException(String message, CommandContext context, Throwable cause) { diff --git a/src/main/java/netneutrality/exceptions/CommandExecutionException.java b/src/main/java/netneutrality/exceptions/CommandExecutionException.java index 74f9341..14ba2ba 100644 --- a/src/main/java/netneutrality/exceptions/CommandExecutionException.java +++ b/src/main/java/netneutrality/exceptions/CommandExecutionException.java @@ -1,4 +1,6 @@ -package netneutrality.exceptions;/* +package netneutrality.exceptions; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/exceptions/ExecutorException.java b/src/main/java/netneutrality/exceptions/ExecutorException.java index 398236c..d7e64e6 100644 --- a/src/main/java/netneutrality/exceptions/ExecutorException.java +++ b/src/main/java/netneutrality/exceptions/ExecutorException.java @@ -1,4 +1,6 @@ -package netneutrality.exceptions;/* +package netneutrality.exceptions; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index a4ecec4..aa72bc6 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -8,7 +8,6 @@ package netneutrality.handler; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.GuildManager; -import netneutrality.MusicBot; import netneutrality.command.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; diff --git a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java index c680058..3c4e09c 100644 --- a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java @@ -13,9 +13,7 @@ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.db.DBController; -import netneutrality.db.MysqlDatabase; import netneutrality.db.controllers.DBMessage; -import netneutrality.db.controllers.DBSettings; import netneutrality.db.models.MTableModel; public class EditHandler extends ListenerAdapter { diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index 3e798b9..6dee6dc 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -7,7 +7,6 @@ package netneutrality.handler.hooks.message; */ import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.GuildManager; diff --git a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java index 277c09d..fd51090 100644 --- a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java +++ b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java @@ -19,11 +19,15 @@ import net.dv8tion.jda.api.entities.TextChannel; import java.time.OffsetDateTime; public class MessageRateLimiterImpl implements IMessageRateLimiter { - private int messagePerSecond = 5; + private final int messagePerSecond = 5; private static Member lastSender; private static OffsetDateTime timestamp; private static final long cooldown = 500000000L; // 1 seconds = 1000000000 nanoseconds + public MessageRateLimiterImpl() { + + } + @Override public void check(Member member, Message message, TextChannel channel) { @@ -44,7 +48,5 @@ public class MessageRateLimiterImpl implements IMessageRateLimiter { lastSender = member; timestamp = message.getTimeCreated(); - - return; } } diff --git a/src/main/java/netneutrality/http/Selly.java b/src/main/java/netneutrality/http/Selly.java index 3064b9d..18d281e 100644 --- a/src/main/java/netneutrality/http/Selly.java +++ b/src/main/java/netneutrality/http/Selly.java @@ -17,7 +17,7 @@ import java.util.Map; public class Selly { - private byte[] encodedAuth; + private final byte[] encodedAuth; public Selly(String email, String apiKey) { String concat = email + ":" + apiKey; diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index b0c8002..565b77c 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -127,8 +127,6 @@ public class WebModule { /** * @return the response as a JSONObject - * @throws JSONException - * @throws IOException */ public JSONObject getAsObject() throws JSONException, IOException { if (response == null) @@ -141,8 +139,6 @@ public class WebModule { * Use if your response start with an array : [ ] * * @return the response as a JSONArray - * @throws JSONException - * @throws IOException */ public JSONArray getAsArray() throws JSONException, IOException { if (response == null) @@ -153,8 +149,6 @@ public class WebModule { /** * @return the response as a String - * @throws JSONException - * @throws IOException */ public String getRawData() throws IOException { if (response == null) diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 57e9188..ac98e2e 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -44,10 +44,11 @@ public class ActionHandler extends AbstractHandler { if (path.startsWith("/actions/settings/current/")) { JSONObject json = new JSONObject(); String[] args = exchange.getRequestURI().toString().split("/"); - String guild = args[args.length - 1]; + String guildId = args[args.length - 1]; - GuildManager manager = GuildManager.getManager(MusicBot.getJDA().getGuildById(guild)); - if (manager != null) { + Guild guild = MusicBot.getJDA().getGuildById(guildId); + if (guild != null) { + GuildManager manager = GuildManager.getManager(guild); Map<String, Object> settings = manager.getSettings(); JSONObject setting = new JSONObject(settings); diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/netneutrality/http/server/GuildHandler.java index 616d4f4..4ba2028 100644 --- a/src/main/java/netneutrality/http/server/GuildHandler.java +++ b/src/main/java/netneutrality/http/server/GuildHandler.java @@ -8,18 +8,12 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; import netneutrality.MusicBot; -import netneutrality.http.WebModule; import org.json.JSONArray; import org.json.JSONObject; import java.io.IOException; -import java.io.OutputStream; -import java.util.*; public class GuildHandler extends AbstractHandler { diff --git a/src/main/java/netneutrality/http/server/RootHandler.java b/src/main/java/netneutrality/http/server/RootHandler.java index cee2056..94d9b00 100644 --- a/src/main/java/netneutrality/http/server/RootHandler.java +++ b/src/main/java/netneutrality/http/server/RootHandler.java @@ -8,10 +8,8 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; import java.io.IOException; -import java.io.OutputStream; public class RootHandler extends AbstractHandler { diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 9d4c268..aec38c8 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -21,13 +21,12 @@ import java.util.concurrent.Executors; public class WebApi { private final static Logger logger = LoggerFactory.getLogger(WebApi.class); - private final ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThreadFactory("web-api")); - private final int port = 9000; private HttpServer server; - public WebApi() { + public WebApi(int port) { logger.info("Starting web server..."); + try { InetAddress localHost = InetAddress.getLoopbackAddress(); InetSocketAddress sockAddr = new InetSocketAddress(localHost, port); @@ -39,6 +38,7 @@ public class WebApi { server.createContext("/", new RootHandler()); server.createContext("/actions", new ActionHandler()); server.createContext("/guilds", new GuildHandler()); + ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThreadFactory("web-api")); server.setExecutor(executor); server.start(); logger.info("Web server started at [" + server.getAddress() + "]"); From 873c7c8d263989c29a55e1e437373d4ddcbb4455 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 27 Feb 2022 15:08:33 -0500 Subject: [PATCH 070/155] Update maven wrapper --- .mvn/wrapper/maven-wrapper.properties | 18 +++++++++++++++- mvnw | 18 ++++++++++------ mvnw.cmd | 30 ++++++++++++++++----------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572..e83fa69 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/mvnw b/mvnw index 41c0f0c..5643201 100644 --- a/mvnw +++ b/mvnw @@ -36,6 +36,10 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi @@ -145,7 +149,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`which java`" + JAVACMD="`\\unset -f command; \\command -v java`" fi fi @@ -212,9 +216,9 @@ else echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." fi if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" fi while IFS="=" read key value; do case "$key" in (wrapperUrl) jarUrl="$value"; break ;; @@ -233,9 +237,9 @@ else echo "Found wget ... using wget" fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl > /dev/null; then if [ "$MVNW_VERBOSE" = true ]; then @@ -305,6 +309,8 @@ WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 8611571..8a15b7f 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -46,8 +46,8 @@ if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") @REM Execute a user defined script before this one if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre @REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* :skipRcPre @setlocal @@ -120,9 +120,9 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B ) @@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... @@ -158,7 +158,13 @@ if exist %WRAPPER_JAR% ( @REM work with both Windows and non-Windows executions. set MAVEN_CMD_LINE_ARGS=%* -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* if ERRORLEVEL 1 goto error goto end @@ -168,15 +174,15 @@ set ERROR_CODE=1 :end @endlocal & set ERROR_CODE=%ERROR_CODE% -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost @REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" :skipRcPost @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause +if "%MAVEN_BATCH_PAUSE%"=="on" pause -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% -exit /B %ERROR_CODE% +cmd /C exit /B %ERROR_CODE% From e3f47bbfe59b4cceeaa68b5daca0aeae897a2f94 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 13 Mar 2022 15:06:22 -0400 Subject: [PATCH 071/155] Switch to JPA for database --- .gitignore | 1 + .jpb/jpb-settings.xml | 6 + Dockerfile | 2 +- bot.config.example => bot.properties.example | 5 +- pom.xml | 36 ++- sql/add_volume_field_to_settings_table.sql | 3 +- src/main/java/netneutrality/GuildManager.java | 162 ---------- .../{MusicBot.java => NetNeutrality.java} | 35 ++- .../command/AbstractMusicCommand.java | 4 +- .../java/netneutrality/command/ICommand.java | 1 + .../command/basic/HelpCommand.java | 8 +- .../command/basic/PingCommand.java | 2 +- .../command/bot/ConfigureCommand.java | 20 +- .../command/crypto/BitcoinPriceCommand.java | 16 +- .../command/crypto/CryptoPriceCommand.java | 16 +- .../command/crypto/EthereumPriceCommand.java | 16 +- .../command/crypto/LitecoinPriceCommand.java | 15 +- .../command/message/BlacklistCommand.java | 74 ++--- .../command/message/PruneCommand.java | 2 +- .../command/music/BitconnectCommand.java | 2 +- .../music/CurrentlyPlayingCommand.java | 5 +- .../command/music/DeleteQueueCommand.java | 19 +- .../command/music/JoinCommand.java | 11 +- .../command/music/LeaveCommand.java | 5 +- .../command/music/PlayCommand.java | 2 +- .../command/music/SkipCommand.java | 5 +- .../command/music/StopCommand.java | 5 +- .../command/music/ViewQueueCommand.java | 5 +- .../command/music/VolumeCommand.java | 14 +- .../command/music/VoteSkipCommand.java | 9 +- .../command/specific/DatabaseCommand.java | 22 +- .../command/specific/LoggingCommand.java | 2 +- .../java/netneutrality/core/GuildManager.java | 279 +++++++++++++++++ .../{handler => core}/LogHandler.java | 19 +- .../netneutrality/core/SessionManager.java | 66 ++++ .../{utils => core}/UnsafeShutdown.java | 11 +- .../context}/CommandContext.java | 30 +- .../netneutrality/db/AbstractController.java | 22 +- .../netneutrality/db/AsyncMySqlAction.java | 66 ---- .../java/netneutrality/db/DBController.java | 54 +--- .../java/netneutrality/db/MysqlConnector.java | 58 ---- .../java/netneutrality/db/MysqlDatabase.java | 293 ------------------ .../db/controllers/DBBlacklist.java | 135 +++++--- .../netneutrality/db/controllers/DBGuild.java | 31 -- .../db/controllers/DBLogging.java | 33 -- .../db/controllers/DBMessage.java | 104 ++++--- .../db/entities/AbstractEntity.java | 54 ---- .../db/entities/EntityInterface.java | 21 -- .../netneutrality/db/entities/OBlacklist.java | 75 +++++ .../netneutrality/db/entities/OGuild.java | 142 ++++++--- .../db/entities/OGuildSetting.java | 86 +++-- .../db/entities/OLogMessage.java | 111 +++++++ .../netneutrality/db/entities/OLogging.java | 49 +++ .../netneutrality/db/entities/OLoggingId.java | 56 ++++ .../db/entities/OPermission.java | 66 ---- .../OSellyOrder.java} | 6 +- .../netneutrality/db/models/MBlacklist.java | 59 ---- .../netneutrality/db/models/MMessage.java | 66 ---- .../netneutrality/db/models/MRowModel.java | 80 ----- .../netneutrality/db/models/MRowsModel.java | 47 --- .../db/models/MSellyProduct.java | 19 -- .../netneutrality/db/models/MTableModel.java | 118 ------- .../exceptions/CommandErrorException.java | 2 +- .../exceptions/CommandException.java | 2 +- .../exceptions/CommandExecutionException.java | 2 +- .../exceptions/ExecutorException.java | 2 +- .../UnimplementedParameterException.java | 38 --- .../hooks/guilds/ServerJoinHandler.java | 8 +- .../handler/hooks/message/EditHandler.java | 61 ++-- .../hooks/message/MessageReceivedHandler.java | 10 +- .../{ => hooks/message}/ReactionHandler.java | 3 +- src/main/java/netneutrality/http/Selly.java | 12 +- .../java/netneutrality/http/WebModule.java | 52 ++-- .../http/server/ActionHandler.java | 21 +- .../http/server/GuildHandler.java | 8 +- .../netneutrality/music/MusicManager.java | 23 +- .../netneutrality/music/TrackScheduler.java | 5 +- .../MusicPlayerAutoDisconnectThread.java | 4 +- .../netneutrality/thread/ShutdownThread.java | 7 +- .../{ => thread}/ThreadManager.java | 18 +- .../netneutrality/utils/ChannelFunction.java | 90 ++++-- .../java/netneutrality/utils/JpaUtils.java | 42 +++ .../netneutrality/utils/MessageFunction.java | 74 +++-- .../java/netneutrality/utils/MusicUtils.java | 30 +- .../java/netneutrality/utils/Settings.java | 6 +- src/main/resources/META-INF/MANIFEST.MF | 2 +- src/main/resources/hibernate.cfg.xml | 19 ++ src/main/resources/log4j2.properties | 34 ++ src/main/resources/log4j2.xml | 16 - src/main/resources/spy.properties | 4 + 90 files changed, 1527 insertions(+), 1854 deletions(-) create mode 100644 .jpb/jpb-settings.xml rename bot.config.example => bot.properties.example (74%) delete mode 100644 src/main/java/netneutrality/GuildManager.java rename src/main/java/netneutrality/{MusicBot.java => NetNeutrality.java} (64%) create mode 100644 src/main/java/netneutrality/core/GuildManager.java rename src/main/java/netneutrality/{handler => core}/LogHandler.java (89%) create mode 100644 src/main/java/netneutrality/core/SessionManager.java rename src/main/java/netneutrality/{utils => core}/UnsafeShutdown.java (91%) rename src/main/java/netneutrality/{command => core/context}/CommandContext.java (81%) delete mode 100644 src/main/java/netneutrality/db/AsyncMySqlAction.java delete mode 100644 src/main/java/netneutrality/db/MysqlConnector.java delete mode 100644 src/main/java/netneutrality/db/MysqlDatabase.java delete mode 100644 src/main/java/netneutrality/db/controllers/DBGuild.java delete mode 100644 src/main/java/netneutrality/db/controllers/DBLogging.java delete mode 100644 src/main/java/netneutrality/db/entities/AbstractEntity.java delete mode 100644 src/main/java/netneutrality/db/entities/EntityInterface.java create mode 100644 src/main/java/netneutrality/db/entities/OBlacklist.java create mode 100644 src/main/java/netneutrality/db/entities/OLogMessage.java create mode 100644 src/main/java/netneutrality/db/entities/OLogging.java create mode 100644 src/main/java/netneutrality/db/entities/OLoggingId.java delete mode 100644 src/main/java/netneutrality/db/entities/OPermission.java rename src/main/java/netneutrality/db/{models/MSellyOrder.java => entities/OSellyOrder.java} (95%) delete mode 100644 src/main/java/netneutrality/db/models/MBlacklist.java delete mode 100644 src/main/java/netneutrality/db/models/MMessage.java delete mode 100644 src/main/java/netneutrality/db/models/MRowModel.java delete mode 100644 src/main/java/netneutrality/db/models/MRowsModel.java delete mode 100644 src/main/java/netneutrality/db/models/MSellyProduct.java delete mode 100644 src/main/java/netneutrality/db/models/MTableModel.java delete mode 100644 src/main/java/netneutrality/exceptions/UnimplementedParameterException.java rename src/main/java/netneutrality/handler/{ => hooks/message}/ReactionHandler.java (95%) rename src/main/java/netneutrality/{ => thread}/ThreadManager.java (86%) create mode 100644 src/main/java/netneutrality/utils/JpaUtils.java create mode 100644 src/main/resources/hibernate.cfg.xml create mode 100644 src/main/resources/log4j2.properties delete mode 100644 src/main/resources/log4j2.xml create mode 100644 src/main/resources/spy.properties diff --git a/.gitignore b/.gitignore index 6d10652..fcc2aa9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ # Config file bot.config +bot.properties # Mobile Tools for Java (J2ME) .mtj.tmp/ diff --git a/.jpb/jpb-settings.xml b/.jpb/jpb-settings.xml new file mode 100644 index 0000000..935cf0d --- /dev/null +++ b/.jpb/jpb-settings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="JpaPluginProjectSettings"> + <option name="lastSelectedLanguage" value="Java" /> + </component> +</project> \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 217542e..c2823fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ WORKDIR /app COPY .mvn/ .mvn COPY mvnw pom.xml ./ COPY src ./src -COPY bot.config.example bot.config ./ +COPY bot.properties.example bot.properties ./ RUN ./mvnw -q -Dmaven.test.skip=true package diff --git a/bot.config.example b/bot.properties.example similarity index 74% rename from bot.config.example rename to bot.properties.example index f6fe2c0..99dab96 100644 --- a/bot.config.example +++ b/bot.properties.example @@ -1,3 +1,4 @@ +BOT_ENV=dev BOT_TOKEN= BOT_PREFIX= BOT_OWNER= @@ -8,4 +9,6 @@ MYSQL_HOST= MYSQL_USER= MYSQL_PASSWORD= MYSQL_DATABASE= -MYSQL_PORT=3306 \ No newline at end of file +MYSQL_PORT=3306 + +SENTRY_DSN= \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2de6182..f3f8ee7 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> - <mainClass>netneutrality.MusicBot</mainClass> + <mainClass>netneutrality.NetNeutrality</mainClass> </manifest> </archive> </configuration> @@ -53,7 +53,7 @@ <configuration> <archive> <manifest> - <mainClass>netneutrality.MusicBot</mainClass> + <mainClass>netneutrality.NetNeutrality</mainClass> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> </manifest> @@ -121,6 +121,27 @@ <version>4.9.3</version> </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-core</artifactId> + <version>5.6.5.Final</version> + </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-hikaricp</artifactId> + <version>5.6.5.Final</version> + </dependency> + <dependency> + <groupId>io.sentry</groupId> + <artifactId>sentry</artifactId> + <version>5.6.3</version> + </dependency> + <dependency> + <groupId>p6spy</groupId> + <artifactId>p6spy</artifactId> + <version>3.9.1</version> + </dependency> + <!-- https://mvnrepository.com/artifact/org.json/json --> <dependency> <groupId>org.json</groupId> @@ -137,22 +158,17 @@ <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>8.0.27</version> - </dependency> - <dependency> - <groupId>org.apache.logging.log4j</groupId> - <artifactId>log4j-api</artifactId> - <version>2.17.0</version> + <version>8.0.28</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> - <version>2.17.0</version> + <version>2.17.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> - <version>2.17.0</version> + <version>2.17.1</version> </dependency> <dependency> diff --git a/sql/add_volume_field_to_settings_table.sql b/sql/add_volume_field_to_settings_table.sql index a5b018b..d427e2b 100644 --- a/sql/add_volume_field_to_settings_table.sql +++ b/sql/add_volume_field_to_settings_table.sql @@ -1,2 +1 @@ -ALTER TABLE `guild_settings` ADD `music_volume` INT NOT NULL DEFAULT '30' AFTER `music_channel`; - +ALTER TABLE `guild_settings` ADD `music_volume` INT NOT NULL DEFAULT '30' AFTER `music_channel`; \ No newline at end of file diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java deleted file mode 100644 index 62bae03..0000000 --- a/src/main/java/netneutrality/GuildManager.java +++ /dev/null @@ -1,162 +0,0 @@ -package netneutrality; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBGuild; -import netneutrality.db.controllers.DBMessage; -import netneutrality.db.entities.OGuild; -import netneutrality.handler.ratelimiter.IMessageRateLimiter; -import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; -import netneutrality.utils.MessageFunction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class GuildManager { - - public enum GuildSetting { - MUSIC_ROLE("MUSIC_ROLE", ""), - MUSIC_CHANNEL("MUSIC_CHANNEL", ""), - MUSIC_VOLUME("MUSIC_VOLUME", 30), - BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); - - private final String name; - private final Object defaultValue; - - GuildSetting(String name, Object defaultValue) { - this.name = name; - this.defaultValue = defaultValue; - } - - public String getName() { - return name; - } - - public Object getDefaultValue() { - return defaultValue; - } - } - - public static final Logger logger = LoggerFactory.getLogger(GuildManager.class); - private static final Map<String, GuildManager> managers = new ConcurrentHashMap<>(); - private final Guild guild; - private OGuild guildEntity; - private final IMessageRateLimiter rateLimiter; - - private GuildManager(Guild guild) { - this.guild = guild; - handleJoinEvent(); - - this.guildEntity = new OGuild(guild.getId()); - this.rateLimiter = new MessageRateLimiterImpl(); - managers.put(guild.getId(), this); - } - - public static GuildManager getManager(Guild guild) { - if (managers.containsKey(guild.getId())) { - return managers.get(guild.getId()); - } else { - return new GuildManager(guild); - } - } - - // Getter - public static Map<String, GuildManager> getManagers() { - return managers; - } - - public static GuildManager getManager(String guildId) { - return managers.getOrDefault(guildId, null); - } - - public Object getSetting(GuildSetting key) { - return guildEntity.getSettings().getSettingByKey(key); - } - - public boolean isLoggingEnabled() { - return guildEntity.isLogging(); - } - - public boolean isDebugEnabled() { - return guildEntity.isDebug(); - } - - public Map<String, Object> getSettings() { - return guildEntity.getSettings().getSettings(); - } - - public IMessageRateLimiter getRateLimiter() { - return rateLimiter; - } - - public Guild getGuild() { - return guild; - } - - - public static boolean reloadSettingsForGuild(String guildId) { - if (managers.containsKey(guildId)) { - GuildManager manager = managers.get(guildId); - manager.reloadSettings(); - - return true; - } - - return false; - } - - public static boolean reloadSettingsForGuild(Guild guild) { - GuildManager manager = GuildManager.getManager(guild.getId()); - manager.reloadSettings(); - - return true; - } - - public void checkAndLogMessage(Message message, Member member, TextChannel channel) { - if (guildEntity.isLogging()) { - ((DBMessage) DBController.get("message")).log(guild, channel, member, message); - } - } - - public void checkBlacklist(Message message, Member member, TextChannel channel) { - //TODO: per-guild - MessageFunction.checkBlacklist(guild, message, channel); - } - - public boolean existInDb() { - return DBController.get().exists("guilds", "guild_id", guild.getId()); - } - - public void reloadSettings() { - logger.debug("Reloading guild entity: " + guild.getId()); - this.guildEntity = new OGuild(guild.getId()); - } - - public void handleJoinEvent() { - if (!existInDb()) { - ((DBGuild) DBController.get("guild")).insertGuildInDB(guild); - - guild.getTextChannels() - .stream() - .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) - .forEach(textChannel -> textChannel.sendMessage("Error logging enabled on channel " + textChannel.getAsMention()).queue()); - } - - } - - public void removeFromDB() { - ((DBGuild) DBController.get("guild")).removeGuildInDB(guild); - } - -} diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/NetNeutrality.java similarity index 64% rename from src/main/java/netneutrality/MusicBot.java rename to src/main/java/netneutrality/NetNeutrality.java index 3de4827..f739550 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -1,33 +1,45 @@ package netneutrality; +import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.GatewayIntent; - import netneutrality.command.CommandManager; +import netneutrality.core.LogHandler; import netneutrality.db.DBController; +import netneutrality.handler.hooks.guilds.ServerJoinHandler; import netneutrality.handler.hooks.message.EditHandler; import netneutrality.handler.hooks.message.MessageReceivedHandler; -import netneutrality.handler.hooks.guilds.ServerJoinHandler; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; import netneutrality.thread.BaseThreadFactory; import netneutrality.thread.ShutdownThread; +import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.security.auth.login.LoginException; -public class MusicBot { +public class NetNeutrality { private static JDA jda; - public final static Logger logger = LoggerFactory.getLogger(MusicBot.class); + public final static Logger logger = LoggerFactory.getLogger(NetNeutrality.class); public static void main(String[] args) { + String sentryDsn = Settings.getInstance().get("SENTRY_DSN"); + Sentry.init(options -> { + options.setDsn(sentryDsn); + options.setEnvironment(Settings.getInstance().get("BOT_ENV", "dev")); + // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring. + // We recommend adjusting this value in production. + options.setTracesSampleRate(1.0); + // When first trying Sentry it's good to see what the SDK is doing: + options.setDebug(true); + }); + DBController.init(); @@ -35,7 +47,6 @@ public class MusicBot { CommandManager.init(); MusicManager.initPlayerManager(); - jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); new WebApi(9000); @@ -47,11 +58,17 @@ public class MusicBot { public static void initJDA() { try { - jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")).enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES).build(); + jda = JDABuilder + .createDefault(Settings.getInstance().get("BOT_TOKEN")) + .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) + .setActivity(Activity.watching("me load...")) + .build(); jda.awaitReady(); } catch (LoginException | IllegalArgumentException | InterruptedException e) { - logger.error(e.getMessage()); - System.exit(0); + Sentry.captureException(e); + + LogHandler.log(e); + System.exit(1); } } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 66c4b99..4614326 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -9,7 +9,7 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; -import netneutrality.GuildManager; +import netneutrality.core.GuildManager; import netneutrality.utils.UserFunction; public abstract class AbstractMusicCommand extends AbstractCommand { @@ -26,7 +26,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = (String) GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_ROLE); boolean can = true; //System.out.println(roleDb); diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 9a35a21..848bc5a 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -8,6 +8,7 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index f97db14..69bf7c9 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -8,7 +8,11 @@ package netneutrality.command.basic; import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; -import netneutrality.command.*; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandManager; +import netneutrality.command.CommandType; +import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.utils.MessageFunction; import netneutrality.utils.UserFunction; @@ -72,8 +76,6 @@ public class HelpCommand extends AbstractCommand { context.replyPrivate("Command [" + c.getCommandName() + "] requires admin privileges"); } - System.out.println(CommandUsage.create(c, new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"get", "add"}, ""))); - MessageEmbed help = MessageFunction.buildHelpMessage(c); context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); context.replyPrivate(help); diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index b70afde..432c9bf 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -7,9 +7,9 @@ package netneutrality.command.basic; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; public class PingCommand extends AbstractCommand { diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index a5abe27..0474c82 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -7,13 +7,11 @@ package netneutrality.command.bot; */ import net.dv8tion.jda.api.entities.Role; -import netneutrality.GuildManager; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; -import netneutrality.db.DBController; -import netneutrality.db.MysqlDatabase; +import netneutrality.core.GuildManager; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; @@ -60,7 +58,6 @@ public class ConfigureCommand extends AbstractCommand { @Override public void execute(CommandContext context) { String[] args = context.getArgumentsAsArray(); - MysqlDatabase database = DBController.get(); GuildManager guildManager = GuildManager.getManager(context.getGuild()); if (args.length > 0) { @@ -68,7 +65,7 @@ public class ConfigureCommand extends AbstractCommand { if (context.getArg(0).equals("musicrole")) { if (args.length == 1) { - String roleDb = (String) guildManager.getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + String roleDb = guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -83,15 +80,13 @@ public class ConfigureCommand extends AbstractCommand { if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { - database.prepareAndExecuteAsync("UPDATE guild_settings SET music_role = ? WHERE guild_id = ?", role.getId(), context.getGuild().getId()).blocking(); - guildManager.reloadSettings(); + guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, role.getId()); context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } if (context.getArg(1).equals("reset")) { - database.prepareAndExecuteAsync("UPDATE guild_settings SET music_role = null WHERE guild_id = ?", context.getGuild().getId()).blocking(); - guildManager.reloadSettings(); + guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); context.reply("Successful reset of the role"); } } @@ -99,7 +94,7 @@ public class ConfigureCommand extends AbstractCommand { if (context.getArg(0).equals("musicvolume")) { if (args.length == 1) { - int volume = (int) guildManager.getSetting(GuildManager.GuildSetting.MUSIC_VOLUME); + int volume = Integer.parseInt(guildManager.getSetting(GuildManager.Settings.MUSIC_VOLUME)); context.reply("Default volume for music player: " + volume); } @@ -108,8 +103,7 @@ public class ConfigureCommand extends AbstractCommand { try { int volume = Integer.parseInt(args[1]); - database.prepareAndExecuteAsync("UPDATE guild_settings SET music_volume = ? WHERE guild_id = ?", volume, context.getGuild().getId()).blocking(); - guildManager.reloadSettings(); + guildManager.setSettingValue(GuildManager.Settings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); context.reply("Default volume for music player is now %d", volume); } catch (NumberFormatException e) { diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 87b57e9..48750c0 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -7,11 +7,10 @@ package netneutrality.command.crypto; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; -import netneutrality.exceptions.CommandErrorException; -import netneutrality.exceptions.CommandExecutionException; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; @@ -70,7 +69,8 @@ public class BitcoinPriceCommand extends AbstractCommand { if (Currency.isCurrency(args[0].toUpperCase())) currency = args[0].toUpperCase(); else { - throw new CommandErrorException("Please enter a valid currency", context, null); + context.reply("Please enter a valid currency"); + return; } } @@ -85,15 +85,11 @@ public class BitcoinPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); - + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - throw new CommandExecutionException("Error during web request", context, e); + LogHandler.log(e); } - - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - }); } - } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 96dd62f..d9d16f4 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -7,11 +7,10 @@ package netneutrality.command.crypto; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; -import netneutrality.exceptions.CommandErrorException; -import netneutrality.exceptions.CommandExecutionException; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; @@ -72,7 +71,8 @@ public class CryptoPriceCommand extends AbstractCommand { if (Currency.isCurrency(args[1].toUpperCase())) currency = args[1].toUpperCase(); else { - throw new CommandErrorException("Please enter a valid currency", context, null); + context.reply("Please enter a valid currency"); + return; } } @@ -88,17 +88,13 @@ public class CryptoPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - throw new CommandExecutionException("Error during web request", context, e); + LogHandler.log(e); } - - - - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } } - } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 625005a..49f2706 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -7,11 +7,10 @@ package netneutrality.command.crypto; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; -import netneutrality.exceptions.CommandErrorException; -import netneutrality.exceptions.CommandExecutionException; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; @@ -70,7 +69,8 @@ public class EthereumPriceCommand extends AbstractCommand { if (Currency.isCurrency(args[0].toUpperCase())) currency = args[0].toUpperCase(); else { - throw new CommandErrorException("Please enter a valid currency", context, null); + context.reply("Please enter a valid currency"); + return; } } @@ -85,15 +85,11 @@ public class EthereumPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); - + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - throw new CommandExecutionException("Error during web request", context, e); + LogHandler.log(e); } - - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - }); } - } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 954a75c..bbd7bc5 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -7,11 +7,10 @@ package netneutrality.command.crypto; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; -import netneutrality.exceptions.CommandErrorException; -import netneutrality.exceptions.CommandExecutionException; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; @@ -70,7 +69,8 @@ public class LitecoinPriceCommand extends AbstractCommand { if (Currency.isCurrency(args[0].toUpperCase())) currency = args[0].toUpperCase(); else { - throw new CommandErrorException("Please enter a valid currency", context, null); + context.reply("Please enter a valid currency"); + return; } } @@ -85,14 +85,11 @@ public class LitecoinPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); - + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - throw new CommandExecutionException("Error during web request", context, e); + LogHandler.log(e); } - - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - }); } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index fd98379..506b11c 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -7,13 +7,13 @@ package netneutrality.command.message; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; import netneutrality.db.DBController; import netneutrality.db.controllers.DBBlacklist; -import netneutrality.db.models.MBlacklist; -import netneutrality.exceptions.CommandExecutionException; +import netneutrality.db.entities.OBlacklist; import java.util.ArrayList; @@ -57,71 +57,39 @@ public class BlacklistCommand extends AbstractCommand { @Override public void execute(CommandContext context) { String[] args = context.getArgumentsAsArray(); - DBBlacklist controller = ((DBBlacklist) DBController.get("blacklist")); + DBBlacklist controller = DBController.get("blacklist", DBBlacklist.class); if (controller == null) { - throw new CommandExecutionException("Error getting database controller", context, null); + } if (args.length > 0 && args.length < 3) { String word = (args.length == 2 ? args[1] : ""); switch (args[0]) { + case "get" -> { - case "get": context.getChannel().sendMessage("Retrieving list, please wait...").queue(t -> { + ArrayList<OBlacklist> blacklists = new ArrayList<>(); + try { + blacklists = controller.getBlacklistForGuild(context); + } catch (Exception e) { + LogHandler.log(e); + } StringBuilder sb = new StringBuilder(); - ArrayList<MBlacklist> blacklists = controller.getBlacklistFromServer(context.getGuild().getId()); - for (MBlacklist bl : blacklists) { - sb.append(bl.getWord()).append(" -> ").append(bl.isEnabled() ? "enabled" : "disabled").append("\n"); - } + for (OBlacklist bl : blacklists) { + sb.append(bl.getWord()).append(" -> ").append(bl.getEnabled() ? "enabled" : "disabled").append("\n"); + } - t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (blacklists.isEmpty() ? "No word found" : sb.toString())).queue(); + t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (blacklists.isEmpty() ? "No word found" : sb.toString())).queue(); }); - - break; - - case "add": - - if (controller.add(new MBlacklist(word, true, context.getDiscordUser().getId(), context.getGuild().getId()))) { - context.reply(String.format("Added the word [%s] to the blacklist.", word)); - } else { - context.reply(String.format("Error adding [%s] to the blacklist. It's already blacklisted!", word)); - } - break; - - case "remove": - - if (controller.delete(word, context.getGuild().getId())) { - context.reply("Removed the word \"" + word + "\" from the blacklist."); - } else { - context.reply("Error removing \"" + word + "\" from the blacklist"); - } - - break; - - case "disable": - - if (controller.disable(word, context.getGuild().getId())) { - context.reply("Removed the word \"" + word + "\" from the blacklist."); - } else { - context.reply("Error removing \"" + word + "\" from the blacklist"); - } - - break; - - case "enable": - - if (controller.enable(word, context.getGuild().getId())) { - context.reply("Removed the word \"" + word + "\" from the blacklist."); - } else { - context.reply("Error removing \"" + word + "\" from the blacklist"); - } - - break; - + } + case "add" -> controller.add(word, context); + case "remove" -> controller.delete(word, context); + case "disable" -> controller.disable(word, context); + case "enable" -> controller.enable(word, context); } } } diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index 646bf1d..e9179de 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -7,9 +7,9 @@ package netneutrality.command.message; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.utils.ChannelFunction; public class PruneCommand extends AbstractCommand { diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index c98a1d4..c66aeba 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -8,9 +8,9 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; public class BitconnectCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index abbc959..d673627 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -9,8 +9,8 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; @@ -46,7 +46,8 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { public void execute(CommandContext context) { Member member = context.getGuildUser(); MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; if (player.getCurrentlyPlaying() != null) { context.reply(MessageFunction.buildCurrentlyPlayingMessage(player, member)); diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 0cf91d6..06e1b55 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -8,18 +8,14 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; public class DeleteQueueCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { @@ -51,7 +47,11 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; + + if (!MusicUtils.checkIfDj(player, context)) + return; if (context.getArgumentsAsArray().length == 0) { context.reply("Select the track you want to delete from the queue (track# or all)"); @@ -66,7 +66,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { if (queueSize > 0) { player.leave(); player.getScheduler().getQueue().clear(); - context.reply("Removed " + queueSize-- + (queueSize > 1 ? " tracks" : "track") + " from the queue"); + context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); } else { context.reply("Queue is empty!"); } @@ -86,11 +86,6 @@ public class DeleteQueueCommand extends AbstractMusicCommand { throw new CommandErrorException("Please enter a number", context, e); } } - - - } - - } } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index b6cd31a..d9c9b57 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -9,9 +9,8 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; -import netneutrality.exceptions.CommandErrorException; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; @@ -47,15 +46,17 @@ public class JoinCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); if (context.getGuildUser().getVoiceState() == null) { - throw new CommandExecutionException("Voice state is null", context, null); + throw new CommandExecutionException("Voice state is null, this should not happen", context, null); } if (!context.getGuildUser().getVoiceState().inVoiceChannel()) { - throw new CommandErrorException("You are not in a voice channel", context, null); + context.reply("You are not in a voice channel"); + return; } if (player.isConnected()) { - throw new CommandErrorException("Player is already in a voice channel", context, null); + context.reply("Player is already in a voice channel"); + return; } VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index d2811ce..829d943 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -8,8 +8,8 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -47,7 +47,8 @@ public class LeaveCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; player.leave(); } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 444e9d4..df719d5 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -8,8 +8,8 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; public class PlayCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 5f3960d..5b56405 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -8,8 +8,8 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -43,7 +43,8 @@ public class SkipCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; // Combined fonctionality of vote skip //TODO: clean ifs diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 0347855..5dcec88 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -8,8 +8,8 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -44,7 +44,8 @@ public class StopCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; if (UserFunction.isAdmin(context.getGuildUser()) || context.getGuildUser().getId().equals(player.getRequesterOfCurrentTrack().getId())) { player.leave(); diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 0d65e64..ea86e90 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -9,8 +9,8 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.Member; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; @@ -50,7 +50,8 @@ public class ViewQueueCommand extends AbstractMusicCommand { public void execute(CommandContext context) { Member member = context.getGuildUser(); MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; int queueSize = player.getScheduler().getQueue().size(); if (queueSize > 0) { diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index f2f1d7b..bd03f77 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -8,17 +8,13 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; public class VolumeCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { @@ -48,14 +44,18 @@ public class VolumeCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(player, context); + if (!MusicUtils.checkIfConnected(player, context)) + return; + + if (!MusicUtils.checkIfDj(player, context)) + return; try { int volume = Integer.parseInt(context.getArgumentsAsArray()[0]); player.setVolume(volume); context.reply("Volume set to %s", volume); } catch (NumberFormatException e) { - throw new CommandErrorException("Please enter a value from 0 to 100", context, null); + throw new CommandErrorException("Please enter a value from 0 to 100", context, e); } } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index 6d5037e..1b656a7 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -7,8 +7,8 @@ package netneutrality.command.music; */ import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -41,9 +41,10 @@ public class VoteSkipCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { - MusicManager manager = MusicManager.get(context.getGuild()); - MusicUtils.checkIfConnected(manager, context); + MusicManager player = MusicManager.get(context.getGuild()); + if (!MusicUtils.checkIfConnected(player, context)) + return; - manager.voteSkip(context); + player.voteSkip(context); } } diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index f227415..210b317 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -9,18 +9,17 @@ package netneutrality.command.specific; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.User; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; -import netneutrality.db.models.MMessage; +import netneutrality.db.entities.OLogMessage; import netneutrality.utils.Settings; import java.awt.*; import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; +import java.util.List; public class DatabaseCommand extends AbstractCommand { @@ -75,29 +74,28 @@ public class DatabaseCommand extends AbstractCommand { if (args.length > 1) { - MMessage message = ((DBMessage) DBController.get("message")).getMessage(args[1]); + OLogMessage message = DBController.get("message", DBMessage.class).getMessage(args[1]); if (message != null) { EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.BLUE); - embed.setTimestamp( - DateTimeFormatter.ofPattern(Settings.getInstance().DATETIMEFORMAT).parse(message.getDateSent())); - embed.setFooter("Guild : " + message.getServerId() + " | ID : " + message.getMessageId(), null); + embed.setTimestamp(message.getDateSent()); + embed.setFooter("Guild : " + context.getGuild().getId() + " | ID : " + message.getMessageId(), null); embed.setDescription( - "Message from " + message.getSender() + " on the channel " + message.getChannelName()); + "Message from " + message.getUserId() + " on the channel " + message.getChannelId()); embed.addField("Message: ", "" + message.getMessage(), false); context.reply(embed.build()); } else { //TODO: cached user lol xd User user = context.getJDA().getUserById(args[1]); if (user != null) { - ArrayList<MMessage> messages = ((DBMessage) DBController.get("message")) + List<OLogMessage> messages = DBController.get("message", DBMessage.class) .getMessagesFromUser(user.getName(), context.getGuild().getName(), 10); EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.BLUE); embed.setTimestamp(OffsetDateTime.now()); - for (MMessage message1 : messages) { + for (OLogMessage message1 : messages) { embed.addField( - "Message in channel \"" + message1.getChannelName() + "\" sent on " + "Message in channel \"" + message1.getChannelId() + "\" sent on " + message1.getDateSent(), "" + message1.getMessage(), false); } diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java index 06f0edf..5d11f47 100644 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ b/src/main/java/netneutrality/command/specific/LoggingCommand.java @@ -7,9 +7,9 @@ package netneutrality.command.specific; */ import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.context.CommandContext; public class LoggingCommand extends AbstractCommand { diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java new file mode 100644 index 0000000..44720d0 --- /dev/null +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -0,0 +1,279 @@ +package netneutrality.core; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.NetNeutrality; +import netneutrality.db.DBController; +import netneutrality.db.controllers.DBMessage; +import netneutrality.db.entities.OBlacklist; +import netneutrality.db.entities.OGuild; +import netneutrality.db.entities.OGuildSetting; +import netneutrality.handler.ratelimiter.IMessageRateLimiter; +import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; +import netneutrality.utils.JpaUtils; +import netneutrality.utils.MessageFunction; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class GuildManager { + + public enum Settings { + MUSIC_ROLE("MUSIC_ROLE", ""), + MUSIC_CHANNEL("MUSIC_CHANNEL", ""), + MUSIC_VOLUME("MUSIC_VOLUME", "30"), + BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); + + private final String name; + private final String defaultValue; + + Settings(String name, String defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public String getDefaultValue() { + return defaultValue; + } + } + + private static final Logger logger = LoggerFactory.getLogger(GuildManager.class); + private static final Map<String, GuildManager> managers = new ConcurrentHashMap<>(); + private static final SessionFactory sessionFactory = SessionManager.getSessionFactory(); + private final Map<String, String> settingsCache = new HashMap<>(); + private final Set<String> blacklistCache = new HashSet<>(); + private final Guild guild; + private OGuild guildEntity; + private final IMessageRateLimiter rateLimiter; + + private GuildManager(Guild guild) { + this.guild = guild; + this.guildEntity = loadGuildFromDb(guild.getId()); + this.rateLimiter = new MessageRateLimiterImpl(); + + managers.put(guild.getId(), this); + reloadBlacklistCache(true); + } + + private GuildManager(String guildId) { + Guild temp = NetNeutrality.getJDA().getGuildById(guildId); + if (temp == null) + throw new IllegalArgumentException("Guild does not exist in current cache"); + + this.guild = temp; + this.guildEntity = loadGuildFromDb(guild.getId()); + this.rateLimiter = new MessageRateLimiterImpl(); + + managers.put(guild.getId(), this); + reloadBlacklistCache(true); + } + + public static GuildManager getManager(Guild guild) { + if (managers.containsKey(guild.getId())) { + return managers.get(guild.getId()); + } else { + return new GuildManager(guild); + } + } + + public static GuildManager getManager(String guildId) { + if (managers.containsKey(guildId)) { + return managers.get(guildId); + } else { + return new GuildManager(guildId); + } + } + + // Getter + public static Map<String, GuildManager> getManagers() { + return managers; + } + + public boolean isLoggingEnabled() { + return guildEntity.getLogging(); + } + + public boolean isDebugEnabled() { + return guildEntity.getDebug(); + } + + public IMessageRateLimiter getRateLimiter() { + return rateLimiter; + } + + public Guild getGuild() { + return guild; + } + + public OGuild getGuildEntity() { + return guildEntity; + } + + public Set<String> getBlacklistCache() { + return blacklistCache; + } + + public Map<String, String> getSettings() { + return settingsCache; + } + + public String getSetting(Settings setting) { + String value = settingsCache.get(setting.getName()); + + if (value == null) { + setSettingValue(setting, null); + value = setting.getDefaultValue(); + } + + return value; + } + + public void setSettingValue(Settings setting, String value) { + Session session = sessionFactory.openSession(); + session.load(guildEntity, guildEntity.getGuildId()); + + if (value == null || value.isEmpty()) { + value = setting.getDefaultValue(); + } + + OGuildSetting oGuildSetting = guildEntity.getSettingByName(setting.getName()); + + session.beginTransaction(); + if (oGuildSetting == null) { + oGuildSetting = new OGuildSetting(); + oGuildSetting.setGuild(guildEntity); + oGuildSetting.setName(setting.getName()); + oGuildSetting.setValue(value); + session.save(oGuildSetting); + } else { + oGuildSetting.setValue(value); + session.update(oGuildSetting); + } + + session.getTransaction().commit(); + + reloadSettingsCache(false); + session.close(); + } + + public static boolean reloadSettingsForGuild(String guildId) { + GuildManager manager = GuildManager.getManager(guildId); + manager.reloadSettingsCache(true); + + return true; + } + + public static boolean reloadSettingsForGuild(Guild guild) { + GuildManager manager = GuildManager.getManager(guild.getId()); + manager.reloadSettingsCache(true); + + return true; + } + + public void reloadSettingsCache(boolean close) { + logger.debug("Reloading settings cache for guild: " + guild.getId()); + settingsCache.clear(); + + Session session = sessionFactory.openSession(); + JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); + + Set<OGuildSetting> settingSet = guildEntity.getGuildSettings(); + for (OGuildSetting setting : settingSet) { + settingsCache.put(setting.getName(), setting.getValue()); + } + + if (close) + session.close(); + } + + public void reloadBlacklistCache(boolean close) { + logger.debug("Reloading blacklist cache for guild: " + guild.getId()); + blacklistCache.clear(); + + Session session = sessionFactory.openSession(); + JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); + + Set<OBlacklist> oBlacklistSet = guildEntity.getBlacklists(); + for (OBlacklist bl : oBlacklistSet) { + if (bl.getEnabled()) { + blacklistCache.add(bl.getWord()); + } + } + + if (close) + session.close(); + } + + public void checkAndLogMessage(Message message, Member member, TextChannel channel) { + if (isLoggingEnabled()) { + DBController.get("message", DBMessage.class).log(this, channel, member, message); + } + } + + public void checkBlacklist(Message message, TextChannel channel) { + MessageFunction.testMessageAgainstBlacklist(message, channel, blacklistCache); + } + + private OGuild loadGuildFromDb(String guildId) { + Session session = sessionFactory.openSession(); + OGuild entity = session.get(OGuild.class, guildId); + + if (entity == null) { + logger.debug("Guild[{}] doesn't exist in DB, creating entity..", guildId); + session.beginTransaction(); + entity = new OGuild(); + entity.setGuildId(guildId); + + session.save(entity); + session.getTransaction().commit(); + + handleJoinEvent(); + } + + session.close(); + return entity; + } + + public void handleJoinEvent() { + guild.getTextChannels() + .stream() + .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .forEach(textChannel -> textChannel.sendMessage("Error logging enabled on channel " + textChannel.getAsMention()).queue()); + + } + + public void reloadEntity() { + this.guildEntity = loadGuildFromDb(guild.getId()); + } + + public void removeFromDB() { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + + session.delete(guildEntity); + session.getTransaction().commit(); + session.close(); + + managers.remove(guild.getId()); + } + +} diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java similarity index 89% rename from src/main/java/netneutrality/handler/LogHandler.java rename to src/main/java/netneutrality/core/LogHandler.java index aa72bc6..fee6ab4 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler; +package netneutrality.core; /* * Copyright (c) anthorob * @@ -6,17 +6,15 @@ package netneutrality.handler; * https://discord.gg/CdFcyQ */ +import io.sentry.Sentry; import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.GuildManager; -import netneutrality.command.CommandContext; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.sql.SQLException; - public class LogHandler { private final static Logger logger = LoggerFactory.getLogger(LogHandler.class); @@ -27,15 +25,15 @@ public class LogHandler { * @param e The exceptions to log */ public static void log(Exception e) { - if (e instanceof CommandErrorException) { sendMessageToChannel((CommandErrorException) e); } else if (e instanceof CommandExecutionException) { + Sentry.captureException(e); + logInternally((CommandExecutionException) e); tryLogToDebugChannel((CommandExecutionException) e); - } else if (e instanceof SQLException) { - logger.error(e.getMessage(), e); } else { + Sentry.captureException(e); logger.error(e.getMessage(), e); } @@ -55,11 +53,6 @@ public class LogHandler { logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage(), error); } - private static void tryLogToAllChannels(SQLException error) { - - - } - private static void tryLogToDebugChannel(CommandExecutionException error) { CommandContext context = error.getCommandContext(); diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java new file mode 100644 index 0000000..69e990d --- /dev/null +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -0,0 +1,66 @@ +package netneutrality.core; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import io.sentry.Sentry; +import netneutrality.utils.Settings; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Environment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +public class SessionManager { + private final static Logger logger = LoggerFactory.getLogger(SessionManager.class); + private static StandardServiceRegistry registry; + private static SessionFactory sessionFactory; + + public static SessionFactory getSessionFactory() { + if (sessionFactory == null) { + try { + StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder().configure(); + Map<String, String> settings = new HashMap<>(); + String dbName = Settings.getInstance().get("MYSQL_DATABASE", "netneutrality"); + String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); + String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); + String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); + logger.info(String.format("Connecting to database '%s' at %s:3306 with user '%s'", dbName, dbHost, dbUser)); + + settings.put(Environment.URL, String.format("jdbc:mysql://%s:3306/%s", dbHost, dbName)); + settings.put(Environment.USER, dbUser); + settings.put(Environment.PASS, dbPass); + registryBuilder.applySettings(settings); + + registry = registryBuilder.build(); + MetadataSources sources = new MetadataSources(registry); + Metadata metadata = sources.getMetadataBuilder().build(); + sessionFactory = metadata.getSessionFactoryBuilder().build(); + + } catch (Exception e) { + Sentry.captureException(e); + + shutdown(); + logger.error("Error connecting to database. Shutting down..", e); + System.exit(1); + } + } + + return sessionFactory; + } + + public static void shutdown() { + if (registry != null) { + StandardServiceRegistryBuilder.destroy(registry); + } + } +} diff --git a/src/main/java/netneutrality/utils/UnsafeShutdown.java b/src/main/java/netneutrality/core/UnsafeShutdown.java similarity index 91% rename from src/main/java/netneutrality/utils/UnsafeShutdown.java rename to src/main/java/netneutrality/core/UnsafeShutdown.java index 1b2d719..9b5e016 100644 --- a/src/main/java/netneutrality/utils/UnsafeShutdown.java +++ b/src/main/java/netneutrality/core/UnsafeShutdown.java @@ -1,4 +1,4 @@ -package netneutrality.utils;/* +package netneutrality.core;/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -6,7 +6,13 @@ package netneutrality.utils;/* */ -import netneutrality.GuildManager; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + import netneutrality.music.MusicManager; import netneutrality.music.TrackScheduler; import org.json.JSONArray; @@ -15,7 +21,6 @@ import org.json.JSONObject; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.nio.file.Files; import java.util.Map; public class UnsafeShutdown { diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java similarity index 81% rename from src/main/java/netneutrality/command/CommandContext.java rename to src/main/java/netneutrality/core/context/CommandContext.java index e52b711..ce3ebff 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -1,4 +1,4 @@ -package netneutrality.command; +package netneutrality.core.context; /* * Copyright (c) anthorob * @@ -6,14 +6,19 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ +import io.sentry.Breadcrumb; +import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; -import netneutrality.ThreadManager; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandUsage; +import netneutrality.core.GuildManager; +import netneutrality.core.LogHandler; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; -import netneutrality.handler.LogHandler; +import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; @@ -39,6 +44,12 @@ public class CommandContext { this.channel = channel; this.user = user; this.jda = jda; + + io.sentry.protocol.User sentryUser = new io.sentry.protocol.User(); + sentryUser.setId(member.getId()); + sentryUser.setUsername(member.getEffectiveName()); + Sentry.setUser(sentryUser); + Sentry.addBreadcrumb(Breadcrumb.info("New context for message id " + message.getId())); } public static CommandContext createContext(GuildMessageReceivedEvent event) { @@ -104,6 +115,10 @@ public class CommandContext { return command; } + public GuildManager getGuildManager() { + return GuildManager.getManager(guild); + } + public void reply(CommandUsage usage) { reply(new MessageBuilder(usage.toString()).build()); } @@ -154,6 +169,15 @@ public class CommandContext { this.command = command; //TODO: Add usage check + Sentry.configureScope(scope -> { + scope.setContexts("command", command.getCommandName()); + scope.setContexts("isAdmin", UserFunction.isAdmin(member)); + scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); + scope.setTag("channel", channel.getId()); + scope.setTag("message", message.getId()); + scope.setTag("guild", guild.getId()); + }); + try { if (command.needAdmin()) { if (!UserFunction.isAdmin(member)) { diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/netneutrality/db/AbstractController.java index d2c2f47..7b8deae 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/netneutrality/db/AbstractController.java @@ -7,27 +7,25 @@ package netneutrality.db; * https://discord.gg/CdFcyQ */ +import netneutrality.core.SessionManager; +import org.hibernate.SessionFactory; + public abstract class AbstractController { - protected MysqlDatabase database; + protected SessionFactory sessionFactory; /** - * The controller name to be used in {@link DBController#get(String controller)} method + * The controller name to be used in {@link DBController#get(String controller, Class returnType)} method * * @return String */ public abstract String getControllerName(); - /** - * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class - * - * @return {@link MysqlDatabase} - */ - protected MysqlDatabase getDatabase() { - return database; + public AbstractController() { + sessionFactory = SessionManager.getSessionFactory(); } - - protected void setDatabase(MysqlDatabase database) { - this.database = database; + + protected SessionFactory getSessionFactory() { + return sessionFactory; } } diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java deleted file mode 100644 index 283abdb..0000000 --- a/src/main/java/netneutrality/db/AsyncMySqlAction.java +++ /dev/null @@ -1,66 +0,0 @@ -package netneutrality.db; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.ThreadManager; -import netneutrality.db.models.MTableModel; - -import java.sql.ResultSet; -import java.util.concurrent.*; -import java.util.function.Consumer; - -public class AsyncMySqlAction { - - private final ExecutorService executor = ThreadManager.getExecutor("db-action", ThreadManager.ExecutorType.SINGLE); - private final String sqlString; - private final Object[] params; - private final MysqlDatabase.CommandType type; - private final MysqlDatabase db; - public final String tableName; - - public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) { - this.db = db; - this.sqlString = sql; - this.params = params; - this.tableName = sqlString.toUpperCase().split(" ")[1]; - - type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]); - } - - public void async() { - async( success -> {} ); - } - - public void async(Consumer<MTableModel> success) { - - switch (type) { - case INSERT -> executor.submit(() -> success.accept(new MTableModel(db.insert(this.sqlString, this.params)))); - case UPDATE -> executor.submit(() -> success.accept(new MTableModel(db.update(this.sqlString, this.params)))); - case DELETE -> executor.submit(() -> success.accept(new MTableModel(db.delete(this.sqlString, this.params)))); - case SELECT -> executor.submit(() -> { - ResultSet result = db.prepareAndExecute(this.sqlString, this.params); - - success.accept(MysqlDatabase.convertToTableModel(result, tableName)); - }); - } - } - - public MTableModel blocking() { - MTableModel table; - - table = switch (type) { - case INSERT -> new MTableModel(db.insert(this.sqlString, this.params)); - case UPDATE -> new MTableModel(db.update(this.sqlString, this.params)); - case DELETE -> new MTableModel(db.delete(this.sqlString, this.params)); - case SELECT -> db.prepareAndExecute(this.sqlString, this.tableName, this.params); - }; - - return table; - } - -} diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index a2eadb9..2476b64 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -7,20 +7,17 @@ package netneutrality.db; * https://discord.gg/CdFcyQ */ -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Set; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import netneutrality.ThreadManager; -import netneutrality.utils.Settings; +import netneutrality.core.SessionManager; +import netneutrality.thread.ThreadManager; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Set; + /** * When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class * A simple thread can't be used in this case because overlapping actions might happen and won't be executed. @@ -31,59 +28,43 @@ public class DBController { * A map that contains all the controllers currently loaded */ private final static HashMap<String, AbstractController> controllers = new HashMap<>(); - private final static Logger logger = LoggerFactory.getLogger(DBController.class); - private static final MysqlDatabase database = new MysqlDatabase(Settings.getInstance().get("MYSQL_DATABASE", "netneutrality")); /** * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method * @return {@link AbstractController} The class with an AbstractController type */ - public static AbstractController get(String controller) { + @SuppressWarnings("unchecked") + public static <T> T get(String controller, Class<T> returnType) { + if (returnType == null) + throw new IllegalArgumentException("return type is null"); if (controllers.isEmpty()) init(); - if (database.isClosed()) - database.reconnect(); - if (controllers.containsKey(controller)) { - return controllers.get(controller); - } - - return null; - } - - public static MysqlDatabase get() { - if (database.isClosed()) { - logger.info("Reconnecting to database.."); - database.reconnect(); - } - - return database; + return (T) controllers.get(controller); + } else + throw new RuntimeException("Error getting database controller"); } public static void shutdown() { - try { - database.close(); - } catch (SQLException | NullPointerException ignored) { } + SessionManager.shutdown(); } /** - * Optional, will be called if the method {@link #get(String) get()} is used + * Optional, will be called if the method {@link #get(String, Class) get()} is used */ public static void init() { if (controllers.isEmpty()) loadControllers(); - - ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED)) - .scheduleWithFixedDelay(() -> DBController.get().query("SELECT 1;"), 0, 120, TimeUnit.SECONDS); } /** * Loads all the controllers which extends {@link AbstractController} */ private static void loadControllers() { + //TODO: to delete logger.info("Loading databases controllers.."); Reflections reflections = new Reflections("netneutrality.db.controllers"); @@ -96,7 +77,6 @@ public class DBController { } AbstractController c = s.getConstructor().newInstance(); - c.setDatabase(database); if (!controllers.containsKey(c.getControllerName())) { controllers.put(c.getControllerName(), c); diff --git a/src/main/java/netneutrality/db/MysqlConnector.java b/src/main/java/netneutrality/db/MysqlConnector.java deleted file mode 100644 index f1f8ab8..0000000 --- a/src/main/java/netneutrality/db/MysqlConnector.java +++ /dev/null @@ -1,58 +0,0 @@ -package netneutrality.db; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import com.mysql.cj.jdbc.MysqlDataSource; - -import java.sql.Connection; -import java.sql.SQLException; - -public class MysqlConnector { - - private final String dbName; - private final String dbUser; - private final String dbHost; - private final String dbPass; - private Connection c; - - MysqlConnector(String dbName, String dbUser, String dbHost, String dbPass) { - this.dbName = dbName; - this.dbUser = dbUser; - this.dbHost = dbHost; - this.dbPass = dbPass; - } - - /** - * Connect to a MySQL instance using the provided information - * - * @return {@link MysqlConnector} - */ - public MysqlConnector connect() throws SQLException { - MysqlDataSource dataSource = new MysqlDataSource(); - String jdbc = "jdbc:mysql://" + dbHost + ":3306/" + dbName; - - dataSource.setURL(jdbc); - dataSource.setUser(dbUser); - dataSource.setPassword(dbPass); - dataSource.setAutoReconnect(true); - dataSource.setConnectTimeout(5000); - c = dataSource.getConnection(); - - return this; - } - - /** - * Get the MySQL connection. Must call {@link #connect()} beforehand. - * - * @return {@link Connection} - */ - public Connection getConnection() { - return c; - } - -} diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java deleted file mode 100644 index 4033f14..0000000 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ /dev/null @@ -1,293 +0,0 @@ -package netneutrality.db; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.sql.Types; -import java.util.Calendar; - -import netneutrality.db.models.MRowModel; -import netneutrality.db.models.MTableModel; -import netneutrality.exceptions.UnimplementedParameterException; -import netneutrality.handler.LogHandler; -import netneutrality.utils.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MysqlDatabase { - - private final static Logger logger = LoggerFactory.getLogger(MysqlDatabase.class); - private final static Object dmlLock = new Object(); - protected Connection connection; - private final String dbName; - - protected enum CommandType { - SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"); - - private final String type; - - CommandType(String type) { - this.type = type; - } - - public static CommandType stringToType(String str) { - return CommandType.valueOf(str); - } - - public String getType() { - return type; - } - } - - protected MysqlDatabase(String dbName) { - this.dbName = dbName; - String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); - String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); - String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); - - try { - logger.info(String.format("Connecting to database '%1$s' at %2$s:3306 with user '%3$s'", dbName, dbHost, dbUser)); - connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); - } catch (SQLException e) { - logger.error("Error connecting to database. Shutting down..", e); - System.exit(-1); - } - } - - /** - * Execute a simple query without any parameters. - * Example : SELECT * FROM table - * - * @param query The SQL query to execute - * @return {@link ResultSet} - */ - protected ResultSet query(String query) { - Statement stmt; - try { - stmt = connection.createStatement(); - return stmt.executeQuery(query); - } catch (SQLException e) { - LogHandler.log(e); - } - - return null; - } - - /** - * Execute an UPDATE statement with the specified parameters. - * In the SQL query, where there is a parameter to be included, you need to replace it with ? - * - * @param sql The SQL query to execute - * @param params The parameters to include in the query - */ - protected int update(String sql, Object... params) { - return executeUpdate(sql, params); - } - - /** - * Execute an INSERT statement with the specified parameters. - * In the SQL query, where there is a parameter to be included, you need to replace it with ? - * - * @param sql The SQL query to execute - * @param params The parameters to include in the query - * @return an integer of how many row were affected - */ - protected int insert(String sql, Object... params) { - return executeUpdate(sql, params); - } - - /** - * Execute a DELETE statement with the specified parameters. - * In the SQL query, where there is a parameter to be included, you need to replace it with ? - * - * @param sql The SQL query to execute - * @param params The parameters to include in the query - * @return an integer of how many row were affected - */ - protected int delete(String sql, Object... params) { - return executeUpdate(sql, params); - } - - private int executeUpdate(String sql, Object[] params) { - logger.debug("Query: " + sql); - - synchronized (dmlLock) { - try { - PreparedStatement query = connection.prepareStatement(sql); - resolveParameters(query, params); - return query.executeUpdate(); - } catch (SQLException e) { - LogHandler.log(e); - } - - return -1; - } - - } - - public boolean exists(String table, String key, String value) { - return !prepareAndExecuteAsync(String.format("SELECT 1 FROM %s WHERE %s = ?", table, key), value).blocking().isEmpty(); - } - - /** - * Execute a SELECT statement with the specified parameters. - * In the SQL query, where there is a parameter to be included, you need to replace it with ? - * - * @param sql The SQL query to execute - * @param params The parameters to include in the query - * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet, String)} - */ - protected ResultSet prepareAndExecute(String sql, Object... params) { - - try { - PreparedStatement query = connection.prepareStatement(sql); - resolveParameters(query, params); - return query.executeQuery(); - } catch (SQLException e) { - logger.error(e.getMessage(), e); - } - - return null; - } - - protected MTableModel prepareAndExecute(String sql, String tableName, Object... params) { - - try { - PreparedStatement query = connection.prepareStatement(sql); - resolveParameters(query, params); - return convertToTableModel(query.executeQuery(), tableName); - } catch (SQLException e) { - logger.error(e.getMessage(), e); - } - - return null; - } - - /** - * Execute a SELECT statement with the specified parameters. - * In the SQL query, where there is a parameter to be included, you need to replace it with ? - * - * @param sql The SQL query to execute - * @param params The parameters to include in the query - * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet, String)} - */ - public AsyncMySqlAction prepareAndExecuteAsync(String sql, Object... params) { - return new AsyncMySqlAction(this, sql, params); - } - - /** - * Insert parameters (specified with a ?) in the SQL statement - * Taken from https://github.com/Kaaz/DiscordBot/blob/master/src/main/java/emily/db/MySQLAdapter.java#resolveParameters - * - * @param query The PreparedStatement object - * @param params The parameters to be included in the prepared statement - */ - private void resolveParameters(PreparedStatement query, Object... params) throws SQLException { - int index = 1; - for (Object p : params) { - if (p instanceof String) { - query.setString(index, (String) p); - } else if (p instanceof Integer) { - query.setInt(index, (int) p); - } else if (p instanceof Boolean) { - query.setBoolean(index, (Boolean) p); - } else if (p instanceof Long) { - query.setLong(index, (Long) p); - } else if (p instanceof Double) { - query.setDouble(index, (double) p); - } else if (p instanceof java.sql.Date date) { - query.setDate(index, date); - } else if (p instanceof java.util.Date date) { - Timestamp ts = new Timestamp(date.getTime()); - query.setTimestamp(index, ts); - } else if (p instanceof Calendar cal) { - Timestamp ts = new Timestamp(cal.getTimeInMillis()); - query.setTimestamp(index, ts); - } else if (p == null) { - query.setNull(index, Types.NULL); - } else { - throw new UnimplementedParameterException(p, index); - } - index++; - } - } - - /** - * Close the MySQL connection - */ - public void close() throws SQLException { - System.out.println("Closing database..."); - connection.close(); - } - - /** - * Recreate and reconnect the MySQL connection. - */ - public void reconnect() { - String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); - String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); - String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); - - try { - logger.info("Reconnecting to database..."); - connection = new MysqlConnector(dbName, dbUser, dbHost, dbPass).connect().getConnection(); - } catch (SQLException e) { - logger.error("Error connecting to database. Shutting down.."); - System.exit(0); - } - } - - /** - * Check if the database is closed. - * - * @return the connection status - */ - public boolean isClosed() { - try { - return connection.isClosed(); - } catch (SQLException e) { - return true; - } - } - - /** - * @param rs The ResultSet returned by the SELECT query - * @return a {@link MTableModel} with the appropriate column and rows - */ - protected static MTableModel convertToTableModel(ResultSet rs, String tableName) { - MTableModel table = new MTableModel(tableName); - - try { - ResultSetMetaData metadata = rs.getMetaData(); - - for (int i = 1; i < metadata.getColumnCount() + 1; i++) { - table.addColumn(metadata.getColumnName(i)); - } - - while (rs.next()) { - MRowModel row = new MRowModel(rs.getRow() - 1); - for (int i = 0; i < metadata.getColumnCount(); i++) { - row.addColumnToRow(rs.getObject(i + 1)); - } - table.addRow(row); - } - - } catch (SQLException e) { - e.printStackTrace(); - } - - return table; - } - -} diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index f5ebf0f..9f381e7 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -1,5 +1,4 @@ package netneutrality.db.controllers; - /* * Copyright (c) anthorob * @@ -7,73 +6,127 @@ package netneutrality.db.controllers; * https://discord.gg/CdFcyQ */ -import java.util.ArrayList; - +import netneutrality.core.GuildManager; +import netneutrality.core.context.CommandContext; import netneutrality.db.AbstractController; -import netneutrality.db.models.MBlacklist; -import netneutrality.db.models.MTableModel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import netneutrality.db.entities.OBlacklist; +import netneutrality.db.entities.OGuild; +import netneutrality.utils.JpaUtils; +import org.hibernate.Session; +import org.hibernate.query.Query; + +import java.util.ArrayList; public class DBBlacklist extends AbstractController { - private final Logger logger = LoggerFactory.getLogger(DBBlacklist.class); + public void add(String word, CommandContext context) { + GuildManager guildManager = GuildManager.getManager(context.getGuild()); + Session session = getSessionFactory().openSession(); - public boolean add(MBlacklist obj) { - if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { - return database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getServerId(), obj.getWord(), obj.isEnabled(), obj.getCreatorId()).blocking().isSuccess(); + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); + + if (bl == null) { + session.beginTransaction(); + bl = new OBlacklist(); + bl.setGuild(guildManager.getGuildEntity()); + bl.setCreatorId(context.getGuildUser().getId()); + bl.setWord(word); + bl.setEnabled(true); + + session.save(bl); + session.getTransaction().commit(); + guildManager.reloadBlacklistCache(false); + context.reply(String.format("Added the word [%s] to the blacklist.", word)); + } else { + context.reply("Word is already blacklisted"); } - return false; + session.close(); + } - public boolean delete(String word, String serverId) { - if (isAlreadyBlacklisted(word, serverId)) { - return database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).blocking().isSuccess(); + public void delete(String word, CommandContext context) { + GuildManager guildManager = GuildManager.getManager(context.getGuild()); + Session session = getSessionFactory().openSession(); + + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); + if (bl != null) { + session.beginTransaction(); + + session.delete(bl); + session.getTransaction().commit(); + guildManager.reloadBlacklistCache(false); + context.reply("Removed the word [%s] from the blacklist.", word); + } else { + context.reply("Can't delete word because it doesn't exist"); } - return false; + session.close(); } - public boolean enable(String word, String serverId) { - if (isAlreadyBlacklisted(word, serverId)) { - return database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 1 WHERE word = ? AND guild_id = ?", word, serverId).blocking().isSuccess(); + public void enable(String word, CommandContext context) { + GuildManager guildManager = GuildManager.getManager(context.getGuild()); + Session session = getSessionFactory().openSession(); + + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); + if (bl != null && !bl.getEnabled()) { + session.beginTransaction(); + bl.setEnabled(true); + + session.update(bl); + session.getTransaction().commit(); + guildManager.reloadBlacklistCache(false); + context.reply("Enabled the word [%s] for the blacklist.", word); + } else { + context.reply("Either word doesn't exist or is already enabled"); } - return false; + session.close(); } - public boolean disable(String word, String serverId) { - if (isAlreadyBlacklisted(word, serverId)) { - return database.prepareAndExecuteAsync("UPDATE blacklist SET enabled = 0 WHERE word = ? AND guild_id = ?", word, serverId).blocking().isSuccess(); + public void disable(String word, CommandContext context) { + GuildManager guildManager = GuildManager.getManager(context.getGuild()); + Session session = getSessionFactory().openSession(); + + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); + if (bl != null && bl.getEnabled()) { + session.beginTransaction(); + bl.setEnabled(false); + + session.update(bl); + session.getTransaction().commit(); + guildManager.reloadBlacklistCache(false); + context.reply("Disabled the word [%s] for the blacklist.", word); + } else { + context.reply("Either word doesn't exist or is already disabled"); } - return false; + session.close(); } - public ArrayList<MBlacklist> getBlacklistFromServer(String serverId) { + public ArrayList<OBlacklist> getBlacklistForGuild(CommandContext context) { + GuildManager guildManager = GuildManager.getManager(context.getGuild()); + Session session = getSessionFactory().openSession(); - MTableModel model = database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE guild_id = ? AND enabled = 1", serverId).blocking(); - ArrayList<MBlacklist> output = new ArrayList<>(); + OGuild guildEntity = guildManager.getGuildEntity(); + JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); - if (model.getNbRows() > 0) { + ArrayList<OBlacklist> blacklists = new ArrayList<>(guildEntity.getBlacklists()); + session.close(); - for (int row = 0; row < model.getNbRows(); row++) { - MBlacklist bl = new MBlacklist(model.getRow(row)); - output.add(bl); - } - } - - return output; + return blacklists; } - private boolean isAlreadyBlacklisted(String word, String serverId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).blocking(); - if (!table.isEmpty()) { - return ((int) table.getRowModel(0).getItem(0)) != 0; - } + private OBlacklist getWordFromDb(String word, String guildId) { + Session session = getSessionFactory().openSession(); - return false; + Query<OBlacklist> query = session.createNamedQuery("OBlacklist.findByWordEqualsIgnoreCaseAndGuild_GuildIdEquals", OBlacklist.class); + query.setParameter("guildId", guildId); + query.setParameter("word", word); + OBlacklist blacklist = query.uniqueResult(); + + session.close(); + return blacklist; } @Override diff --git a/src/main/java/netneutrality/db/controllers/DBGuild.java b/src/main/java/netneutrality/db/controllers/DBGuild.java deleted file mode 100644 index 5619d2b..0000000 --- a/src/main/java/netneutrality/db/controllers/DBGuild.java +++ /dev/null @@ -1,31 +0,0 @@ -package netneutrality.db.controllers; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.Guild; -import netneutrality.db.AbstractController; - -public class DBGuild extends AbstractController { - - public void insertGuildInDB(Guild g) { - if (!database.exists("guilds", "guild_id", g.getId())) { - database.prepareAndExecuteAsync("INSERT INTO guilds VALUES(?, ?, ?, ?)", g.getId(), "0", null, null).blocking(); - } - } - - public void removeGuildInDB(Guild g) { - if (database.exists("guilds", "guild_id", g.getId())) { - database.prepareAndExecuteAsync("DELETE FROM guilds WHERE guild_id = ?", g.getId()).blocking(); - } - } - - @Override - public String getControllerName() { - return "guild"; - } -} diff --git a/src/main/java/netneutrality/db/controllers/DBLogging.java b/src/main/java/netneutrality/db/controllers/DBLogging.java deleted file mode 100644 index bb2b93d..0000000 --- a/src/main/java/netneutrality/db/controllers/DBLogging.java +++ /dev/null @@ -1,33 +0,0 @@ -package netneutrality.db.controllers; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.db.AbstractController; -import netneutrality.db.models.MTableModel; - -public class DBLogging extends AbstractController { - - public void setupLog(String serverId, String channelId) { - database.prepareAndExecuteAsync("INSERT INTO logging VALUES(?,?,?)", serverId, channelId, true).blocking(); - } - - public void toggleLog(String serverId, String channelId) { - database.prepareAndExecuteAsync("UPDATE logging SET enabled = NOT enabled WHERE guild_id = ? AND channelId = ?", serverId, channelId).blocking(); - } - - public boolean isLoggingEnabled(String serverId, String channelId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT enabled FROM logging WHERE guild_id = ? AND channelId = ?", serverId, channelId).blocking(); - - return (Boolean) table.getRow(0).get(0); - } - - @Override - public String getControllerName() { - return "logging"; - } -} diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 5690d6f..3978b45 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -7,74 +7,94 @@ package netneutrality.db.controllers; * https://discord.gg/CdFcyQ */ -import java.util.ArrayList; -import java.util.Date; - -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.core.GuildManager; import netneutrality.db.AbstractController; -import netneutrality.db.DBController; -import netneutrality.db.MysqlDatabase; -import netneutrality.db.models.MMessage; -import netneutrality.db.models.MTableModel; - +import netneutrality.db.entities.OLogMessage; +import org.hibernate.Session; +import org.hibernate.query.Query; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + public class DBMessage extends AbstractController { private final static Logger logger = LoggerFactory.getLogger(DBMessage.class); - /** - * Returns an instance of {@link MysqlDatabase} with the database name as set in the {@link DBController} class - * - * @return {@link MysqlDatabase} - */ - public MysqlDatabase getDatabase() { - return database; - } + public void log(GuildManager guildManager, TextChannel channel, Member author, Message message) { + Session session = getSessionFactory().openSession(); + session.beginTransaction(); - public void log(Guild guild, TextChannel channel, Member author, Message message) { - String guildId = guild.getId(); - String channelId = channel.getId(); - String authorId = author.getId(); - Date dateSent = new Date(message.getTimeCreated().toInstant().toEpochMilli()); - String messageId = message.getId(); - String msg = message.getContentRaw().trim(); + OLogMessage logMessage = new OLogMessage(); + logMessage.setGuild(guildManager.getGuildEntity()); + logMessage.setMessageId(message.getId()); + logMessage.setMessage(message.getContentRaw().trim()); + logMessage.setChannelId(channel.getId()); + logMessage.setUserId(author.getId()); + logMessage.setDateSent(message.getTimeCreated().toInstant()); - database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", guildId, channelId, authorId, dateSent, messageId, msg, null).blocking(); + session.save(logMessage); + session.getTransaction().commit(); + session.close(); } public void logEdit(String messageId, String newMessage) { - database.prepareAndExecuteAsync("UPDATE log_message SET edited_message = ? WHERE message_id = ?", newMessage, messageId).blocking(); + Session session = getSessionFactory().openSession(); + Query<OLogMessage> query = session.createNamedQuery("OLogMessage.findByMessageIdEquals", OLogMessage.class); + query.setParameter("messageId", messageId); - } + OLogMessage message = query.uniqueResult(); + if (message != null) { + session.beginTransaction(); + message.setEditedMessage(newMessage); - public MMessage getMessage(String messageId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE message_id = ?", messageId).blocking(); - if (table.getNbRows() > 0) { - return new MMessage(table.getRowModel(0)); + session.update(message); + session.getTransaction().commit(); } - return null; + session.close(); } - public ArrayList<MMessage> getMessagesFromUser(String username, String serverName, int max) { - ArrayList<MMessage> messages = new ArrayList<>(); + public OLogMessage getMessage(String messageId) { + Session session = getSessionFactory().openSession(); + Query<OLogMessage> query = session.createNamedQuery("OLogMessage.findByMessageIdEquals", OLogMessage.class); + query.setParameter("messageId", messageId); - MTableModel table = database.prepareAndExecuteAsync("SELECT * FROM log_message WHERE user_id = ? AND guild_id = ? ORDER BY date_sent DESC LIMIT ?", username, serverName, max).blocking(); - if (table.getNbRows() > 0) { - for (int row = 0; row < max; row++) { - messages.add(new MMessage(table.getRowModel(row))); - } - } + OLogMessage message = query.uniqueResult(); + session.close(); + + return message; + } + + public List<OLogMessage> getMessagesFromUser(String userId, String guildId, int max) { + Session session = getSessionFactory().openSession(); + Query<OLogMessage> query = session.createNamedQuery("OLogMessage.findByUserIdEquals", OLogMessage.class); + query.setParameter("guildId", guildId); + query.setParameter("userId", userId); + query.setMaxResults(max); + + List<OLogMessage> messages = query.getResultList(); + session.close(); return messages; } public String getMessageString(String messageId) { - MTableModel table = database.prepareAndExecuteAsync("SELECT message FROM log_message WHERE message_id = ?", messageId).blocking(); + Session session = getSessionFactory().openSession(); + Query<OLogMessage> query = session.createNamedQuery("OLogMessage.findByMessageIdEquals", OLogMessage.class); + query.setParameter("messageId", messageId); + + OLogMessage message = query.uniqueResult(); + session.close(); + + if (message == null) + return null; + else + return message.getMessage(); - return (String) table.getRowModel(0).getItem(0); } diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java deleted file mode 100644 index 37ea1df..0000000 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ /dev/null @@ -1,54 +0,0 @@ -package netneutrality.db.entities; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.db.DBController; -import netneutrality.db.models.MTableModel; -import netneutrality.handler.LogHandler; - -public abstract class AbstractEntity implements EntityInterface { - private final String primaryKey; - private final String[] primaryKeys; - protected MTableModel table; - - - public AbstractEntity(String primaryKey, String... primaryKeys) throws ArrayIndexOutOfBoundsException { - this.primaryKey = primaryKey; - this.primaryKeys = primaryKeys; - - fillTableModel(); - - try { - if (!table.isEmpty()) - convertFromTableModel(table); - } catch (NullPointerException e) { - LogHandler.log("Table structure does not match expected variables", e); - } - } - - private void fillTableModel() throws ArrayIndexOutOfBoundsException { - StringBuilder whereClause = new StringBuilder(); - for (String pk : getPrimaryKeys()) { - whereClause.append(pk).append(" = ?"); - - //TODO: Fix last and - if (getPrimaryKeys().length > 1) - whereClause.append(" AND "); - } - - String sql = "SELECT * FROM " + getTableName() + " WHERE " + whereClause; - // MusicBot.logger.debug(sql + " - pk: " + primaryKey); - - if (this.primaryKeys.length > 0) - this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey, this.primaryKeys).blocking(); - else - this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey).blocking(); - - } - -} diff --git a/src/main/java/netneutrality/db/entities/EntityInterface.java b/src/main/java/netneutrality/db/entities/EntityInterface.java deleted file mode 100644 index 5f55490..0000000 --- a/src/main/java/netneutrality/db/entities/EntityInterface.java +++ /dev/null @@ -1,21 +0,0 @@ -package netneutrality.db.entities; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.db.models.MTableModel; - -public interface EntityInterface { - - String getTableName(); - String[] getPrimaryKeys(); - boolean exists(); - - - void convertFromTableModel(MTableModel table); - -} diff --git a/src/main/java/netneutrality/db/entities/OBlacklist.java b/src/main/java/netneutrality/db/entities/OBlacklist.java new file mode 100644 index 0000000..36c4715 --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OBlacklist.java @@ -0,0 +1,75 @@ +package netneutrality.db.entities; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import javax.persistence.*; + +@Entity +@Table(name = "blacklist") +@NamedQueries({ + @NamedQuery(name = "OBlacklist.findByWordEqualsIgnoreCaseAndGuild_GuildIdEquals", query = "select o from OBlacklist o where upper(o.word) = upper(:word) and o.guild.guildId = :guildId") +}) +public class OBlacklist { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Integer id; + + @Column(name = "word", nullable = false) + private String word; + + @Column(name = "enabled", nullable = false) + private Boolean enabled = false; + + @Column(name = "creator_id", nullable = false) + private String creatorId; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "guild_id", nullable = false) + private OGuild guild; + + public OGuild getGuild() { + return guild; + } + + public void setGuild(OGuild guild) { + this.guild = guild; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java index 928b922..c7d4659 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -7,72 +7,112 @@ package netneutrality.db.entities; * https://discord.gg/CdFcyQ */ +import javax.persistence.*; +import java.util.LinkedHashSet; +import java.util.Optional; +import java.util.Set; -import netneutrality.GuildManager; -import netneutrality.db.models.MTableModel; +@Entity +@Table(name = "guilds") +public class OGuild { -public class OGuild extends AbstractEntity { + @Id + @Column(name = "guild_id", nullable = false) + private String guildId; - private String guildID; - private boolean logging; - private boolean debug; - private String logchannel; + @Column(name = "logging", nullable = false) + private Boolean logging = false; - private OGuildSetting settings; + @Column(name = "debug", nullable = false) + private Boolean debug = true; - public OGuild(String guildId) { - super(guildId); + @Column(name = "log_channel") + private String logChannel; - this.settings = new OGuildSetting(this); + @OneToMany(mappedBy = "guild") + private Set<OGuildSetting> guildSettings = new LinkedHashSet<>(); + + @OneToMany(mappedBy = "guild") + private Set<OBlacklist> blacklists = new LinkedHashSet<>(); + + @OneToMany(mappedBy = "guild") + private Set<OLogMessage> logMessages = new LinkedHashSet<>(); + + @OneToMany(mappedBy = "guild") + private Set<OLogging> OLoggings = new LinkedHashSet<>(); + + public Set<OLogging> getLoggings() { + return OLoggings; } - public boolean isLogging() { + public void setLoggings(Set<OLogging> OLoggings) { + this.OLoggings = OLoggings; + } + + public Set<OLogMessage> getLogMessages() { + return logMessages; + } + + public void setLogMessages(Set<OLogMessage> logMessages) { + this.logMessages = logMessages; + } + + public Set<OBlacklist> getBlacklists() { + return blacklists; + } + + public void setBlacklists(Set<OBlacklist> blacklists) { + this.blacklists = blacklists; + } + + public Set<OGuildSetting> getGuildSettings() { + return guildSettings; + } + + public void setGuildSettings(Set<OGuildSetting> guildSettings) { + this.guildSettings = guildSettings; + } + + public String getLogChannel() { + return logChannel; + } + + public void setLogChannel(String logChannel) { + this.logChannel = logChannel; + } + + public Boolean getLogging() { return logging; } - public boolean isDebug() { + public void setLogging(Boolean logging) { + this.logging = logging; + } + + public Boolean getDebug() { return debug; } - public String getLogchannel() { - return logchannel; - } - - public void reloadSettings() { - GuildManager.logger.debug("Reloading settings for guild: " + guildID); - this.settings = new OGuildSetting(this); - } - - public String getGuildID() { - return guildID; - } - - public OGuildSetting getSettings() { - return settings; - } - - @Override - public boolean exists() { - return guildID != null; - } - - @Override - public String getTableName() { - return "guilds"; - } - - @Override - public String[] getPrimaryKeys() { - return new String[] {"guild_id"}; + public void setDebug(Boolean debug) { + this.debug = debug; } - @Override - public void convertFromTableModel(MTableModel table) { - this.guildID = (String) table.getRow(0).get(0); - this.logging = ((Integer) table.getRow(0).get(1)) == 1; - this.debug = ((Boolean) table.getRow(0).get(2)); - this.logchannel = (String) table.getRow(0).get(3); - + public String getGuildId() { + return guildId; } -} + + public void setGuildId(String guildId) { + this.guildId = guildId; + } + + public OGuildSetting getSettingByName(String name) { + Optional<OGuildSetting> setting = getGuildSettings() + .stream() + .filter(setting1 -> setting1.getName().equalsIgnoreCase(name)) + .findFirst(); + + return setting.orElse(null); + } + +} \ No newline at end of file diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java index 1888fc2..b2704ca 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -1,73 +1,65 @@ -package netneutrality.db.entities;/* +package netneutrality.db.entities; + +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ * https://discord.gg/CdFcyQ */ -import netneutrality.GuildManager; -import netneutrality.db.models.MRowModel; -import netneutrality.db.models.MTableModel; +import javax.persistence.*; -import java.util.*; +@Entity +@Table(name = "guild_settings") +@NamedQueries({ + @NamedQuery(name = "settings_findByName", query = "select o from OGuildSetting o where o.guild.id = :id and upper(o.name) = upper(:name)") +}) +public class OGuildSetting { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Integer id; -public class OGuildSetting extends AbstractEntity { - private final OGuild guild; - private Map<String, Object> settings; + @Column(name = "name", nullable = false) + private String name; - public OGuildSetting(OGuild OGuild) { - super(OGuild.getGuildID()); + @Lob + @Column(name = "value", nullable = false) + private String value; - this.guild = OGuild; - } + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "guild_id", nullable = false) + private OGuild guild; public OGuild getGuild() { return guild; } - public Map<String, Object> getSettings() { - return settings; + public void setGuild(OGuild guild) { + this.guild = guild; } - public Object getSettingByKey(GuildManager.GuildSetting key) { - if (settings.containsKey(key.getName())) { - return settings.get(key.getName()); - } - - return key.getDefaultValue(); + public String getValue() { + return value; } - @Override - public String getTableName() { - return "guild_settings"; + public void setValue(String value) { + this.value = value; } - @Override - public String[] getPrimaryKeys() { - return new String[] {"guild_id"}; + public String getName() { + return name; } - @Override - public boolean exists() { - return !settings.isEmpty(); + public void setName(String name) { + this.name = name; } - @Override - public void convertFromTableModel(MTableModel table) { - settings = new HashMap<>(); - - List<String> columns = table.getColumns(); - MRowModel row = table.getRowModel(0); - - for (int i = 0; i < columns.size(); i++) { - if (i == 0) continue; - - String key = columns.get(i).toUpperCase(); - Object value = row.getItem(i); - - settings.put(key, value); - } - - + public Integer getId() { + return id; } -} + + public void setId(Integer id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/netneutrality/db/entities/OLogMessage.java b/src/main/java/netneutrality/db/entities/OLogMessage.java new file mode 100644 index 0000000..cc5ccee --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OLogMessage.java @@ -0,0 +1,111 @@ +package netneutrality.db.entities; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import javax.persistence.*; +import java.time.Instant; + +@Entity +@Table(name = "log_message") +@NamedQueries({ + @NamedQuery(name = "OLogMessage.findByMessageIdEquals", query = "select o from OLogMessage o where o.messageId = :messageId"), + @NamedQuery(name = "OLogMessage.findByGuild_GuildIdEqualsAndUserIdEquals", query = "select o from OLogMessage o where o.guild.guildId = :guildId and o.userId = :userId") +}) +public class OLogMessage { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Integer id; + + @Column(name = "channel_id", nullable = false) + private String channelId; + + @Column(name = "message_id", nullable = false) + private String messageId; + + @Column(name = "user_id", nullable = false) + private String userId; + + @Convert(disableConversion = true) + @Column(name = "date_sent", nullable = false) + private Instant dateSent; + + @Column(name = "message", length = 2000) + private String message; + + @Column(name = "edited_message", length = 2000) + private String editedMessage; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "guild_id", nullable = false) + private OGuild guild; + + public OGuild getGuild() { + return guild; + } + + public void setGuild(OGuild guild) { + this.guild = guild; + } + + public String getEditedMessage() { + return editedMessage; + } + + public void setEditedMessage(String editedMessage) { + this.editedMessage = editedMessage; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Instant getDateSent() { + return dateSent; + } + + public void setDateSent(Instant dateSent) { + this.dateSent = dateSent; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/netneutrality/db/entities/OLogging.java b/src/main/java/netneutrality/db/entities/OLogging.java new file mode 100644 index 0000000..ed1b470 --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OLogging.java @@ -0,0 +1,49 @@ +package netneutrality.db.entities; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import javax.persistence.*; + +@Entity +@Table(name = "logging") +public class OLogging { + @EmbeddedId + private OLoggingId id; + + @MapsId("guildId") + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "guild_id", nullable = false) + private OGuild guild; + + @Column(name = "enabled", nullable = false) + private Boolean enabled = false; + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public OGuild getGuild() { + return guild; + } + + public void setGuild(OGuild guild) { + this.guild = guild; + } + + public OLoggingId getId() { + return id; + } + + public void setId(OLoggingId id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/netneutrality/db/entities/OLoggingId.java b/src/main/java/netneutrality/db/entities/OLoggingId.java new file mode 100644 index 0000000..d3eafa2 --- /dev/null +++ b/src/main/java/netneutrality/db/entities/OLoggingId.java @@ -0,0 +1,56 @@ +package netneutrality.db.entities; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import org.hibernate.Hibernate; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import java.io.Serial; +import java.io.Serializable; +import java.util.Objects; + +@Embeddable +public class OLoggingId implements Serializable { + @Serial + private static final long serialVersionUID = 8216581265618800768L; + @Column(name = "guild_id", nullable = false) + private String guildId; + @Column(name = "channel_id", nullable = false) + private String channelId; + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public String getGuildId() { + return guildId; + } + + public void setGuildId(String guildId) { + this.guildId = guildId; + } + + @Override + public int hashCode() { + return Objects.hash(guildId, channelId); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; + OLoggingId entity = (OLoggingId) o; + return Objects.equals(this.guildId, entity.guildId) && + Objects.equals(this.channelId, entity.channelId); + } +} \ No newline at end of file diff --git a/src/main/java/netneutrality/db/entities/OPermission.java b/src/main/java/netneutrality/db/entities/OPermission.java deleted file mode 100644 index 761dc5f..0000000 --- a/src/main/java/netneutrality/db/entities/OPermission.java +++ /dev/null @@ -1,66 +0,0 @@ -package netneutrality.db.entities; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.CommandType; -import netneutrality.db.models.MTableModel; - -public class OPermission extends AbstractEntity { - private final String guild_id; - private final String role_id; - public CommandType type; - public String command; - - public OPermission(String guild_id, String role_id) { - super(guild_id, role_id); - - this.guild_id = guild_id; - this.role_id = role_id; - } - - @Override - public boolean exists() { - return guild_id != null && role_id != null; - } - - public String getGuildId() { - return guild_id; - } - - public String getRoleId() { - return role_id; - } - - public CommandType getType() { - return type; - } - - public String getCommand() { - return command; - } - - - @Override - public String getTableName() { - return "permissions"; - } - - @Override - public String[] getPrimaryKeys() { - return new String[] {"guild_id", "role_id"}; - } - - - @Override - public void convertFromTableModel(MTableModel table) { - - this.type = (CommandType) table.getRow(0).get(2); - this.command = (String) table.getRow(0).get(3); - - } -} diff --git a/src/main/java/netneutrality/db/models/MSellyOrder.java b/src/main/java/netneutrality/db/entities/OSellyOrder.java similarity index 95% rename from src/main/java/netneutrality/db/models/MSellyOrder.java rename to src/main/java/netneutrality/db/entities/OSellyOrder.java index 75ea0c8..9c15182 100644 --- a/src/main/java/netneutrality/db/models/MSellyOrder.java +++ b/src/main/java/netneutrality/db/entities/OSellyOrder.java @@ -1,4 +1,4 @@ -package netneutrality.db.models; +package netneutrality.db.entities; /* * Copyright (c) anthorob @@ -7,7 +7,7 @@ package netneutrality.db.models; * https://discord.gg/CdFcyQ */ -public class MSellyOrder { +public class OSellyOrder { private final String id; private final String productId; @@ -23,7 +23,7 @@ public class MSellyOrder { private final float usdValue; private final String createdAt; - public MSellyOrder(String id, String productId, String email, String ip, float value, String currency, String gateway, int risk, int status, int cryptoValue, String cryptoAddress, float usdValue, String createdAt) { + public OSellyOrder(String id, String productId, String email, String ip, float value, String currency, String gateway, int risk, int status, int cryptoValue, String cryptoAddress, float usdValue, String createdAt) { this.id = id; this.productId = productId; this.email = email; diff --git a/src/main/java/netneutrality/db/models/MBlacklist.java b/src/main/java/netneutrality/db/models/MBlacklist.java deleted file mode 100644 index 1457dc4..0000000 --- a/src/main/java/netneutrality/db/models/MBlacklist.java +++ /dev/null @@ -1,59 +0,0 @@ -package netneutrality.db.models; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import java.util.List; - -public class MBlacklist { - - private final String word; - private final boolean enabled; - private final String creatorId; - private final String serverId; - - public MBlacklist(String word, boolean enabled, String creatorId, String serverId) { - this.word = word; - this.enabled = enabled; - this.creatorId = creatorId; - this.serverId = serverId; - } - - public MBlacklist(List<Object> row) { - this.word = (String) row.get(1); - this.enabled = (Boolean) row.get(2); - this.creatorId = (String) row.get(3); - this.serverId = (String) row.get(0); - } - - /** - * @return String The blacklisted word - */ - public String getWord() { - return word; - } - - public boolean isEnabled() { - return enabled; - } - - public String getCreatorId() { - return creatorId; - } - - public String getServerId() { - return serverId; - } - - @Override - public String toString() { - return "[word=" + word + ", enabled=" + enabled + "]"; - } - - - -} diff --git a/src/main/java/netneutrality/db/models/MMessage.java b/src/main/java/netneutrality/db/models/MMessage.java deleted file mode 100644 index 6684480..0000000 --- a/src/main/java/netneutrality/db/models/MMessage.java +++ /dev/null @@ -1,66 +0,0 @@ -package netneutrality.db.models; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -public class MMessage { - - private final String serverId; - private final String channelName; - private final String sender; - private final String dateSent; - private final String messageId; - private final String message; - private final String editedMessage; - - public MMessage(MRowModel row) { - this.serverId = (String) row.getItem(0); - this.channelName = (String) row.getItem(1); - this.sender = (String) row.getItem(2); - this.dateSent = (String) row.getItem(3); - this.messageId = (String) row.getItem(4); - this.message = (String) row.getItem(5); - this.editedMessage = ""; - } - - public String getServerId() { - return serverId; - } - - public String getChannelName() { - return channelName; - } - - public String getSender() { - return sender; - } - - public String getDateSent() { - return dateSent; - } - - public String getMessageId() { - return messageId; - } - - public String getMessage() { - return message; - } - - public String getEditedMessage() { - return editedMessage; - } - - @Override - public String toString() { - return "MMessage [serverName=" + serverId + ", channelName=" + channelName + ", sender=" + sender - + ", dateSent=" + dateSent + ", messageId=" + messageId + ", message=" + message + ", editedMessage=" - + editedMessage + "]"; - } - - -} diff --git a/src/main/java/netneutrality/db/models/MRowModel.java b/src/main/java/netneutrality/db/models/MRowModel.java deleted file mode 100644 index 69fff35..0000000 --- a/src/main/java/netneutrality/db/models/MRowModel.java +++ /dev/null @@ -1,80 +0,0 @@ -package netneutrality.db.models; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class MRowModel { - private final ArrayList<Object> row; - private int rowIndex; - - public MRowModel() { - row = new ArrayList<>(); - } - - public MRowModel(Integer rowIndex) { - row = new ArrayList<>(); - this.rowIndex = rowIndex; - } - - public MRowModel(Object... objs) { - row = new ArrayList<>(); - row.addAll(Arrays.asList(objs)); - } - - public int getRowIndex() { - return rowIndex; - } - - /** - * Add an item to the row. No checks are made to match the table itself - * @param obj Object to add to the row - */ - public void addColumnToRow(Object obj) { - row.add(obj); - } - - /** - * Get a list of all objects in the row. - * @return List of objects - */ - public List<Object> getRow() { - return row; - } - - /** - * <pre> - * Get an item at the specified index. - * - * Example: - * SQL: SELECT first, second, third - * Index: 0 1 2 - * </pre> - * - * @param index Index - * @return The object - */ - public Object getItem(int index) { - try { - return row.get(index); - } catch (Exception e) { - return null; - } - } - - public int count() { - return row.size(); - } - - @Override - public String toString() { - return row.toString(); - } -} diff --git a/src/main/java/netneutrality/db/models/MRowsModel.java b/src/main/java/netneutrality/db/models/MRowsModel.java deleted file mode 100644 index e9fd3e8..0000000 --- a/src/main/java/netneutrality/db/models/MRowsModel.java +++ /dev/null @@ -1,47 +0,0 @@ -package netneutrality.db.models; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import java.util.ArrayList; - -public class MRowsModel { - private final ArrayList<MRowModel> rows; - private String[] primaryKeys; - - public MRowsModel() { - rows = new ArrayList<>(); - } - - public void addRow(MRowModel row) { - rows.add(row); - } - - public MRowModel getRowModel(int index) { - if (!rows.isEmpty()) - return rows.get(index); - - return null; - } - - public int size() { - return rows.size(); - } - - public void addColumnInRow(int index, Object obj) { - rows.get(index).addColumnToRow(obj); - } - - public ArrayList<MRowModel> getRows() { - return rows; - } - - @Override - public String toString() { - return rows.toString(); - } -} diff --git a/src/main/java/netneutrality/db/models/MSellyProduct.java b/src/main/java/netneutrality/db/models/MSellyProduct.java deleted file mode 100644 index 9ffddfa..0000000 --- a/src/main/java/netneutrality/db/models/MSellyProduct.java +++ /dev/null @@ -1,19 +0,0 @@ -package netneutrality.db.models; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -public class MSellyProduct { - - private String id; - private String title; - private String description; - private String stock; - private float price; - private String currency; - private boolean isPrivate; -} diff --git a/src/main/java/netneutrality/db/models/MTableModel.java b/src/main/java/netneutrality/db/models/MTableModel.java deleted file mode 100644 index 420f275..0000000 --- a/src/main/java/netneutrality/db/models/MTableModel.java +++ /dev/null @@ -1,118 +0,0 @@ -package netneutrality.db.models; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -public class MTableModel { - private final boolean emptyResult; - private final boolean success; - private final String name; - private final List<String> column; - private final MRowsModel rows; - - public MTableModel() { - this.emptyResult = true; - this.success = false; - this.name = null; - this.column = new LinkedList<>(); - this.rows = new MRowsModel(); - } - - public MTableModel(int success) { - this.emptyResult = true; - this.success = success > 0; - this.name = null; - this.column = new LinkedList<>(); - this.rows = new MRowsModel(); - } - - public MTableModel(String tableName) { - this.emptyResult = false; - this.success = true; - this.name = tableName; - this.column = new LinkedList<>(); - this.rows = new MRowsModel(); - } - - public MTableModel(String... columns) { - this.emptyResult = false; - this.success = true; - this.name = null; - this.column = new LinkedList<>(); - this.rows = new MRowsModel(); - - Collections.addAll(column, columns); - } - - public boolean isEmptyResult() { - return emptyResult; - } - - public boolean isSuccess() { - return success; - } - - public String getName() { - return name; - } - - public void addColumn(String name) { - column.add(name); - } - - public void addRow(MRowModel row) { - rows.addRow(row); - } - - public MRowsModel getRows() { - return rows; - } - - public List<Object> getRow(int index) { - if (getNbRows() != 0) - return rows.getRowModel(index).getRow(); - - return null; - } - - /** - * Represent a row in a table - * - * @param rowIndex The index of the row - * @return A row model - */ - public MRowModel getRowModel(int rowIndex) { - if (getNbRows() != 0) - return rows.getRowModel(rowIndex); - - return new MRowModel(); - } - - public List<String> getColumns() { - return column; - } - - public boolean isEmpty() { - return rows.getRows().isEmpty(); - } - - public int getNbRows() { - return rows.getRows().size(); - } - - @Override - public String toString() { - return "Column: " + column + ", Rows (" + getNbRows() + "): " + rows; - } - - - -} diff --git a/src/main/java/netneutrality/exceptions/CommandErrorException.java b/src/main/java/netneutrality/exceptions/CommandErrorException.java index fe519f9..0802ea2 100644 --- a/src/main/java/netneutrality/exceptions/CommandErrorException.java +++ b/src/main/java/netneutrality/exceptions/CommandErrorException.java @@ -7,7 +7,7 @@ package netneutrality.exceptions; * https://discord.gg/CdFcyQ */ -import netneutrality.command.CommandContext; +import netneutrality.core.context.CommandContext; /** * Used to reply with a message in the text channel where the command was executed diff --git a/src/main/java/netneutrality/exceptions/CommandException.java b/src/main/java/netneutrality/exceptions/CommandException.java index 5a98a85..e058aad 100644 --- a/src/main/java/netneutrality/exceptions/CommandException.java +++ b/src/main/java/netneutrality/exceptions/CommandException.java @@ -7,7 +7,7 @@ package netneutrality.exceptions; * https://discord.gg/CdFcyQ */ -import netneutrality.command.CommandContext; +import netneutrality.core.context.CommandContext; public abstract class CommandException extends RuntimeException { diff --git a/src/main/java/netneutrality/exceptions/CommandExecutionException.java b/src/main/java/netneutrality/exceptions/CommandExecutionException.java index 14ba2ba..4a65787 100644 --- a/src/main/java/netneutrality/exceptions/CommandExecutionException.java +++ b/src/main/java/netneutrality/exceptions/CommandExecutionException.java @@ -7,7 +7,7 @@ package netneutrality.exceptions; * https://discord.gg/CdFcyQ */ -import netneutrality.command.CommandContext; +import netneutrality.core.context.CommandContext; /** * Logs the error internally, without sending a message diff --git a/src/main/java/netneutrality/exceptions/ExecutorException.java b/src/main/java/netneutrality/exceptions/ExecutorException.java index d7e64e6..8f58931 100644 --- a/src/main/java/netneutrality/exceptions/ExecutorException.java +++ b/src/main/java/netneutrality/exceptions/ExecutorException.java @@ -7,7 +7,7 @@ package netneutrality.exceptions; * https://discord.gg/CdFcyQ */ -import netneutrality.handler.LogHandler; +import netneutrality.core.LogHandler; public class ExecutorException implements Thread.UncaughtExceptionHandler { diff --git a/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java b/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java deleted file mode 100644 index 4cffbd5..0000000 --- a/src/main/java/netneutrality/exceptions/UnimplementedParameterException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 github.com/kaaz - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package netneutrality.exceptions; - -import java.sql.SQLException; - -public class UnimplementedParameterException extends SQLException { - - private final String s; - - public UnimplementedParameterException(Object parameter) { - s = "Parameter not implemented at for: " + parameter; - } - - public UnimplementedParameterException(Object parameter, int pos) { - s = "Parameter not implemented! parameter:" + parameter + " - position:" + pos; - } - - @Override - public String toString() { - return s; - } - -} diff --git a/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java b/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java index a015db9..086b0d8 100644 --- a/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java @@ -7,19 +7,13 @@ package netneutrality.handler.hooks.guilds; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.GuildManager; +import netneutrality.core.GuildManager; import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { - @Override - public void onGuildJoin(@NotNull GuildJoinEvent event) { - GuildManager.getManager(event.getGuild()).handleJoinEvent(); - } - @Override public void onGuildLeave(@NotNull GuildLeaveEvent event) { GuildManager.getManager(event.getGuild()).removeFromDB(); diff --git a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java index 3c4e09c..1f0bd94 100644 --- a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java @@ -7,14 +7,18 @@ package netneutrality.handler.hooks.message; * https://discord.gg/CdFcyQ */ -import java.awt.Color; - -import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.core.GuildManager; +import netneutrality.core.SessionManager; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; -import netneutrality.db.models.MTableModel; +import netneutrality.db.entities.OGuild; +import netneutrality.utils.MessageFunction; +import org.hibernate.Session; + +import java.util.stream.Collectors; public class EditHandler extends ListenerAdapter { @@ -23,37 +27,32 @@ public class EditHandler extends ListenerAdapter { if (event.getAuthor().isBot()) return; - MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id, guild_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); + GuildManager guildManager = GuildManager.getManager(event.getGuild()); - Object logChannel = table.getRowModel(0).getItem(0); - Object guild = table.getRowModel(0).getItem(1); + if (guildManager.getGuildEntity().getLogging()) { + OGuild guildEntity = guildManager.getGuildEntity(); - if (logChannel != null && guild != null) { - String originalMessage = ((DBMessage) DBController.get("message")).getMessageString(event.getMessage().getId()); - ((DBMessage) DBController.get("message")).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); + if (guildEntity.getLogChannel() != null && !guildEntity.getLogChannel().isEmpty()) { + Session session = SessionManager.getSessionFactory().openSession(); + session.load(guildEntity, guildEntity.getGuildId()); - EmbedBuilder editEmbed = new EmbedBuilder(); - editEmbed.setColor(Color.RED); - editEmbed.setDescription(":pencil2: **Message edited by " + event.getAuthor().getName() + "**"); - try { - editEmbed.addField("Original message", (originalMessage == null ? "Not available" : originalMessage), false); - } catch (IllegalArgumentException ex) { - editEmbed.addField("Original message:", "Message too long.", false); + int size = guildEntity.getLoggings() + .stream() + .filter(oLogging -> oLogging.getId().getChannelId().equals(event.getChannel().getId()) && oLogging.getEnabled()) + .collect(Collectors.toSet()) + .size(); + + if (size > 0) { + TextChannel channel = event.getGuild().getTextChannelById(guildEntity.getLogChannel()); + + if (channel != null) { + String originalMessage = DBController.get("message", DBMessage.class).getMessageString(event.getMessage().getId()); + DBController.get("message", DBMessage.class).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); + + channel.sendMessageEmbeds(MessageFunction.buildEditMessage(event.getMember(), event.getMessage(), originalMessage)).queue(); + } + } } - - try { - editEmbed.addField("Edited to:", event.getMessage().getContentDisplay(), false); - } catch (IllegalArgumentException ex) { - editEmbed.addField("Edited to:", "Message too long.", false); - } - - editEmbed.setFooter("ID : " + event.getMessageId(), null); - editEmbed.setTimestamp(event.getMessage().getTimeCreated()); - - event.getJDA().getGuildById((String) guild).getTextChannelById((String) logChannel).sendMessageEmbeds(editEmbed.build()).queue(); } - - } - } diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index 6dee6dc..4cb6d96 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -6,13 +6,15 @@ package netneutrality.handler.hooks.message; * https://discord.gg/CdFcyQ */ +import io.sentry.Breadcrumb; +import io.sentry.Sentry; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.GuildManager; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandManager; +import netneutrality.core.GuildManager; +import netneutrality.core.context.CommandContext; import netneutrality.utils.Settings; import org.jetbrains.annotations.NotNull; @@ -29,6 +31,8 @@ public class MessageReceivedHandler extends ListenerAdapter { if (user.isBot()) return; if (event.isWebhookMessage()) return; + Sentry.addBreadcrumb(Breadcrumb.info("New message from " + member.getEffectiveName())); + CommandContext context = CommandContext.createContext(event); GuildManager.getManager(guild).getRateLimiter().check(member, message, channel); @@ -48,7 +52,7 @@ public class MessageReceivedHandler extends ListenerAdapter { } } else { - GuildManager.getManager(guild).checkBlacklist(message, member, channel); + GuildManager.getManager(guild).checkBlacklist(message, channel); } } } diff --git a/src/main/java/netneutrality/handler/ReactionHandler.java b/src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java similarity index 95% rename from src/main/java/netneutrality/handler/ReactionHandler.java rename to src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java index 512a834..b309f44 100644 --- a/src/main/java/netneutrality/handler/ReactionHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java @@ -1,4 +1,5 @@ -package netneutrality.handler;/* +package netneutrality.handler.hooks.message; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ diff --git a/src/main/java/netneutrality/http/Selly.java b/src/main/java/netneutrality/http/Selly.java index 18d281e..5bad45c 100644 --- a/src/main/java/netneutrality/http/Selly.java +++ b/src/main/java/netneutrality/http/Selly.java @@ -1,12 +1,12 @@ package netneutrality.http; - /* * Copyright (c) anthorob * - * This file is closed-source. It should not be distributed or copied in any way or form + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ */ -import netneutrality.db.models.MSellyOrder; +import netneutrality.db.entities.OSellyOrder; import org.json.JSONArray; import org.json.JSONObject; @@ -24,10 +24,10 @@ public class Selly { encodedAuth = Base64.getEncoder().encode(concat.getBytes()); } - public Map<String, MSellyOrder> getOrders() { + public Map<String, OSellyOrder> getOrders() { WebModule sellyApi = new WebModule("https://selly.gg/api/v2/orders"); Map<String, String> headers = new HashMap<>(); - Map<String, MSellyOrder> orders = new HashMap<>(); + Map<String, OSellyOrder> orders = new HashMap<>(); headers.put("Authorization", "Basic " + new String(encodedAuth)); JSONArray response = null; try { @@ -40,7 +40,7 @@ public class Selly { for (int i = 0; i < response.length(); i++) { JSONObject order = response.getJSONObject(i); - orders.put(order.getString("id"), new MSellyOrder(order.getString("id"), order.getString("product_id"), order.getString("email"), order.getString("ip_address"), + orders.put(order.getString("id"), new OSellyOrder(order.getString("id"), order.getString("product_id"), order.getString("email"), order.getString("ip_address"), Float.parseFloat(order.getString("value")), order.getString("currency"), order.getString("gateway"), order.getInt("risk_level"), order.getInt("status"), order.getInt("crypto_value"), order.getString("crypto_address"), Float.parseFloat(order.getString("usd_value")), order.getString("created_at"))); } diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index 565b77c..cd8c8a6 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -1,11 +1,12 @@ package netneutrality.http; +import io.sentry.Breadcrumb; +import io.sentry.Sentry; import okhttp3.*; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; - import java.io.IOException; import java.util.List; import java.util.Map; @@ -28,21 +29,22 @@ public class WebModule { * @return an instance of the WebModule class with the Response of the Web Request */ public WebModule request() { - + Sentry.addBreadcrumb(Breadcrumb.http(url, "get")); Request request = new Request.Builder().url(this.url) .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 OPR/82.0.4227.43") .build(); try { response = client.newCall(request).execute(); + Sentry.addBreadcrumb(Breadcrumb.http(url, "get", response.code())); } catch (IOException e) { - e.printStackTrace(); + Sentry.captureException(e); } return this; } public WebModule request(Map<String, String> headers) throws IOException { - + Sentry.addBreadcrumb(Breadcrumb.http(url, "get")); Request.Builder builder = new Request.Builder().url(this.url) .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"); @@ -52,12 +54,18 @@ public class WebModule { Request request = builder.build(); - response = client.newCall(request).execute(); + try { + response = client.newCall(request).execute(); + Sentry.addBreadcrumb(Breadcrumb.http(url, "get", response.code())); + } catch (IOException e) { + Sentry.captureException(e); + } return this; } - public WebModule post(TreeMap<String, String> params, Map<String, String> headers) throws IOException { + public WebModule post(TreeMap<String, String> params, Map<String, String> headers) { + Sentry.addBreadcrumb(Breadcrumb.http(url, "post")); RequestBody body = RequestBody.create(createJson(params), MediaType.parse("application/json; charset=utf-8")); Request.Builder builder = new Request.Builder().url(this.url) .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"); @@ -66,7 +74,12 @@ public class WebModule { builder.addHeader(header.getKey(), header.getValue()); } Request request = builder.post(body).build(); - response = client.newCall(request).execute(); + try { + response = client.newCall(request).execute(); + Sentry.addBreadcrumb(Breadcrumb.http(url, "post", response.code())); + } catch (IOException e) { + Sentry.captureException(e); + } return this; } @@ -157,29 +170,4 @@ public class WebModule { return response.body().string(); } - public String getTextInHtmlTag(String tag) { - String body = ""; - try { - body = getRawData(); - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - } - int startOfTag = body.indexOf(tag); - int endOfTag = body.indexOf(getEndHtmlTag(tag)); - if (startOfTag < 0 || endOfTag < 0) { - return ""; - } - - return body.substring(startOfTag + tag.length(), endOfTag - (tag.length() - 1)); - } - - private String getEndHtmlTag(String startingTag) { - String endingTag = ""; - if (startingTag.charAt(0) == '<' && startingTag.charAt(1) != '/' ) { - endingTag = "</" + startingTag.substring(1, startingTag.length() - 1) + ">"; - } - System.out.println("endingTag = " + endingTag); - - return endingTag; - } } diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index ac98e2e..78f9329 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -7,11 +7,11 @@ package netneutrality.http.server;/* import com.sun.net.httpserver.HttpExchange; import net.dv8tion.jda.api.entities.Guild; -import netneutrality.GuildManager; -import netneutrality.MusicBot; +import netneutrality.NetNeutrality; +import netneutrality.core.GuildManager; import netneutrality.http.WebModule; -import org.apache.logging.log4j.LogManager; import org.json.JSONObject; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Map; @@ -24,9 +24,9 @@ public class ActionHandler extends AbstractHandler { String path = exchange.getRequestURI().getRawPath(); if (path.equals("/actions/shutdown")) { - LogManager.getLogger(MusicBot.class).info("Request to shutdown received"); + LoggerFactory.getLogger(NetNeutrality.class).info("Request to shutdown received"); sendStringResponse(exchange, "Shutting down.."); - MusicBot.shutdown(); + NetNeutrality.shutdown(); System.exit(0); return; @@ -34,8 +34,8 @@ public class ActionHandler extends AbstractHandler { if (path.equals("/actions/status")) { TreeMap<String, String> json = new TreeMap<>(); - json.put("health", String.valueOf(MusicBot.getJDA().getStatus())); - json.put("ping", String.valueOf(MusicBot.getJDA().getGatewayPing())); + json.put("health", String.valueOf(NetNeutrality.getJDA().getStatus())); + json.put("ping", String.valueOf(NetNeutrality.getJDA().getGatewayPing())); sendJsonResponse(exchange, WebModule.createJson(json)); return; @@ -46,10 +46,10 @@ public class ActionHandler extends AbstractHandler { String[] args = exchange.getRequestURI().toString().split("/"); String guildId = args[args.length - 1]; - Guild guild = MusicBot.getJDA().getGuildById(guildId); + Guild guild = NetNeutrality.getJDA().getGuildById(guildId); if (guild != null) { GuildManager manager = GuildManager.getManager(guild); - Map<String, Object> settings = manager.getSettings(); + Map<String, String> settings = manager.getSettings(); JSONObject setting = new JSONObject(settings); json.put("status", "ok"); @@ -67,13 +67,14 @@ public class ActionHandler extends AbstractHandler { String[] args = exchange.getRequestURI().toString().split("/"); String guildId = args[args.length - 1]; - Guild guild = MusicBot.getJDA().getGuildById(guildId); + Guild guild = NetNeutrality.getJDA().getGuildById(guildId); boolean ok; if (guild == null) ok = GuildManager.reloadSettingsForGuild(guildId); else ok = GuildManager.reloadSettingsForGuild(guild); + json.put("status", String.valueOf(ok)); sendJsonResponse(exchange, WebModule.createJson(json)); diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/netneutrality/http/server/GuildHandler.java index 4ba2028..b709f13 100644 --- a/src/main/java/netneutrality/http/server/GuildHandler.java +++ b/src/main/java/netneutrality/http/server/GuildHandler.java @@ -9,7 +9,7 @@ package netneutrality.http.server; import com.sun.net.httpserver.HttpExchange; import net.dv8tion.jda.api.JDA; -import netneutrality.MusicBot; +import netneutrality.NetNeutrality; import org.json.JSONArray; import org.json.JSONObject; @@ -26,7 +26,7 @@ public class GuildHandler extends AbstractHandler { JSONArray array = new JSONArray(); - JDA jda = MusicBot.getJDA(); + JDA jda = NetNeutrality.getJDA(); jda.getGuilds().forEach(guild -> { JSONObject obj = new JSONObject(); @@ -46,7 +46,7 @@ public class GuildHandler extends AbstractHandler { String guild = args[args.length - 1]; JSONArray array = new JSONArray(); - JDA jda = MusicBot.getJDA(); + JDA jda = NetNeutrality.getJDA(); if (jda.getGuildById(guild) == null) { sendStringResponse(exchange, path); @@ -70,7 +70,7 @@ public class GuildHandler extends AbstractHandler { String[] args = exchange.getRequestURI().toString().split("/"); String guild = args[args.length - 1]; JSONArray array = new JSONArray(); - JDA jda = MusicBot.getJDA(); + JDA jda = NetNeutrality.getJDA(); if (jda.getGuildById(guild) == null) { sendStringResponse(exchange, path); diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index c6ee655..476d8eb 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -20,14 +20,13 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.VoiceChannel; -import netneutrality.GuildManager; -import netneutrality.ThreadManager; -import netneutrality.command.CommandContext; +import netneutrality.core.GuildManager; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; -import netneutrality.handler.LogHandler; import netneutrality.thread.MusicPlayerAutoDisconnectThread; +import netneutrality.thread.ThreadManager; import netneutrality.utils.MessageFunction; -import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,17 +50,18 @@ public class MusicManager { private final AudioPlayerManager playerManager; private final TrackScheduler scheduler; private ScheduledFuture<?> autoDisconnectThread; + private final int baseVolume; private MusicManager(Guild guild) { this.guild = guild; this.playerManager = new DefaultAudioPlayerManager(); this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(player); + this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME)); AudioSourceManagers.registerRemoteSources(playerManager); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); - player.setVolume((Integer) GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_VOLUME)); managers.put(guild.getId(), this); } @@ -75,8 +75,8 @@ public class MusicManager { } public static void initPlayerManager() { - YoutubeHttpContextFilter.setPAPISID(Settings.getInstance().get("BOT_PAPISID", "")); - YoutubeHttpContextFilter.setPSID(Settings.getInstance().get("BOT_PSID", "")); + YoutubeHttpContextFilter.setPAPISID(netneutrality.utils.Settings.getInstance().get("BOT_PAPISID", "")); + YoutubeHttpContextFilter.setPSID(netneutrality.utils.Settings.getInstance().get("BOT_PSID", "")); } public boolean isConnectedTo(VoiceChannel vChannel) { @@ -87,6 +87,7 @@ public class MusicManager { if (vChannel != null && !isConnectedTo(vChannel)) { guild.getAudioManager().openAudioConnection(vChannel); guild.getAudioManager().setSelfDeafened(true); + player.setVolume(baseVolume); if (autoDisconnectThread == null) autoDisconnectThread = executor.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 120, 120, TimeUnit.SECONDS); @@ -142,7 +143,7 @@ public class MusicManager { } public boolean restoreQueue(List<String> track) { - + //TODO: todo return false; } @@ -235,6 +236,10 @@ public class MusicManager { } } + public synchronized void stopTrack() { + player.stopTrack(); + } + public synchronized void skip(int nbTrack) { if (!scheduler.getQueue().isEmpty()) { if (nbTrack >= scheduler.getQueue().size()) { diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index e23380a..26e05da 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -17,7 +17,10 @@ import net.dv8tion.jda.api.entities.TextChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; public class TrackScheduler extends AudioEventAdapter { diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index eebaf7b..4e3101b 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -8,7 +8,7 @@ package netneutrality.thread;/* import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; -import netneutrality.MusicBot; +import netneutrality.NetNeutrality; import netneutrality.music.MusicManager; import java.util.List; @@ -32,7 +32,7 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { } if (channel != null) { - List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(MusicBot.getSelf().getId())).toList(); + List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); if (members.size() == 0) manager.leave(); diff --git a/src/main/java/netneutrality/thread/ShutdownThread.java b/src/main/java/netneutrality/thread/ShutdownThread.java index 34e1e1a..ca926b7 100644 --- a/src/main/java/netneutrality/thread/ShutdownThread.java +++ b/src/main/java/netneutrality/thread/ShutdownThread.java @@ -5,8 +5,7 @@ package netneutrality.thread;/* * https://discord.gg/CdFcyQ */ -import netneutrality.MusicBot; -import netneutrality.utils.UnsafeShutdown; +import netneutrality.NetNeutrality; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configurator; @@ -20,8 +19,8 @@ public class ShutdownThread implements Runnable { Configurator.shutdown((LoggerContext) LogManager.getContext()); } - if (MusicBot.getJDA() != null) { - MusicBot.shutdown(); + if (NetNeutrality.getJDA() != null) { + NetNeutrality.shutdown(); } } diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/thread/ThreadManager.java similarity index 86% rename from src/main/java/netneutrality/ThreadManager.java rename to src/main/java/netneutrality/thread/ThreadManager.java index 2530aae..946ab44 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/thread/ThreadManager.java @@ -1,11 +1,16 @@ -package netneutrality; - -import netneutrality.thread.BaseThreadFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +package netneutrality.thread; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ import java.util.Map; -import java.util.concurrent.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; public class ThreadManager { @@ -14,7 +19,6 @@ public class ThreadManager { } private static final Map<String, ExecutorService> executors = new ConcurrentHashMap<>(); - private final static Logger logger = LoggerFactory.getLogger(ThreadManager.class); public static ExecutorService getExecutor(String name) { return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index 4cb37b1..abe112f 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -1,14 +1,18 @@ package netneutrality.utils; +import io.sentry.ISpan; +import io.sentry.ITransaction; +import io.sentry.Sentry; +import io.sentry.SpanStatus; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.thread.ThreadManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.time.OffsetDateTime; import java.util.List; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.ThreadManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class ChannelFunction { private static final Logger logger = LoggerFactory.getLogger(ChannelFunction.class); @@ -18,38 +22,74 @@ public class ChannelFunction { if (toDelete >= 2500) return; ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { + ITransaction transaction = Sentry.startTransaction(String.format("bulkDeleteMessage(%s, %d)", channel.getId(), toDelete), "task"); + transaction.setData("channel", channel.getId()); + transaction.setData("toDelete", toDelete); + transaction.setTag("operation", "bulk-delete"); - int toDeleteFinal = toDelete + 1; - int iteration = toDeleteFinal / 100; - for (int i = 0; i < iteration; i++) { - List<Message> messages = channel.getHistory().retrievePast(100).complete(); - deleteFromList(messages, channel); - toDeleteFinal -= 100; + try { + int toDeleteFinal = toDelete + 1; + int iteration = toDeleteFinal / 100; + for (int i = 0; i < iteration; i++) { + ISpan innerSpan = transaction.startChild("task", "Processing iteration " + (i + 1) + "/" + iteration); + try { + List<Message> messages = channel.getHistory().retrievePast(100).complete(); + deleteFromList(messages, channel, innerSpan); + toDeleteFinal -= 100; + innerSpan.setStatus(SpanStatus.OK); + } catch (Exception e) { + innerSpan.setThrowable(e); + innerSpan.setStatus(SpanStatus.INTERNAL_ERROR); + throw e; + } finally { + innerSpan.finish(); + } + } + + if (toDeleteFinal > 0) { + ISpan innerSpan = transaction.startChild("task", String.format("Processing final iteration (%d messages)", toDeleteFinal)); + try { + List<Message> messages = channel.getHistory().retrievePast(toDeleteFinal).complete(); + deleteFromList(messages, channel, innerSpan); + innerSpan.setStatus(SpanStatus.OK); + } catch (Exception e) { + innerSpan.setThrowable(e); + innerSpan.setStatus(SpanStatus.INTERNAL_ERROR); + throw e; + } finally { + innerSpan.finish(); + } + + + innerSpan.finish(); + } + + transaction.setStatus(SpanStatus.OK); + } catch (Exception e) { + transaction.setThrowable(e); + transaction.setStatus(SpanStatus.INTERNAL_ERROR); + } finally { + transaction.finish(); } - - if (toDeleteFinal > 0) { - List<Message> messages = channel.getHistory().retrievePast(toDeleteFinal).complete(); - deleteFromList(messages, channel); - - } - }); - } - private synchronized static void deleteFromList(List<Message> messages, TextChannel channel) { + private synchronized static void deleteFromList(List<Message> messages, TextChannel channel, ISpan span) { + ISpan innerSpan = span.startChild("delete", "Executing delete of: " + messages.size() + " messages"); try { channel.deleteMessages(messages).complete(); - logger.debug("Deleted {} messages from channel [{}] in guild [{}]", messages.size(), channel.getName(), channel.getGuild().getName()); - + innerSpan.setStatus(SpanStatus.OK); } catch (IllegalArgumentException e) { + innerSpan.setThrowable(e); + innerSpan.setStatus(SpanStatus.OUT_OF_RANGE); messages.forEach(m -> { if (!m.getTimeCreated().isBefore(OffsetDateTime.now().minusWeeks(2))) { m.delete().queue(); } }); - + } finally { + innerSpan.finish(); } } -} \ No newline at end of file +} diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/netneutrality/utils/JpaUtils.java new file mode 100644 index 0000000..068c3b9 --- /dev/null +++ b/src/main/java/netneutrality/utils/JpaUtils.java @@ -0,0 +1,42 @@ +package netneutrality.utils;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import io.sentry.Breadcrumb; +import io.sentry.Sentry; +import io.sentry.SentryLevel; +import netneutrality.core.GuildManager; +import netneutrality.db.entities.OGuild; +import org.hibernate.HibernateException; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.Session; + +import java.io.Serializable; + +public class JpaUtils { + + public static void tryLoad(Session session, Object object, Serializable id) { + try { + session.load(object, id); + } catch (HibernateException exception) { + if (object instanceof OGuild oGuild) { + if (exception instanceof ObjectNotFoundException) { + Sentry.addBreadcrumb(Breadcrumb.error("ObjectNotFoundException")); + + String cachedId = oGuild.getGuildId(); + Sentry.captureMessage("Trying to load Guild[" + cachedId + "] while deleted from database, reloading..", SentryLevel.ERROR); + GuildManager guildManager = GuildManager.getManager(cachedId); + guildManager.reloadEntity(); + guildManager.getBlacklistCache().clear(); + Sentry.captureMessage("Guild[" + cachedId + "] reloaded", SentryLevel.INFO); + } + } + session.close(); + + throw exception; + } + } +} diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 6c77edf..9c40b2b 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -7,27 +7,24 @@ package netneutrality.utils; * https://discord.gg/CdFcyQ */ -import java.awt.*; -import java.time.OffsetDateTime; -import java.util.*; -import java.util.List; - import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandContext; import netneutrality.command.CommandType; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBBlacklist; -import netneutrality.db.models.MBlacklist; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.awt.*; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.*; + public class MessageFunction { private final static Logger logger = LoggerFactory.getLogger(MessageFunction.class); @@ -89,7 +86,7 @@ public class MessageFunction { message.addField("Track title: ", track.getInfo().title, false); message.addField("Uploaded by: ", track.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); - message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); @@ -103,7 +100,7 @@ public class MessageFunction { message.setColor(Color.BLUE); message.addField("Playlist: ", playlist.getName(), false); message.addField("Number of tracks: ", String.valueOf(playlist.getTracks().size()), false); - message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); @@ -118,7 +115,7 @@ public class MessageFunction { message.setColor(Color.BLUE); int index = 0; - for (AudioTrack track: tracks) { + for (AudioTrack track : tracks) { if (track.getInfo().title.equals(current.getInfo().title) && currentlyPlaying) { message.addField("Track #" + ++index + " (Currently playing)", track.getInfo().title, false); } else { @@ -128,7 +125,7 @@ public class MessageFunction { if (index == 10) break; } - message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); + message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); @@ -140,7 +137,7 @@ public class MessageFunction { message.setColor(Color.BLUE); message.addField("Command", command.getCommandName(), false); message.addField("Description", command.getDescription(), false); - message.addField("Aliases", ((command.getAlias() == null || command.getAlias().length == 0) ? "None": Arrays.toString(command.getAlias()).replaceAll("[\\[\\]]", "")), false); + message.addField("Aliases", ((command.getAlias() == null || command.getAlias().length == 0) ? "None" : Arrays.toString(command.getAlias()).replaceAll("[\\[\\]]", "")), false); message.addField("Usage", (command.getUsage() == null ? "No arguments defined" : command.getUsage().toString()), false); return message.build(); @@ -217,32 +214,47 @@ public class MessageFunction { message.addField("Caused by:", cause, false); } - message.setFooter("Requested by " + context.getDiscordUser().getName(), context.getDiscordUser().getAvatarUrl()); + message.setFooter("Requested by " + context.getGuildUser().getEffectiveName(), context.getGuildUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static void checkBlacklist(Guild guild, Message message, TextChannel channel) { + public static MessageEmbed buildEditMessage(Member member, Message message, String originalMessage) { + EmbedBuilder editEmbed = new EmbedBuilder(); + editEmbed.setColor(Color.RED); + editEmbed.setDescription(":pencil2: **Message edited by " + member.getEffectiveName() + "**"); + try { + editEmbed.addField("Original message", (originalMessage == null ? "Not available" : originalMessage), false); + } catch (IllegalArgumentException ex) { + editEmbed.addField("Original message:", "Message too long.", false); + } - ArrayList<MBlacklist> mBlacklists = ((DBBlacklist) DBController.get("blacklist")).getBlacklistFromServer(guild.getId()); - if (!mBlacklists.isEmpty()) { + try { + editEmbed.addField("Edited to:", message.getContentDisplay(), false); + } catch (IllegalArgumentException ex) { + editEmbed.addField("Edited to:", "Message too long.", false); + } - boolean found = false; - for (MBlacklist aBlacklist : mBlacklists) { - if (message.getContentRaw().toLowerCase().contains(aBlacklist.getWord())) { - found = true; - break; - } - } - - if (found) { - message.delete().queue(); - channel.sendMessage("Not in my christian server").queue(); - } - } + editEmbed.setFooter("ID : " + message.getId(), null); + editEmbed.setTimestamp(message.getTimeCreated()); + return editEmbed.build(); } + public static void testMessageAgainstBlacklist(Message message, TextChannel channel, Set<String> cache) { + boolean found = false; + for (String word : cache) { + if (message.getContentRaw().toLowerCase().contains(word)) { + found = true; + break; + } + } + + if (found) { + message.delete().queue(); + channel.sendMessage("Not in my christian server").queue(); + } + } } diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index 2a83e44..a68973d 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -6,29 +6,45 @@ package netneutrality.utils;/* */ import net.dv8tion.jda.api.entities.VoiceChannel; -import netneutrality.command.CommandContext; -import netneutrality.exceptions.CommandErrorException; +import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; public class MusicUtils { - public static void checkIfConnected(MusicManager manager, CommandContext context) { + public static boolean checkIfConnected(MusicManager manager, CommandContext context) { if (context.getGuildUser().getVoiceState() == null) { - throw new CommandExecutionException("Voice state is null", context, null); + throw new CommandExecutionException("Voice state is null, this should not happen", context, null); } if (!context.getGuildUser().getVoiceState().inVoiceChannel()) { - throw new CommandErrorException("You are not in a voice channel", context, null); + context.reply("You are not in a voice channel"); + return false; } VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); if (!manager.isConnected()) { - throw new CommandErrorException("Player is not in a voice channel", context, null); + context.reply("You are not in a voice channel"); + return false; } if (!manager.isConnectedTo(vChannel)) { - throw new CommandErrorException("Player is not in your voice channel", context, null); + context.reply("You are not in a voice channel"); + return false; } + + return true; + } + + public static boolean checkIfDj(MusicManager manager, CommandContext context) { + if (manager.getCurrentlyPlaying() != null) { + if (!UserFunction.isAdmin(context.getGuildUser()) || !manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) { + context.reply("You are not powerful enough, scrub"); + return false; + } else + return true; + } + + return false; } } diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 0179810..17205be 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -1,6 +1,8 @@ package netneutrality.utils; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.util.Map; import java.util.Properties; @@ -10,7 +12,7 @@ public class Settings { private final Properties prop = new Properties(); public Settings() { - File file = new File("bot.config"); + File file = new File("bot.properties"); FileInputStream fis = null; try { diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF index 6d311f9..329b72b 100644 --- a/src/main/resources/META-INF/MANIFEST.MF +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: netneutrality.MusicBot +Main-Class: netneutrality.NetNeutrality diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml new file mode 100644 index 0000000..d92de99 --- /dev/null +++ b/src/main/resources/hibernate.cfg.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> + +<hibernate-configuration> + <session-factory> + + <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> + <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property> + <property name="hibernate.connection.provider_class">org.hibernate.hikaricp.internal.HikariCPConnectionProvider</property> + + <mapping class="netneutrality.db.entities.OGuild"/> + <mapping class="netneutrality.db.entities.OBlacklist"/> + <mapping class="netneutrality.db.entities.OGuildSetting"/> + <mapping class="netneutrality.db.entities.OLogMessage"/> + <mapping class="netneutrality.db.entities.OLogging"/> + <mapping class="netneutrality.db.entities.OLoggingId"/> + + </session-factory> +</hibernate-configuration> \ No newline at end of file diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties new file mode 100644 index 0000000..ca00468 --- /dev/null +++ b/src/main/resources/log4j2.properties @@ -0,0 +1,34 @@ +status = warn + +appender.console.type = Console +appender.console.name = consoleLogger +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %p [%thread] %logger - %msg%n + +# Rotate log file +appender.rolling.type = RollingFile +appender.rolling.name = LogToRollingFile +appender.rolling.fileName = logs/debug.log +appender.rolling.filePattern = logs/$${date:yyyy-MM}/debug-%d{MM-dd-yyyy}-%i.log.gz +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %p [%thread] %logger - %msg%n +appender.rolling.policies.type = Policies +appender.rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size=10MB +appender.rolling.strategy.type = DefaultRolloverStrategy +appender.rolling.strategy.max = 5 + +logger.hibernate.name = org.hibernate +logger.hibernate.level = info +logger.hibernate.additivity = false +logger.hibernate.appenderRef.rolling.ref = LogToRollingFile + +logger.app.name = netneutrality +logger.app.level = debug +logger.app.additivity = false +logger.app.appenderRef.rolling.ref = LogToRollingFile +logger.app.appenderRef.console.ref = consoleLogger + +rootLogger.level = error +rootLogger.appenderRef.stdout.ref = consoleLogger \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml deleted file mode 100644 index ac416cb..0000000 --- a/src/main/resources/log4j2.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Configuration status="WARN" shutdownHook="disable"> - <Appenders> - <Console name="Console" target="SYSTEM_OUT"> - <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight{%-5level}{STYLE=Logback} %logger - %msg%n" /> - </Console> - </Appenders> - <Loggers> - <Logger name="netneutrality" level="trace" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Root level="error"> - <AppenderRef ref="Console" /> - </Root> - </Loggers> -</Configuration> diff --git a/src/main/resources/spy.properties b/src/main/resources/spy.properties new file mode 100644 index 0000000..fa4d6da --- /dev/null +++ b/src/main/resources/spy.properties @@ -0,0 +1,4 @@ +driverlist=com.mysql.cj.jdbc.Driver +dateformat=yyyy-MM-dd hh:mm:ss a +appender=com.p6spy.engine.spy.appender.StdoutLogger +logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat \ No newline at end of file From 932be7040740835ca4a743b18739ad5e919a41a1 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 13 Mar 2022 16:47:14 -0400 Subject: [PATCH 072/155] Sentry env --- src/main/java/netneutrality/NetNeutrality.java | 14 ++++---------- src/main/java/netneutrality/core/LogHandler.java | 1 - 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index f739550..16b2731 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -30,25 +30,19 @@ public class NetNeutrality { public static void main(String[] args) { String sentryDsn = Settings.getInstance().get("SENTRY_DSN"); + String env = Settings.getInstance().get("BOT_ENV", "dev"); Sentry.init(options -> { options.setDsn(sentryDsn); - options.setEnvironment(Settings.getInstance().get("BOT_ENV", "dev")); - // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring. - // We recommend adjusting this value in production. + options.setEnvironment(env); options.setTracesSampleRate(1.0); - // When first trying Sentry it's good to see what the SDK is doing: - options.setDebug(true); + options.setDebug(env.equals("dev")); }); - DBController.init(); - - initJDA(); - + DBController.init(); CommandManager.init(); MusicManager.initPlayerManager(); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); - new WebApi(9000); jda.getPresence().setActivity(Activity.watching("you")); diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index fee6ab4..1319974 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -29,7 +29,6 @@ public class LogHandler { sendMessageToChannel((CommandErrorException) e); } else if (e instanceof CommandExecutionException) { Sentry.captureException(e); - logInternally((CommandExecutionException) e); tryLogToDebugChannel((CommandExecutionException) e); } else { From 9f7056c56f36034c00ecca4efdff6941dfef0b85 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 14 Mar 2022 04:56:39 -0400 Subject: [PATCH 073/155] Fix settings cache --- src/main/java/netneutrality/core/GuildManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 44720d0..6f6a1b3 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -140,7 +140,6 @@ public class GuildManager { String value = settingsCache.get(setting.getName()); if (value == null) { - setSettingValue(setting, null); value = setting.getDefaultValue(); } From 8d442a45fc7485cd5f20795e3e3a5d83a1186cf7 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 14 Mar 2022 05:08:13 -0400 Subject: [PATCH 074/155] new db scheme --- docker-compose.yml | 2 +- sql/add_debug_field_to_guilds_table.sql | 1 - sql/add_volume_field_to_settings_table.sql | 1 - sql/netneutrality.sql | 142 ------------------ ...utrality_new.sql => netneutrality_jpa.sql} | 63 +++----- 5 files changed, 26 insertions(+), 183 deletions(-) delete mode 100644 sql/add_debug_field_to_guilds_table.sql delete mode 100644 sql/add_volume_field_to_settings_table.sql delete mode 100644 sql/netneutrality.sql rename sql/{netneutrality_new.sql => netneutrality_jpa.sql} (79%) diff --git a/docker-compose.yml b/docker-compose.yml index e1f3842..4a56fe0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: restart: always volumes: - netneutrality-db:/var/lib/mysql - - ./sql/netneutrality.sql:/docker-entrypoint-initdb.d/dump.sql + - ./sql/netneutrality_jpa.sql:/docker-entrypoint-initdb.d/dump.sql environment: MYSQL_DATABASE: 'netneutrality' MYSQL_USER: 'java' diff --git a/sql/add_debug_field_to_guilds_table.sql b/sql/add_debug_field_to_guilds_table.sql deleted file mode 100644 index accb099..0000000 --- a/sql/add_debug_field_to_guilds_table.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `guilds` ADD `debug` BOOLEAN NOT NULL DEFAULT '1' AFTER `logging`; \ No newline at end of file diff --git a/sql/add_volume_field_to_settings_table.sql b/sql/add_volume_field_to_settings_table.sql deleted file mode 100644 index d427e2b..0000000 --- a/sql/add_volume_field_to_settings_table.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `guild_settings` ADD `music_volume` INT NOT NULL DEFAULT '30' AFTER `music_channel`; \ No newline at end of file diff --git a/sql/netneutrality.sql b/sql/netneutrality.sql deleted file mode 100644 index ba60239..0000000 --- a/sql/netneutrality.sql +++ /dev/null @@ -1,142 +0,0 @@ --- phpMyAdmin SQL Dump --- version 5.1.0 --- https://www.phpmyadmin.net/ --- --- Host: 127.0.0.1:3306 --- Generation Time: Nov 07, 2021 at 04:31 AM --- Server version: 10.4.10-MariaDB --- PHP Version: 7.4.19 - -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -START TRANSACTION; -SET time_zone = "+00:00"; - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; - --- --- Database: `netneutrality` --- - --- -------------------------------------------------------- - --- --- Table structure for table `blacklist` --- - -DROP TABLE IF EXISTS `blacklist`; -CREATE TABLE IF NOT EXISTS `blacklist` ( - `word` varchar(255) NOT NULL, - `serverId` varchar(255) NOT NULL, - `isEnabled` tinyint(1) NOT NULL, - `creatorId` varchar(255) NOT NULL, - PRIMARY KEY (`word`,`serverId`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `guilds` --- - -DROP TABLE IF EXISTS `guilds`; -CREATE TABLE IF NOT EXISTS `guilds` ( - `guild_id` varchar(255) NOT NULL, - `logging` int(11) DEFAULT 0, - `logchannel` varchar(255) DEFAULT NULL, - PRIMARY KEY (`guild_id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- --- Dumping data for table `guilds` --- - -INSERT INTO `guilds` (`guild_id`, `logging`, `logchannel`) VALUES -('195386426400047105', 0, NULL); - --- -------------------------------------------------------- - --- --- Table structure for table `guild_settings` --- - -DROP TABLE IF EXISTS `guild_settings`; -CREATE TABLE IF NOT EXISTS `guild_settings` ( - `guild_id` varchar(255) NOT NULL, - `music_role` varchar(255) DEFAULT NULL, - `music_channel` varchar(255) DEFAULT NULL, - `blacklist_exclude_channels` text DEFAULT NULL, - PRIMARY KEY (`guild_id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- --- Dumping data for table `guild_settings` --- - -INSERT INTO `guild_settings` (`guild_id`, `music_role`, `music_channel`, `blacklist_exclude_channels`) VALUES -('195386426400047105', NULL, NULL, NULL); - --- -------------------------------------------------------- - --- --- Table structure for table `logging` --- - -DROP TABLE IF EXISTS `logging`; -CREATE TABLE IF NOT EXISTS `logging` ( - `serverId` varchar(255) NOT NULL, - `channelId` varchar(255) NOT NULL, - `enabled` tinyint(4) NOT NULL, - PRIMARY KEY (`serverId`,`channelId`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `log_message` --- - -DROP TABLE IF EXISTS `log_message`; -CREATE TABLE IF NOT EXISTS `log_message` ( - `serverId` varchar(255) NOT NULL, - `channelId` varchar(255) NOT NULL, - `userId` varchar(255) NOT NULL, - `dateSent` varchar(255) NOT NULL, - `messageId` varchar(255) NOT NULL, - `message` varchar(2000) DEFAULT NULL, - `editedMessage` varchar(2000) DEFAULT NULL, - PRIMARY KEY (`messageId`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `permissions` --- - -DROP TABLE IF EXISTS `permissions`; -CREATE TABLE IF NOT EXISTS `permissions` ( - `guild_id` varchar(255) NOT NULL, - `role_id` varchar(255) NOT NULL, - `type` int(11) DEFAULT NULL, - `command` int(11) DEFAULT NULL, - PRIMARY KEY (`guild_id`,`role_id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- --- Constraints for dumped tables --- - --- --- Constraints for table `guild_settings` --- -ALTER TABLE `guild_settings` - ADD CONSTRAINT `fk_guildid_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); -COMMIT; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/sql/netneutrality_new.sql b/sql/netneutrality_jpa.sql similarity index 79% rename from sql/netneutrality_new.sql rename to sql/netneutrality_jpa.sql index 0f23fb3..94ebd9a 100644 --- a/sql/netneutrality_new.sql +++ b/sql/netneutrality_jpa.sql @@ -3,7 +3,7 @@ -- https://www.phpmyadmin.net/ -- -- Host: 127.0.0.1:3306 --- Generation Time: Jan 04, 2022 at 09:55 PM +-- Generation Time: Mar 14, 2022 at 08:59 AM -- Server version: 10.4.10-MariaDB -- PHP Version: 7.4.19 @@ -29,11 +29,13 @@ SET time_zone = "+00:00"; DROP TABLE IF EXISTS `blacklist`; CREATE TABLE IF NOT EXISTS `blacklist` ( + `id` int(11) NOT NULL AUTO_INCREMENT, `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `word` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `enabled` tinyint(1) NOT NULL, `creator_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - PRIMARY KEY (`guild_id`,`word`) + PRIMARY KEY (`id`), + KEY `fk_blacklist_guilds` (`guild_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- -------------------------------------------------------- @@ -45,28 +47,12 @@ CREATE TABLE IF NOT EXISTS `blacklist` ( DROP TABLE IF EXISTS `guilds`; CREATE TABLE IF NOT EXISTS `guilds` ( `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `logging` int(11) DEFAULT 0, + `logging` tinyint(1) NOT NULL DEFAULT 0, + `debug` tinyint(1) NOT NULL DEFAULT 1, `log_channel` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (`guild_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; --- --- Dumping data for table `guilds` --- - -INSERT INTO `guilds` (`guild_id`, `logging`, `log_channel`) VALUES -('195386426400047105', 0, NULL), -('250767028397408256', 0, NULL); - --- --- Triggers `guilds` --- -DROP TRIGGER IF EXISTS `insert_settings`; -DELIMITER $$ -CREATE TRIGGER `insert_settings` AFTER INSERT ON `guilds` FOR EACH ROW INSERT INTO guild_settings(guild_id) VALUES (new.guild_id) -$$ -DELIMITER ; - -- -------------------------------------------------------- -- @@ -75,21 +61,14 @@ DELIMITER ; DROP TABLE IF EXISTS `guild_settings`; CREATE TABLE IF NOT EXISTS `guild_settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `music_role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `music_channel` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `blacklist_exclude_channels` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`guild_id`) + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `value` text COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + KEY `fk_guildsetting_guilds` (`guild_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; --- --- Dumping data for table `guild_settings` --- - -INSERT INTO `guild_settings` (`guild_id`, `music_role`, `music_channel`, `blacklist_exclude_channels`) VALUES -('195386426400047105', NULL, NULL, NULL), -('250767028397408256', NULL, NULL, NULL); - -- -------------------------------------------------------- -- @@ -100,7 +79,7 @@ DROP TABLE IF EXISTS `logging`; CREATE TABLE IF NOT EXISTS `logging` ( `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `channel_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `enabled` tinyint(4) NOT NULL, + `enabled` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`guild_id`,`channel_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; @@ -112,14 +91,16 @@ CREATE TABLE IF NOT EXISTS `logging` ( DROP TABLE IF EXISTS `log_message`; CREATE TABLE IF NOT EXISTS `log_message` ( + `id` int(11) NOT NULL AUTO_INCREMENT, `guild_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `channel_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `message_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `user_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `date_sent` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - `message_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `message` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `edited_message` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`message_id`), + PRIMARY KEY (`id`), + UNIQUE KEY `message_id` (`message_id`), KEY `fk_log_guilds` (`guild_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; @@ -163,19 +144,25 @@ CREATE TABLE IF NOT EXISTS `web_users` ( -- Constraints for table `blacklist` -- ALTER TABLE `blacklist` - ADD CONSTRAINT `fk_blacklist_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); + ADD CONSTRAINT `fk_blacklist_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`) ON DELETE CASCADE ON UPDATE CASCADE; -- -- Constraints for table `guild_settings` -- ALTER TABLE `guild_settings` - ADD CONSTRAINT `fk_guildid_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); + ADD CONSTRAINT `fk_guildsetting_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- +-- Constraints for table `logging` +-- +ALTER TABLE `logging` + ADD CONSTRAINT `fk_logging_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`) ON DELETE CASCADE ON UPDATE CASCADE; -- -- Constraints for table `log_message` -- ALTER TABLE `log_message` - ADD CONSTRAINT `fk_log_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`); + ADD CONSTRAINT `fk_log_guilds` FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`guild_id`) ON DELETE CASCADE ON UPDATE CASCADE; COMMIT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; From c44ddd42beafa64d214d7f13f5bf126ebdcf1d90 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 14 Mar 2022 07:03:39 -0400 Subject: [PATCH 075/155] Check for valid json in crypto commands, move class --- .gitignore | 3 +++ src/main/java/netneutrality/NetNeutrality.java | 2 +- .../java/netneutrality/command/basic/HelpCommand.java | 2 +- .../command/crypto/BitcoinPriceCommand.java | 9 ++++++++- .../netneutrality/command/crypto/CryptoPriceCommand.java | 9 ++++++++- .../command/crypto/EthereumPriceCommand.java | 9 ++++++++- .../command/crypto/LitecoinPriceCommand.java | 9 ++++++++- .../netneutrality/{command => core}/CommandManager.java | 3 ++- .../handler/hooks/message/MessageReceivedHandler.java | 2 +- src/main/java/netneutrality/http/WebModule.java | 9 ++++++--- 10 files changed, 46 insertions(+), 11 deletions(-) rename src/main/java/netneutrality/{command => core}/CommandManager.java (96%) diff --git a/.gitignore b/.gitignore index fcc2aa9..a27df78 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,6 @@ hs_err_pid* # Maven log/ target/ + +#log4j +logs/ \ No newline at end of file diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 16b2731..e4d5c4e 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -6,7 +6,7 @@ import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.GatewayIntent; -import netneutrality.command.CommandManager; +import netneutrality.core.CommandManager; import netneutrality.core.LogHandler; import netneutrality.db.DBController; import netneutrality.handler.hooks.guilds.ServerJoinHandler; diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 69bf7c9..7a3d2c1 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -9,7 +9,7 @@ package netneutrality.command.basic; import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandManager; +import netneutrality.core.CommandManager; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 48750c0..adba8db 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -13,6 +13,7 @@ import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.text.NumberFormat; @@ -84,7 +85,13 @@ public class BitcoinPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + JSONObject json = http.getAsObject(); + if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); + return; + } + + price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index d9d16f4..c05a072 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -13,6 +13,7 @@ import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.text.NumberFormat; @@ -87,7 +88,13 @@ public class CryptoPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + JSONObject json = http.getAsObject(); + if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + t.editMessage("Crypto doesn't exist.. yet").queue(); + return; + } + + price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 49f2706..65948cf 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -13,6 +13,7 @@ import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.text.NumberFormat; @@ -84,7 +85,13 @@ public class EthereumPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + JSONObject json = http.getAsObject(); + if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); + return; + } + + price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index bbd7bc5..165cc51 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -13,6 +13,7 @@ import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.http.WebModule; import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.text.NumberFormat; @@ -84,7 +85,13 @@ public class LitecoinPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - price = dollarFormat.format(http.getAsObject().getDouble(finalCurrency)); + JSONObject json = http.getAsObject(); + if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); + return; + } + + price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); diff --git a/src/main/java/netneutrality/command/CommandManager.java b/src/main/java/netneutrality/core/CommandManager.java similarity index 96% rename from src/main/java/netneutrality/command/CommandManager.java rename to src/main/java/netneutrality/core/CommandManager.java index f0dfb74..16a5234 100644 --- a/src/main/java/netneutrality/command/CommandManager.java +++ b/src/main/java/netneutrality/core/CommandManager.java @@ -1,4 +1,4 @@ -package netneutrality.command; +package netneutrality.core; /* * Copyright (c) anthorob @@ -7,6 +7,7 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ +import netneutrality.command.AbstractCommand; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index 4cb6d96..52ab9ce 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -12,7 +12,7 @@ import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandManager; +import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; import netneutrality.utils.Settings; diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index cd8c8a6..47eb57d 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -17,6 +17,9 @@ public class WebModule { private final String url; private final OkHttpClient client = new OkHttpClient(); private Response response; + //private final String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 OPR/82.0.4227.43"; + private final String userAgent = "NetNeutrality/1.0 (Discord bot, anthorob@xtremmail.com)"; + public WebModule(String url) { this.url = url; @@ -31,7 +34,7 @@ public class WebModule { public WebModule request() { Sentry.addBreadcrumb(Breadcrumb.http(url, "get")); Request request = new Request.Builder().url(this.url) - .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 OPR/82.0.4227.43") + .addHeader("User-Agent", userAgent) .build(); try { response = client.newCall(request).execute(); @@ -46,7 +49,7 @@ public class WebModule { public WebModule request(Map<String, String> headers) throws IOException { Sentry.addBreadcrumb(Breadcrumb.http(url, "get")); Request.Builder builder = new Request.Builder().url(this.url) - .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"); + .addHeader("User-Agent", userAgent); for (Map.Entry<String, String> header : headers.entrySet()) { builder.addHeader(header.getKey(), header.getValue()); @@ -68,7 +71,7 @@ public class WebModule { Sentry.addBreadcrumb(Breadcrumb.http(url, "post")); RequestBody body = RequestBody.create(createJson(params), MediaType.parse("application/json; charset=utf-8")); Request.Builder builder = new Request.Builder().url(this.url) - .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"); + .addHeader("User-Agent", userAgent); for (Map.Entry<String, String> header : headers.entrySet()) { builder.addHeader(header.getKey(), header.getValue()); From f71cdb324b23d09b126df6adeb6972514c54c4ed Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Tue, 15 Mar 2022 16:46:53 -0400 Subject: [PATCH 076/155] Create guild in DB on guild join --- src/main/java/netneutrality/core/GuildManager.java | 13 ++++--------- .../handler/hooks/guilds/ServerJoinHandler.java | 6 ++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 6f6a1b3..93b8d7b 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -245,21 +245,16 @@ public class GuildManager { session.save(entity); session.getTransaction().commit(); - handleJoinEvent(); + guild.getTextChannels() + .stream() + .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .forEach(textChannel -> textChannel.sendMessage("Error logging enabled on channel " + textChannel.getAsMention()).queue()); } session.close(); return entity; } - public void handleJoinEvent() { - guild.getTextChannels() - .stream() - .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) - .forEach(textChannel -> textChannel.sendMessage("Error logging enabled on channel " + textChannel.getAsMention()).queue()); - - } - public void reloadEntity() { this.guildEntity = loadGuildFromDb(guild.getId()); } diff --git a/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java b/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java index 086b0d8..de6a6a7 100644 --- a/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java +++ b/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java @@ -7,6 +7,7 @@ package netneutrality.handler.hooks.guilds; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.core.GuildManager; @@ -14,6 +15,11 @@ import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { + @Override + public void onGuildJoin(@NotNull GuildJoinEvent event) { + GuildManager.getManager(event.getGuild()); + } + @Override public void onGuildLeave(@NotNull GuildLeaveEvent event) { GuildManager.getManager(event.getGuild()).removeFromDB(); From d13e11eac5b38e2c01421905b46608e7f674727c Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Tue, 15 Mar 2022 19:41:12 -0400 Subject: [PATCH 077/155] Make debug logging configurable --- .../command/bot/ConfigureCommand.java | 58 +++++++++++++++---- .../command/music/VolumeCommand.java | 13 +++-- .../java/netneutrality/core/GuildManager.java | 14 +++++ 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 0474c82..a89d60f 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -41,7 +41,7 @@ public class ConfigureCommand extends AbstractCommand { @Override public CommandUsage getUsage() { return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"musicrole", "musicvolume"}, "") + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"musicrole", "musicvolume", "debug"}, "") ); } @@ -62,8 +62,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length > 0) { + // Role for music commands if (context.getArg(0).equals("musicrole")) { - if (args.length == 1) { String roleDb = guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE); Role role = null; @@ -72,11 +72,19 @@ public class ConfigureCommand extends AbstractCommand { } context.reply("Current role needed to use music commands (default is everyone): %s", (role == null ? "Everyone" : role.getAsMention())); + context.reply("Reset role using 'conf musicrole reset' or set it using 'conf musicrole @'"); } if (args.length == 2) { - List<Role> roles = context.getMessage().getMentionedRoles(); + if (context.getArg(1).equals("reset")) { + if (!guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE).isEmpty()) { + guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); + } + context.reply("Successful reset of the role"); + } + + List<Role> roles = context.getMessage().getMentionedRoles(); if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { @@ -84,32 +92,58 @@ public class ConfigureCommand extends AbstractCommand { context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } - - if (context.getArg(1).equals("reset")) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); - context.reply("Successful reset of the role"); - } } } + // Default volume for music player if (context.getArg(0).equals("musicvolume")) { if (args.length == 1) { int volume = Integer.parseInt(guildManager.getSetting(GuildManager.Settings.MUSIC_VOLUME)); context.reply("Default volume for music player: " + volume); + context.reply("Set using 'conf musicvolume <value between 0 and 100>'"); } if (args.length == 2) { try { int volume = Integer.parseInt(args[1]); - guildManager.setSettingValue(GuildManager.Settings.MUSIC_VOLUME, String.valueOf(volume)); - MusicManager.get(context.getGuild()).setVolume(volume); - context.reply("Default volume for music player is now %d", volume); + if (volume > 0 && volume <= 100) { + guildManager.setSettingValue(GuildManager.Settings.MUSIC_VOLUME, String.valueOf(volume)); + MusicManager.get(context.getGuild()).setVolume(volume); + + context.reply("Default volume for music player is now %d", volume); + } else + throw new NumberFormatException(); + } catch (NumberFormatException e) { - throw new CommandErrorException("Not a value between 0 and 100", context, e); + context.reply("Not a value between 0 and 100"); + } + } + } + + // Debug + if (context.getArg(0).equals("debug")) { + if (args.length == 1) { + boolean debug = guildManager.isDebugEnabled(); + + context.reply("Error logging is currently %s for this guild.", (debug ? "enabled" : "disabled")); + context.reply("Use 'conf debug 0/1' to toggle between states."); + } + + if (args.length == 2) { + String str = args[1]; + boolean debug = guildManager.isDebugEnabled(); + if (str.equals("0") || str.equalsIgnoreCase("false")) { + debug = false; } + if (str.equals("1") || str.equalsIgnoreCase("true")) { + debug = true; + } + + guildManager.setDebug(debug); + context.reply("Error logging is now %s for this guild", (debug ? "enabled" : "disabled")); } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index bd03f77..e7f12cb 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -51,11 +51,16 @@ public class VolumeCommand extends AbstractMusicCommand { return; try { - int volume = Integer.parseInt(context.getArgumentsAsArray()[0]); - player.setVolume(volume); - context.reply("Volume set to %s", volume); + int volume = Integer.parseInt(context.getArg(0)); + + if (volume > 0 && volume <= 100) { + player.setVolume(volume); + context.reply("Volume set to %s", volume); + } else + throw new NumberFormatException(); + } catch (NumberFormatException e) { - throw new CommandErrorException("Please enter a value from 0 to 100", context, e); + context.reply("Please enter a value from 0 to 100"); } } diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 93b8d7b..ea06606 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -174,6 +174,20 @@ public class GuildManager { session.close(); } + public void setDebug(boolean toggle) { + if (toggle == isDebugEnabled()) + return; + + Session session = sessionFactory.openSession(); + session.beginTransaction(); + + guildEntity.setDebug(toggle); + + session.update(guildEntity); + session.getTransaction().commit(); + session.close(); + } + public static boolean reloadSettingsForGuild(String guildId) { GuildManager manager = GuildManager.getManager(guildId); manager.reloadSettingsCache(true); From 734e4e0b2572672dd5c4c6910604c08484d55699 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 17 Mar 2022 07:38:59 -0400 Subject: [PATCH 078/155] Add timezone to log4j --- src/main/resources/log4j2.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties index ca00468..b859553 100644 --- a/src/main/resources/log4j2.properties +++ b/src/main/resources/log4j2.properties @@ -3,7 +3,7 @@ status = warn appender.console.type = Console appender.console.name = consoleLogger appender.console.layout.type = PatternLayout -appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %p [%thread] %logger - %msg%n +appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS}{America/Toronto} %p [%thread] %logger - %msg%n # Rotate log file appender.rolling.type = RollingFile @@ -11,7 +11,7 @@ appender.rolling.name = LogToRollingFile appender.rolling.fileName = logs/debug.log appender.rolling.filePattern = logs/$${date:yyyy-MM}/debug-%d{MM-dd-yyyy}-%i.log.gz appender.rolling.layout.type = PatternLayout -appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %p [%thread] %logger - %msg%n +appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS}{America/Toronto} %p [%thread] %logger - %msg%n appender.rolling.policies.type = Policies appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.size.type = SizeBasedTriggeringPolicy From 90c2f8fba7c12f728aa7123d64d091af0f6ff857 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 17 Mar 2022 07:45:37 -0400 Subject: [PATCH 079/155] small correction to text --- .../java/netneutrality/command/bot/ConfigureCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index a89d60f..0a0bb79 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -128,17 +128,17 @@ public class ConfigureCommand extends AbstractCommand { boolean debug = guildManager.isDebugEnabled(); context.reply("Error logging is currently %s for this guild.", (debug ? "enabled" : "disabled")); - context.reply("Use 'conf debug 0/1' to toggle between states."); + context.reply("Use 'conf debug 0/1' to toggle between states (0 = disabled, 1 = enabled)."); } if (args.length == 2) { String str = args[1]; boolean debug = guildManager.isDebugEnabled(); - if (str.equals("0") || str.equalsIgnoreCase("false")) { + if (str.equals("0") || str.equalsIgnoreCase("disable")) { debug = false; } - if (str.equals("1") || str.equalsIgnoreCase("true")) { + if (str.equals("1") || str.equalsIgnoreCase("enable")) { debug = true; } From 832fc0ff3dbe4416ef3c37ee0f8c11a82399c183 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 20 Mar 2022 16:56:33 -0400 Subject: [PATCH 080/155] Fix settings loading and add helpers for JPA --- .../java/netneutrality/core/GuildManager.java | 104 ++++++++---------- .../java/netneutrality/http/WebModule.java | 2 +- .../http/server/ActionHandler.java | 4 +- .../netneutrality/thread/ThreadManager.java | 1 - .../java/netneutrality/utils/JpaUtils.java | 45 +++++++- 5 files changed, 90 insertions(+), 66 deletions(-) diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index ea06606..c2fdea3 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -18,6 +18,7 @@ import netneutrality.db.entities.OGuild; import netneutrality.db.entities.OGuildSetting; import netneutrality.handler.ratelimiter.IMessageRateLimiter; import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; +import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; import org.hibernate.Session; @@ -71,7 +72,8 @@ public class GuildManager { this.rateLimiter = new MessageRateLimiterImpl(); managers.put(guild.getId(), this); - reloadBlacklistCache(true); + reloadBlacklistCache(); + reloadSettingsCache(); } private GuildManager(String guildId) { @@ -84,7 +86,8 @@ public class GuildManager { this.rateLimiter = new MessageRateLimiterImpl(); managers.put(guild.getId(), this); - reloadBlacklistCache(true); + reloadBlacklistCache(); + reloadSettingsCache(); } public static GuildManager getManager(Guild guild) { @@ -148,28 +151,31 @@ public class GuildManager { public void setSettingValue(Settings setting, String value) { Session session = sessionFactory.openSession(); - session.load(guildEntity, guildEntity.getGuildId()); - - if (value == null || value.isEmpty()) { - value = setting.getDefaultValue(); - } + JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); OGuildSetting oGuildSetting = guildEntity.getSettingByName(setting.getName()); session.beginTransaction(); - if (oGuildSetting == null) { - oGuildSetting = new OGuildSetting(); - oGuildSetting.setGuild(guildEntity); - oGuildSetting.setName(setting.getName()); - oGuildSetting.setValue(value); - session.save(oGuildSetting); + if (value == null || setting.getDefaultValue().equals(value)) { + if (oGuildSetting != null) { + session.delete(oGuildSetting); + } } else { - oGuildSetting.setValue(value); - session.update(oGuildSetting); + if (oGuildSetting == null) { + oGuildSetting = new OGuildSetting(); + oGuildSetting.setGuild(guildEntity); + oGuildSetting.setName(setting.getName()); + oGuildSetting.setValue(value); + + session.save(oGuildSetting); + } else { + oGuildSetting.setValue(value); + + session.update(oGuildSetting); + } } session.getTransaction().commit(); - reloadSettingsCache(false); session.close(); } @@ -178,67 +184,50 @@ public class GuildManager { if (toggle == isDebugEnabled()) return; - Session session = sessionFactory.openSession(); - session.beginTransaction(); - - guildEntity.setDebug(toggle); - - session.update(guildEntity); - session.getTransaction().commit(); - session.close(); + JpaUtils.updateWithTransaction(guildEntity, () -> guildEntity.setDebug(toggle)); } - public static boolean reloadSettingsForGuild(String guildId) { - GuildManager manager = GuildManager.getManager(guildId); - manager.reloadSettingsCache(true); - - return true; - } - - public static boolean reloadSettingsForGuild(Guild guild) { - GuildManager manager = GuildManager.getManager(guild.getId()); - manager.reloadSettingsCache(true); - - return true; - } - - public void reloadSettingsCache(boolean close) { + public boolean reloadSettingsCache(boolean close) { logger.debug("Reloading settings cache for guild: " + guild.getId()); settingsCache.clear(); - Session session = sessionFactory.openSession(); - JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); + JpaUtils.getWithSession(guildEntity, close, () -> { + Set<OGuildSetting> settingSet = guildEntity.getGuildSettings(); - Set<OGuildSetting> settingSet = guildEntity.getGuildSettings(); - for (OGuildSetting setting : settingSet) { - settingsCache.put(setting.getName(), setting.getValue()); - } + for (OGuildSetting setting : settingSet) { + settingsCache.put(setting.getName(), setting.getValue()); + } + }); - if (close) - session.close(); + return true; + } + + public boolean reloadSettingsCache() { + return reloadSettingsCache(true); } public void reloadBlacklistCache(boolean close) { logger.debug("Reloading blacklist cache for guild: " + guild.getId()); blacklistCache.clear(); - Session session = sessionFactory.openSession(); - JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); + JpaUtils.getWithSession(guildEntity, close, () -> { + Set<OBlacklist> oBlacklistSet = guildEntity.getBlacklists(); - Set<OBlacklist> oBlacklistSet = guildEntity.getBlacklists(); - for (OBlacklist bl : oBlacklistSet) { - if (bl.getEnabled()) { - blacklistCache.add(bl.getWord()); + for (OBlacklist bl : oBlacklistSet) { + if (bl.getEnabled()) { + blacklistCache.add(bl.getWord()); + } } - } + }); + } - if (close) - session.close(); + public void reloadBlacklistCache() { + reloadBlacklistCache(true); } public void checkAndLogMessage(Message message, Member member, TextChannel channel) { if (isLoggingEnabled()) { - DBController.get("message", DBMessage.class).log(this, channel, member, message); + ThreadManager.getExecutor("log-messages").submit(() -> DBController.get("message", DBMessage.class).log(this, channel, member, message)); } } @@ -254,6 +243,7 @@ public class GuildManager { logger.debug("Guild[{}] doesn't exist in DB, creating entity..", guildId); session.beginTransaction(); entity = new OGuild(); + entity.setGuildId(guildId); session.save(entity); diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index 47eb57d..38a0b84 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -18,7 +18,7 @@ public class WebModule { private final OkHttpClient client = new OkHttpClient(); private Response response; //private final String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 OPR/82.0.4227.43"; - private final String userAgent = "NetNeutrality/1.0 (Discord bot, anthorob@xtremmail.com)"; + private static final String userAgent = "NetNeutrality/1.0 (Discord bot, anthorob@xtremmail.com)"; public WebModule(String url) { diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 78f9329..85bdb30 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -70,9 +70,9 @@ public class ActionHandler extends AbstractHandler { Guild guild = NetNeutrality.getJDA().getGuildById(guildId); boolean ok; if (guild == null) - ok = GuildManager.reloadSettingsForGuild(guildId); + ok = GuildManager.getManager(guildId).reloadSettingsCache(); else - ok = GuildManager.reloadSettingsForGuild(guild); + ok = GuildManager.getManager(guild).reloadSettingsCache(); json.put("status", String.valueOf(ok)); diff --git a/src/main/java/netneutrality/thread/ThreadManager.java b/src/main/java/netneutrality/thread/ThreadManager.java index 946ab44..791bb54 100644 --- a/src/main/java/netneutrality/thread/ThreadManager.java +++ b/src/main/java/netneutrality/thread/ThreadManager.java @@ -22,7 +22,6 @@ public class ThreadManager { public static ExecutorService getExecutor(String name) { return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); - } public static ExecutorService getExecutor(String name, ExecutorType type) { diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/netneutrality/utils/JpaUtils.java index 068c3b9..4d3aebc 100644 --- a/src/main/java/netneutrality/utils/JpaUtils.java +++ b/src/main/java/netneutrality/utils/JpaUtils.java @@ -9,6 +9,7 @@ import io.sentry.Breadcrumb; import io.sentry.Sentry; import io.sentry.SentryLevel; import netneutrality.core.GuildManager; +import netneutrality.core.SessionManager; import netneutrality.db.entities.OGuild; import org.hibernate.HibernateException; import org.hibernate.ObjectNotFoundException; @@ -22,21 +23,55 @@ public class JpaUtils { try { session.load(object, id); } catch (HibernateException exception) { - if (object instanceof OGuild oGuild) { - if (exception instanceof ObjectNotFoundException) { - Sentry.addBreadcrumb(Breadcrumb.error("ObjectNotFoundException")); + if (exception instanceof ObjectNotFoundException) { + Sentry.addBreadcrumb(Breadcrumb.error("ObjectNotFoundException")); + if (object instanceof OGuild oGuild) { String cachedId = oGuild.getGuildId(); - Sentry.captureMessage("Trying to load Guild[" + cachedId + "] while deleted from database, reloading..", SentryLevel.ERROR); + Sentry.captureMessage("Trying to load Guild[" + cachedId + "] while deleted from database, reloading entity..", SentryLevel.ERROR); + GuildManager guildManager = GuildManager.getManager(cachedId); guildManager.reloadEntity(); guildManager.getBlacklistCache().clear(); Sentry.captureMessage("Guild[" + cachedId + "] reloaded", SentryLevel.INFO); } } - session.close(); + session.close(); throw exception; } } + + public static void updateWithTransaction(Object persistantEntity, Runnable runnable) { + Session session = SessionManager.getSessionFactory().openSession(); + session.beginTransaction(); + + runnable.run(); + + session.update(persistantEntity); + session.getTransaction().commit(); + session.close(); + } + + public static void getWithSession(OGuild oGuild, Runnable runnable) { + getWithSession(oGuild, oGuild.getGuildId(), runnable); + } + + public static void getWithSession(OGuild oGuild, boolean close, Runnable runnable) { + getWithSession(oGuild, oGuild.getGuildId(), close, runnable); + } + + public static void getWithSession(Object persistantEntity, Serializable id, Runnable runnable) { + getWithSession(persistantEntity, id, true, runnable); + } + + public static void getWithSession(Object persistantEntity, Serializable id, boolean close, Runnable runnable) { + Session session = SessionManager.getSessionFactory().openSession(); + tryLoad(session, persistantEntity, id); + + runnable.run(); + + if (close) + session.close(); + } } From ef038c5b5bb06bd14da21bf2ff2b331f9243b8dc Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 21 Mar 2022 19:28:20 -0400 Subject: [PATCH 081/155] Add ability to limit music commands to a certain channel --- .../command/AbstractCommand.java | 6 +++ .../command/AbstractMusicCommand.java | 32 +++++++++++----- .../java/netneutrality/command/ICommand.java | 3 ++ .../command/PermissionManager.java | 26 ------------- .../command/bot/ConfigureCommand.java | 37 ++++++++++++++++++- .../java/netneutrality/core/GuildManager.java | 4 +- .../core/context/CommandContext.java | 10 ++--- .../java/netneutrality/utils/JpaUtils.java | 36 ++++++++++++++---- 8 files changed, 102 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/netneutrality/command/PermissionManager.java diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 071264a..252a597 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -2,6 +2,7 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; public abstract class AbstractCommand implements ICommand { @@ -9,4 +10,9 @@ public abstract class AbstractCommand implements ICommand { public boolean canBeExecutedBy(Guild guild, Member member) { return true; } + + @Override + public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { + return true; + } } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 4614326..afcf418 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -6,9 +6,7 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.*; import netneutrality.core.GuildManager; import netneutrality.utils.UserFunction; @@ -27,17 +25,33 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_ROLE); - boolean can = true; - //System.out.println(roleDb); if (roleDb != null && !roleDb.isEmpty()) { + if (UserFunction.isAdmin(member)) { + return true; + } + Role neededRole = guild.getRoleById(roleDb); - can = member.getRoles().contains(neededRole); + if (neededRole == null) { + // Role doesn't exist on guild anymore, remove from db + GuildManager.getManager(guild).setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); + return true; + } + + return member.getRoles().contains(neededRole); } - if (UserFunction.isAdmin(member)) - can = true; + return true; + } - return can; + @Override + public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { + String channelDb = GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_CHANNEL); + + if (channelDb != null && !channelDb.isEmpty()) { + return channelDb.equals(channel.getId()); + } + + return true; } } diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 848bc5a..91fed50 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -8,6 +8,7 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandExecutionException; @@ -44,6 +45,8 @@ public interface ICommand { boolean canBeExecutedBy(Guild guild, Member member); + boolean canBeExecutedFrom(Guild guild, TextChannel channel); + /** * Command is executed with this function. * diff --git a/src/main/java/netneutrality/command/PermissionManager.java b/src/main/java/netneutrality/command/PermissionManager.java deleted file mode 100644 index 43c4983..0000000 --- a/src/main/java/netneutrality/command/PermissionManager.java +++ /dev/null @@ -1,26 +0,0 @@ -package netneutrality.command; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Role; - -import java.util.List; - -public class PermissionManager { - - public static boolean CheckPermissionForUser(Guild guild, Member member, AbstractCommand command) { - - //Permission permissions = DBController.get().prepareAndExecuteAsync("SELECT * FROM permissions WHERE guild_id = ?").blocking(); - - List<Role> roles = member.getRoles(); - - return false; - } - -} diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 0a0bb79..8254d3d 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -7,12 +7,12 @@ package netneutrality.command.bot; */ import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; import java.util.List; @@ -41,7 +41,7 @@ public class ConfigureCommand extends AbstractCommand { @Override public CommandUsage getUsage() { return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"musicrole", "musicvolume", "debug"}, "") + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"musicrole", "music-channel", "musicvolume", "debug"}, "") ); } @@ -95,6 +95,39 @@ public class ConfigureCommand extends AbstractCommand { } } + // Role for music commands + if (context.getArg(0).equals("music-channel")) { + if (args.length == 1) { + String channelDb = guildManager.getSetting(GuildManager.Settings.MUSIC_CHANNEL); + TextChannel channel = null; + if (!channelDb.isEmpty()) { + channel = context.getGuild().getTextChannelById(channelDb); + } + + context.reply("Current channel where music commands can be executed (default is everywhere): %s", (channel == null ? "Everywhere" : channel.getAsMention())); + context.reply("Reset channel using 'conf music-channel reset' or set it using 'conf music-channel #'"); + } + + if (args.length == 2) { + if (context.getArg(1).equals("reset")) { + if (!guildManager.getSetting(GuildManager.Settings.MUSIC_CHANNEL).isEmpty()) { + guildManager.setSettingValue(GuildManager.Settings.MUSIC_CHANNEL, null); + } + + context.reply("Successful reset of the channel"); + } + + List<TextChannel> channels = context.getMessage().getMentionedChannels(); + if (channels.size() == 1) { + TextChannel channel = channels.get(0); + if (channel.getGuild().getId().equals(context.getGuild().getId())) { + guildManager.setSettingValue(GuildManager.Settings.MUSIC_CHANNEL, channel.getId()); + context.reply("Successfully set %s as the channel required to execute music command", channel.getAsMention()); + } + } + } + } + // Default volume for music player if (context.getArg(0).equals("musicvolume")) { if (args.length == 1) { diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index c2fdea3..91b6697 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -191,7 +191,7 @@ public class GuildManager { logger.debug("Reloading settings cache for guild: " + guild.getId()); settingsCache.clear(); - JpaUtils.getWithSession(guildEntity, close, () -> { + JpaUtils.getWithSession(guildEntity, close, session -> { Set<OGuildSetting> settingSet = guildEntity.getGuildSettings(); for (OGuildSetting setting : settingSet) { @@ -210,7 +210,7 @@ public class GuildManager { logger.debug("Reloading blacklist cache for guild: " + guild.getId()); blacklistCache.clear(); - JpaUtils.getWithSession(guildEntity, close, () -> { + JpaUtils.getWithSession(guildEntity, close, session -> { Set<OBlacklist> oBlacklistSet = guildEntity.getBlacklists(); for (OBlacklist bl : oBlacklistSet) { diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index ce3ebff..0b82b40 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -179,14 +179,14 @@ public class CommandContext { }); try { - if (command.needAdmin()) { - if (!UserFunction.isAdmin(member)) { - return; - } + if (command.needAdmin() && !UserFunction.isAdmin(member)) { + return; } if (command.canBeExecutedBy(guild, member)) { - command.execute(this); + if (command.canBeExecutedFrom(guild, channel)) { + command.execute(this); + } } } catch (CommandErrorException | CommandExecutionException e) { LogHandler.log(e); diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/netneutrality/utils/JpaUtils.java index 4d3aebc..6ad9d58 100644 --- a/src/main/java/netneutrality/utils/JpaUtils.java +++ b/src/main/java/netneutrality/utils/JpaUtils.java @@ -16,9 +16,22 @@ import org.hibernate.ObjectNotFoundException; import org.hibernate.Session; import java.io.Serializable; +import java.util.function.Consumer; public class JpaUtils { + /** + * Tries to read the persistent state into the object. + * + * If the object is not found in the database and is of type {@link OGuild}, tries to recreate entity and throws + * an exception to block execution. + * + * The session is not closed + * + * @param session The session in which to load the persistent object + * @param object The persistent object + * @param id Identifier + */ public static void tryLoad(Session session, Object object, Serializable id) { try { session.load(object, id); @@ -53,23 +66,30 @@ public class JpaUtils { session.close(); } - public static void getWithSession(OGuild oGuild, Runnable runnable) { - getWithSession(oGuild, oGuild.getGuildId(), runnable); + public static void getWithSession(OGuild oGuild, Consumer<Session> consumer) { + getWithSession(oGuild, oGuild.getGuildId(), consumer); } - public static void getWithSession(OGuild oGuild, boolean close, Runnable runnable) { - getWithSession(oGuild, oGuild.getGuildId(), close, runnable); + public static void getWithSession(OGuild oGuild, boolean close, Consumer<Session> consumer) { + getWithSession(oGuild, oGuild.getGuildId(), close, consumer); } - public static void getWithSession(Object persistantEntity, Serializable id, Runnable runnable) { - getWithSession(persistantEntity, id, true, runnable); + public static void getWithSession(Object persistantEntity, Serializable id, Consumer<Session> consumer) { + getWithSession(persistantEntity, id, true, consumer); } - public static void getWithSession(Object persistantEntity, Serializable id, boolean close, Runnable runnable) { + + /** + * @param persistantEntity The entity to load + * @param id The identifier for the entity + * @param close If the session should be closed after consumer is executed + * @param consumer The comsumer, which exposes the session + */ + public static void getWithSession(Object persistantEntity, Serializable id, boolean close, Consumer<Session> consumer) { Session session = SessionManager.getSessionFactory().openSession(); tryLoad(session, persistantEntity, id); - runnable.run(); + consumer.accept(session); if (close) session.close(); From 7bfadb05f7340d7f0cfb759fb6182f80c091e954 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 26 Mar 2022 18:13:56 -0400 Subject: [PATCH 082/155] Split queue management in its own class and use a double-ended queue instead --- .../command/AbstractMusicCommand.java | 5 +- .../command/basic/HelpCommand.java | 2 +- .../command/bot/ConfigureCommand.java | 34 +++- .../command/message/BlacklistCommand.java | 4 - .../music/CurrentlyPlayingCommand.java | 8 +- .../command/music/DeleteQueueCommand.java | 13 +- .../command/music/LeaveCommand.java | 6 +- .../command/music/PlayCommand.java | 8 +- .../command/music/SkipCommand.java | 22 ++- .../command/music/StopCommand.java | 9 +- .../command/music/ViewQueueCommand.java | 17 +- .../command/music/VolumeCommand.java | 27 ++- .../command/music/VoteSkipCommand.java | 6 +- .../java/netneutrality/core/GuildManager.java | 1 + .../core/context/CommandContext.java | 5 + .../netneutrality/music/MusicManager.java | 63 +++--- .../netneutrality/music/QueueManager.java | 187 ++++++++++++++++++ .../netneutrality/music/SourceFinder.java | 31 +-- .../netneutrality/music/TopicManager.java | 74 +++++++ .../netneutrality/music/TrackScheduler.java | 160 +++------------ .../MusicPlayerAutoDisconnectThread.java | 7 +- .../netneutrality/utils/MessageFunction.java | 2 +- .../java/netneutrality/utils/MusicUtils.java | 13 +- src/main/resources/log4j2.properties | 6 + 24 files changed, 446 insertions(+), 264 deletions(-) create mode 100644 src/main/java/netneutrality/music/QueueManager.java create mode 100644 src/main/java/netneutrality/music/TopicManager.java diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index afcf418..13bfb6a 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -6,7 +6,10 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.GuildManager; import netneutrality.utils.UserFunction; diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 7a3d2c1..c8eef3e 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -9,9 +9,9 @@ package netneutrality.command.basic; import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; import netneutrality.command.AbstractCommand; -import netneutrality.core.CommandManager; import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; +import netneutrality.core.CommandManager; import netneutrality.core.context.CommandContext; import netneutrality.utils.MessageFunction; import netneutrality.utils.UserFunction; diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 8254d3d..b564262 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -41,7 +41,7 @@ public class ConfigureCommand extends AbstractCommand { @Override public CommandUsage getUsage() { return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"musicrole", "music-channel", "musicvolume", "debug"}, "") + new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"music-role", "music-channel", "music-volume", "music-topic", "debug"}, "") ); } @@ -63,7 +63,7 @@ public class ConfigureCommand extends AbstractCommand { if (args.length > 0) { // Role for music commands - if (context.getArg(0).equals("musicrole")) { + if (context.getArg(0).equals("music-role")) { if (args.length == 1) { String roleDb = guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE); Role role = null; @@ -72,7 +72,7 @@ public class ConfigureCommand extends AbstractCommand { } context.reply("Current role needed to use music commands (default is everyone): %s", (role == null ? "Everyone" : role.getAsMention())); - context.reply("Reset role using 'conf musicrole reset' or set it using 'conf musicrole @'"); + context.reply("Reset role using 'conf music-role reset' or set it using 'conf musicrole @'"); } if (args.length == 2) { @@ -129,12 +129,12 @@ public class ConfigureCommand extends AbstractCommand { } // Default volume for music player - if (context.getArg(0).equals("musicvolume")) { + if (context.getArg(0).equals("music-volume")) { if (args.length == 1) { int volume = Integer.parseInt(guildManager.getSetting(GuildManager.Settings.MUSIC_VOLUME)); - context.reply("Default volume for music player: " + volume); - context.reply("Set using 'conf musicvolume <value between 0 and 100>'"); + context.reply("Default volume for music player: %d", volume); + context.reply("Set using 'conf music-volume <value between 0 and 100>'"); } if (args.length == 2) { @@ -155,6 +155,28 @@ public class ConfigureCommand extends AbstractCommand { } } + // Music topic change + if (context.getArg(0).equals("music-topic")) { + if (args.length == 1) { + boolean enabled = "1".equals(guildManager.getSetting(GuildManager.Settings.MUSIC_TOPIC)); + + context.reply("Set currently playing track in text channel topic: %s", (enabled ? "enabled" : "disabled")); + context.reply("Use 'conf music-topic 0/1' to toggle between states (0 = disabled, 1 = enabled)."); + } + + if (args.length == 2) { + String str = args[1]; + boolean enabled = "1".equals(guildManager.getSetting(GuildManager.Settings.MUSIC_TOPIC)); + if (str.equals("0") || str.equals("1")) { + guildManager.setSettingValue(GuildManager.Settings.MUSIC_TOPIC, str); + enabled = "1".equals(str); + } + + context.reply("Set currently playing track in text channel topic is now %s for this guild", (enabled ? "enabled" : "disabled")); + + } + } + // Debug if (context.getArg(0).equals("debug")) { if (args.length == 1) { diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 506b11c..fc13906 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -59,10 +59,6 @@ public class BlacklistCommand extends AbstractCommand { String[] args = context.getArgumentsAsArray(); DBBlacklist controller = DBController.get("blacklist", DBBlacklist.class); - if (controller == null) { - - } - if (args.length > 0 && args.length < 3) { String word = (args.length == 2 ? args[1] : ""); diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index d673627..57ee083 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -7,7 +7,6 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; @@ -44,13 +43,10 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { - Member member = context.getGuildUser(); MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - if (player.getCurrentlyPlaying() != null) { - context.reply(MessageFunction.buildCurrentlyPlayingMessage(player, member)); + if (MusicUtils.checkIfConnected(player, context) && player.isCurrentlyPlaying()) { + context.reply(MessageFunction.buildCurrentlyPlayingMessage(player, context.getGuildUser())); } else { context.reply("Player is not playing any tracks right now"); } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 06e1b55..669bb6c 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -17,6 +17,11 @@ import netneutrality.utils.MusicUtils; public class DeleteQueueCommand extends AbstractMusicCommand { + @Override + public boolean needAdmin() { + return true; + } + @Override public boolean isEnabled() { return true; @@ -47,10 +52,8 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - if (!MusicUtils.checkIfDj(player, context)) + if (!MusicUtils.checkIfConnected(player, context)) return; if (context.getArgumentsAsArray().length == 0) { @@ -60,12 +63,12 @@ public class DeleteQueueCommand extends AbstractMusicCommand { if (context.getArgumentsAsArray().length > 0) { - int queueSize = player.getScheduler().getQueue().size(); + int queueSize = player.getQueueSize(); if (context.getArg(0).equals("all")) { if (queueSize > 0) { player.leave(); - player.getScheduler().getQueue().clear(); + player.getScheduler().getQueueManager().getQueue().clear(); context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); } else { context.reply("Queue is empty!"); diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 829d943..9a1d844 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -47,9 +47,9 @@ public class LeaveCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - player.leave(); + if (MusicUtils.checkIfConnected(player, context)) { + player.leave(); + } } } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index df719d5..07df0c2 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -12,6 +12,8 @@ import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; +import java.util.concurrent.TimeUnit; + public class PlayCommand extends AbstractMusicCommand { @Override @@ -45,12 +47,12 @@ public class PlayCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - context.getMessage().delete().queue(); + context.getMessage().delete().queueAfter(1, TimeUnit.SECONDS); - if (context.getArgumentsAsArray().length > 0) { + if (context.getArgs().length > 0) { player.play(context.getMessageText(), context, false, false); - } else { + //TODO: resume queue context.reply(getUsage()); } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 5b56405..86cab80 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -43,19 +43,23 @@ public class SkipCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); + if (!MusicUtils.checkIfConnected(player, context)) return; - // Combined fonctionality of vote skip - //TODO: clean ifs - if (context.getArgumentsAsArray().length > 0 && UserFunction.isAdmin(context.getGuildUser())) { - int skips = Integer.parseInt(context.getArg(0)); - player.skip(skips); - } else { - if (UserFunction.isAdmin(context.getGuildUser())) + if (UserFunction.isAdmin(context.getGuildUser())) { + if (context.getArgs().length > 0) { + try { + int skips = Integer.parseInt(context.getArg(0)); + player.skip(skips); + } catch (NumberFormatException e) { + context.reply("Please enter how many track(s) to skip"); + } + } else { player.skip(1); - else - player.voteSkip(context); + } + } else { + player.voteSkip(context); } } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 5dcec88..3c23419 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -12,7 +12,6 @@ import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; -import netneutrality.utils.UserFunction; public class StopCommand extends AbstractMusicCommand { @@ -38,17 +37,15 @@ public class StopCommand extends AbstractMusicCommand { @Override public String getDescription() { - return "Stop the music player, emptying the queue in the process"; + return "Stop the music player, keeping the current queue."; } @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - if (UserFunction.isAdmin(context.getGuildUser()) || context.getGuildUser().getId().equals(player.getRequesterOfCurrentTrack().getId())) { - player.leave(); + if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { + player.stopTrack(); } } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index ea86e90..c6afbbc 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -7,7 +7,6 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Member; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; @@ -48,16 +47,16 @@ public class ViewQueueCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { - Member member = context.getGuildUser(); MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - int queueSize = player.getScheduler().getQueue().size(); - if (queueSize > 0) { - context.reply(MessageFunction.buildViewQueueMessage(player, member, true)); - } else { - context.reply("Queue is empty!"); + if (MusicUtils.checkIfConnected(player, context)) { + int queueSize = player.getQueueSize(); + if (queueSize > 0) { + context.reply(MessageFunction.buildViewQueueMessage(player, context.getGuildUser(), true)); + } else { + context.reply("Queue is empty!"); + } } + } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index e7f12cb..95ac941 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -10,7 +10,6 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -44,24 +43,20 @@ public class VolumeCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - if (!MusicUtils.checkIfDj(player, context)) - return; + if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { + try { + int volume = Integer.parseInt(context.getArg(0)); - try { - int volume = Integer.parseInt(context.getArg(0)); + if (volume > 0 && volume <= 100) { + player.setVolume(volume); + context.reply("Volume set to %s", volume); + } else + throw new NumberFormatException(); - if (volume > 0 && volume <= 100) { - player.setVolume(volume); - context.reply("Volume set to %s", volume); - } else - throw new NumberFormatException(); - - } catch (NumberFormatException e) { - context.reply("Please enter a value from 0 to 100"); + } catch (NumberFormatException e) { + context.reply("Please enter a value from 0 to 100"); + } } - } } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index 1b656a7..65606b7 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -42,9 +42,9 @@ public class VoteSkipCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (!MusicUtils.checkIfConnected(player, context)) - return; - player.voteSkip(context); + if (MusicUtils.checkIfConnected(player, context)) { + player.voteSkip(context); + } } } diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 91b6697..9e311ef 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -38,6 +38,7 @@ public class GuildManager { MUSIC_ROLE("MUSIC_ROLE", ""), MUSIC_CHANNEL("MUSIC_CHANNEL", ""), MUSIC_VOLUME("MUSIC_VOLUME", "30"), + MUSIC_TOPIC("MUSIC_TOPIC", "0"), BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); private final String name; diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 0b82b40..0dd780a 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -67,6 +67,10 @@ public class CommandContext { return getArgumentsAsArray()[index]; } + public String[] getArgs() { + return getArgumentsAsArray(); + } + public String[] getArgumentsAsArray() { String msg = message.getContentDisplay().trim(); msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); @@ -180,6 +184,7 @@ public class CommandContext { try { if (command.needAdmin() && !UserFunction.isAdmin(member)) { + reply("You are not powerful enough, scrub"); return; } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 476d8eb..64e0ca9 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -56,7 +56,7 @@ public class MusicManager { this.guild = guild; this.playerManager = new DefaultAudioPlayerManager(); this.player = playerManager.createPlayer(); - this.scheduler = new TrackScheduler(player); + this.scheduler = new TrackScheduler(player, guild); this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME)); AudioSourceManagers.registerRemoteSources(playerManager); @@ -105,8 +105,12 @@ public class MusicManager { return player.getPlayingTrack(); } + public synchronized boolean isCurrentlyPlaying() { + return player.getPlayingTrack() != null; + } + public synchronized Member getRequesterOfCurrentTrack() { - TrackScheduler.TrackInfo info = scheduler.getQueue().peek(); + QueueManager.TrackInfo info = scheduler.getQueueManager().getQueue().peek(); if (info == null) return null; @@ -124,7 +128,7 @@ public class MusicManager { guild.getAudioManager().closeAudioConnection(); } - scheduler.resetTopic(); + scheduler.getTopicManager().detachTextChannel(); if (autoDisconnectThread != null) { boolean cancel = autoDisconnectThread.cancel(true); @@ -138,7 +142,7 @@ public class MusicManager { for (MusicManager mm : managers.values()) { mm.leave(); mm.player.destroy(); - mm.scheduler.getQueue().clear(); + mm.scheduler.getQueueManager().getQueue().clear(); } } @@ -157,12 +161,14 @@ public class MusicManager { } if (!member.getVoiceState().inVoiceChannel()) { - throw new CommandErrorException("You are not in a voice channel", context, null); + context.reply("You are not in a voice channel"); + return; } VoiceChannel vChannel = member.getVoiceState().getChannel(); if (needToBeConnected && !isConnectedTo(vChannel)) { - throw new CommandErrorException("Not in your voice channel", context, null); + context.reply("The player is not in your voice channel"); + return; } if (!isConnectedTo(vChannel)) { @@ -170,7 +176,7 @@ public class MusicManager { } String identifier = SourceFinder.getIdentifier(url); - scheduler.setTextChannel(channel); + scheduler.getTopicManager().attachTextChannel(channel); if (identifier != null) { @@ -179,12 +185,11 @@ public class MusicManager { @Override public void trackLoaded(AudioTrack audioTrack) { logger.debug("Found results for identifier: {}", identifier); + scheduler.getQueueManager().queue(audioTrack, member); if (!silent) { channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)).queue(); } - - scheduler.queue(audioTrack, member); } @Override @@ -192,20 +197,22 @@ public class MusicManager { if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); logger.debug("Found results for identifier: {}", identifier); + scheduler.getQueueManager().queue(track, member); - if (!silent) + if (!silent) { channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); + } - scheduler.queue(track, member); } else { logger.debug("Found results for playlist identifier: {}", identifier); - if (!silent) + if (!silent) { channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)).queue(); + } for (AudioTrack track : audioPlaylist.getTracks()) { - synchronized (scheduler.getQueue()) { - scheduler.queue(track, member); + synchronized (scheduler.getQueueManager().getQueue()) { + scheduler.getQueueManager().queue(track, member); } } } @@ -232,7 +239,7 @@ public class MusicManager { if (num == 1) { skip(1); } else { - scheduler.removeFromQueue(num); + scheduler.getQueueManager().removeFromQueue(num); } } @@ -241,23 +248,23 @@ public class MusicManager { } public synchronized void skip(int nbTrack) { - if (!scheduler.getQueue().isEmpty()) { - if (nbTrack >= scheduler.getQueue().size()) { + if (!scheduler.getQueueManager().getQueue().isEmpty()) { + if (nbTrack >= scheduler.getQueueManager().getQueue().size()) { nbTrack = 1; } - scheduler.skipAndPlay(nbTrack); + scheduler.getQueueManager().skipAndPlay(nbTrack); } else { leave(); } } public synchronized void voteSkip(CommandContext context) { - Queue<TrackScheduler.TrackInfo> queue = scheduler.getQueue(); + Queue<QueueManager.TrackInfo> queue = scheduler.getQueueManager().getQueue(); VoiceChannel voiceChannel = guild.getAudioManager().getConnectedChannel(); - TrackScheduler.TrackInfo info = queue.peek(); + QueueManager.TrackInfo info = queue.peek(); - if (getCurrentlyPlaying() == null || voiceChannel == null) { + if (!isCurrentlyPlaying() || voiceChannel == null) { return; } @@ -290,15 +297,15 @@ public class MusicManager { player.setVolume(volume); } + public int getQueueSize () { + synchronized (scheduler.getQueueManager().getQueue()) { + return scheduler.getQueueManager().getQueue().size(); + } + + } + public TrackScheduler getScheduler() { return scheduler; } - public synchronized ArrayList<AudioTrack> getAllQueuedTrack() { - ArrayList<AudioTrack> tracks = new ArrayList<>(); - Queue<TrackScheduler.TrackInfo> queue = scheduler.getQueue(); - - queue.forEach(trackInfo -> tracks.add(trackInfo.getTrack())); - return tracks; - } } diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java new file mode 100644 index 0000000..cf27ad5 --- /dev/null +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -0,0 +1,187 @@ +package netneutrality.music;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; + +import java.util.*; +import java.util.concurrent.LinkedBlockingDeque; + +public class QueueManager { + + static class TrackInfo { + + private final AudioTrack track; + private final Member member; + private final Set<String> skips; + + public TrackInfo(AudioTrack track, Member member) { + this.track = track; + this.member = member; + this.skips = new HashSet<>(); + } + + public AudioTrack getTrack() { + return track; + } + + public Set<String> getSkips() { + return skips; + } + + public void toggleSkip(Member member) { + if (!hasSkip(member)) + skips.add(member.getId()); + else + skips.remove(member.getId()); + } + + public boolean hasSkip(Member member) { + return skips.contains(member.getId()); + } + + public Member getRequester() { + return member; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TrackInfo trackInfo = (TrackInfo) o; + return track.equals(trackInfo.track); + } + + @Override + public int hashCode() { + return Objects.hash(track); + } + + @Override + public String toString() { + return "TrackInfo{" + + "track=" + track.getInfo().title + + ", member=" + member.getEffectiveName() + + ", skips=" + skips + + '}'; + } + } + + private final AudioPlayer player; + private final Guild guild; + private final Deque<TrackInfo> queue; + + public QueueManager(AudioPlayer player, Guild guild) { + this.player = player; + this.guild = guild; + + this.queue = new LinkedBlockingDeque<>(); + } + + public Queue<TrackInfo> getQueue() { + synchronized (queue) { + return queue; + } + } + + public Guild getGuild() { + return guild; + } + + public ArrayList<AudioTrack> getAllQueuedTrack() { + synchronized (queue) { + ArrayList<AudioTrack> tracks = new ArrayList<>(); + + queue.forEach(trackInfo -> tracks.add(trackInfo.getTrack())); + return tracks; + } + } + + public void queue(AudioTrack track, Member member) { + TrackInfo info = new TrackInfo(track, member); + + synchronized (queue) { + if (queue.contains(info)) { + return; + } + + if (player.getPlayingTrack() == null && !queue.isEmpty()) { + queue.addFirst(info); + } + + if ((player.getPlayingTrack() == null && queue.isEmpty()) || player.getPlayingTrack() != null) { + queue.add(info); + } + + if (player.getPlayingTrack() == null) { + player.startTrack(queue.peek().getTrack(), false); + } + } + } + + public void nextTrack(AudioPlayer player) { + synchronized (queue) { + TrackInfo last = queue.poll(); + + if (queue.peek() != null) { + player.startTrack(queue.peek().getTrack(), false); + } else { + player.stopTrack(); + } + } + + } + + public void skipAndPlay(int nb) { + if (nb == 0) + return; + + synchronized (queue) { + for (int i = 0; i < nb; i++) { + TrackInfo last = queue.poll(); + } + + TrackInfo current = queue.peek(); + if (current != null) { + player.startTrack(current.getTrack(), false); + } else { + player.stopTrack(); + } + } + + } + + public void shuffle() { + synchronized (queue) { + if (queue.size() > 2) { + TrackInfo current = queue.poll(); + + ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); + newQueue.remove(0); + + Collections.shuffle(newQueue); + + queue.clear(); + queue.add(current); + queue.addAll(newQueue); + } + } + } + + protected void removeFromQueue(int index) { + synchronized (queue) { + ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); + newQueue.remove(index - 1); + + queue.clear(); + queue.addAll(newQueue); + } + } + +} diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index 6e9328c..eca65df 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -10,36 +10,37 @@ package netneutrality.music; import java.util.regex.Matcher; import java.util.regex.Pattern; -enum SourceEnum { - Youtube, - Soundcloud, - Bandcamp, - Vimeo, - YTSearch, - Nothing - -} - public class SourceFinder { + + public enum AvailableSource { + Youtube, + Soundcloud, + Bandcamp, + Vimeo, + YTSearch, + Nothing + + } + private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); private static Matcher BandcampMatcher; private static Matcher vimeoMatcher; - public static SourceEnum getSource(String url) { + public static AvailableSource getSource(String url) { Matcher youtubeMatcher = youtubePattern.matcher(url); Matcher soundcloudMatcher = soundcloudPattern.matcher(url); if (youtubeMatcher.find()) - return SourceEnum.Youtube; + return AvailableSource.Youtube; if (soundcloudMatcher.find()) - return SourceEnum.Soundcloud; + return AvailableSource.Soundcloud; if (!(url.startsWith("http://") || url.startsWith("https://"))) - return SourceEnum.YTSearch; + return AvailableSource.YTSearch; - return SourceEnum.Nothing; + return AvailableSource.Nothing; } public static String getIdentifier(String url) { diff --git a/src/main/java/netneutrality/music/TopicManager.java b/src/main/java/netneutrality/music/TopicManager.java new file mode 100644 index 0000000..76e2b99 --- /dev/null +++ b/src/main/java/netneutrality/music/TopicManager.java @@ -0,0 +1,74 @@ +package netneutrality.music;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.core.GuildManager; +import netneutrality.thread.ThreadManager; +import org.apache.logging.log4j.LogManager; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class TopicManager { + + private final ScheduledExecutorService service; + private final Guild guild; + private TextChannel channel; + private String originalTopic; + + public TopicManager(Guild guild) { + this.guild = guild; + this.service = (ScheduledExecutorService) ThreadManager.getExecutor("topic-management", ThreadManager.ExecutorType.SCHEDULED); + } + + public Guild getGuild() { + return guild; + } + + public TextChannel getTextChannel() { + return channel; + } + + public String getOriginalTopic() { + return originalTopic; + } + + public synchronized void attachTextChannel(TextChannel channel) { + this.channel = channel; + + if (originalTopic == null) { + String current = channel.getTopic(); + originalTopic = (current == null ? "" : current); + } + } + + public synchronized void detachTextChannel() { + updateTopic(null); + + this.channel = null; + this.originalTopic = null; + } + + public synchronized void updateTopic(AudioTrack track) { + if (isEnabled() && channel != null) { + + if (track == null) { + LogManager.getLogger(TopicManager.class).debug("Resetting topic for channel [{}] in guild [{}]", channel.getId(), guild.getId()); + channel.getManager().setTopic(originalTopic).queueAfter(3, TimeUnit.SECONDS, service); + } else { + channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(3, TimeUnit.SECONDS, service); + } + + } + } + + private boolean isEnabled() { + return "1".equals(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_TOPIC)); + } +} diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 26e05da..a3e13de 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -12,142 +12,35 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.Guild; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; - public class TrackScheduler extends AudioEventAdapter { - static class TrackInfo { - - private final AudioTrack track; - private final Member member; - private final Set<String> skips; - - public TrackInfo(AudioTrack track, Member member) { - this.track = track; - this.member = member; - this.skips = new HashSet<>(); - } - - public AudioTrack getTrack() { - return track; - } - - public Set<String> getSkips() { - return skips; - } - - public void toggleSkip(Member member) { - if (!hasSkip(member)) - skips.add(member.getId()); - else - skips.remove(member.getId()); - } - - public boolean hasSkip(Member member) { - return skips.contains(member.getId()); - } - - public Member getRequester() { - return member; - } - } - private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class); + private final QueueManager queueManager; + private final TopicManager topicManager; private final AudioPlayer player; - private final Queue<TrackInfo> queue; - private TextChannel channel; - private String originalTopic; + private final Guild guild; - public TrackScheduler(AudioPlayer player) { + public TrackScheduler(AudioPlayer player, Guild guild) { this.player = player; - this.queue = new LinkedBlockingQueue<>(); + this.guild = guild; + this.queueManager = new QueueManager(player, guild); + this.topicManager = new TopicManager(guild); } - public synchronized void queue(AudioTrack track, Member member) { - // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If - // something is playing, it returns false and does nothing. In that case the player was already playing so this - // track goes to the queue instead. - queue.offer(new TrackInfo(track, member)); - - if (player.getPlayingTrack() == null) { - player.startTrack(track, true); - } - + public QueueManager getQueueManager() { + return queueManager; } - public synchronized String getOriginalTopic() { - return originalTopic; + public TopicManager getTopicManager() { + return topicManager; } - public TextChannel getTextChannel() { - return channel; - } - - public synchronized void setTextChannel(TextChannel channel) { - this.channel = channel; - - if (originalTopic == null) { - originalTopic = channel.getTopic(); - } - - } - - public synchronized void resetTextChannel() { - this.channel = null; - } - - public synchronized Queue<TrackInfo> getQueue() { - return queue; - } - - public synchronized void resetTopic() { - if (channel != null && (originalTopic != null && !originalTopic.isEmpty())) { - //channel.getManager().setTopic(topic).queue(); - } - - originalTopic = null; - } - - public synchronized void nextTrack(AudioPlayer player) { - TrackInfo last = queue.poll(); - - if (queue.peek() != null) { - player.startTrack(queue.peek().getTrack(), false); - } else - player.stopTrack(); - } - - public synchronized void skipAndPlay(int nb) { - if (nb == 0) - return; - - for (int i = 0; i < nb; i++) { - TrackInfo last = queue.poll(); - } - - TrackInfo current = queue.peek(); - if (current != null) { - player.startTrack(current.getTrack(), false); - } else { - player.stopTrack(); - } - } - - protected synchronized void removeFromQueue(int index) { - ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); - newQueue.remove(index - 1); - - queue.clear(); - queue.addAll(newQueue); + public AudioPlayer getPlayer() { + return player; } @Override @@ -162,30 +55,25 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { - logger.debug("Starting track on guild {}: {}", channel.getGuild().getId(), track.getIdentifier()); - // A track started playing - //channel.getManager().setTopic(":speaker: Now playing : " + track.getInfo().title).queue(); + logger.debug("Starting track on guild {}: {}", guild.getId(), track.getIdentifier()); + topicManager.updateTopic(track); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { - resetTopic(); - // check if mayStartNext if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { - //logger.debug("Queue size before next: " + queue.size()); - nextTrack(player); + queueManager.nextTrack(player); } if (endReason == AudioTrackEndReason.STOPPED) { - synchronized (queue) { - queue.poll(); + synchronized (queueManager.getQueue()) { + topicManager.updateTopic(null); + queueManager.getQueue().poll(); } } - //logger.debug("Queue size after next: " + queue.size()); - // endReason == FINISHED: A track finished or died by an exception (mayStartNext = true). // endReason == LOAD_FAILED: Loading of a track failed (mayStartNext = true). // endReason == STOPPED: The player was stopped. @@ -196,13 +84,13 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { - resetTopic(); - channel.sendMessage("Error while playing track: " + track.getInfo().title).queue(); + topicManager.updateTopic(null); + topicManager.getTextChannel().sendMessage("Error while playing track: " + track.getInfo().title).queue(); } @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { - resetTopic(); - nextTrack(player); + topicManager.updateTopic(null); + queueManager.nextTrack(player); } } diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index 4e3101b..a7141c5 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -26,15 +26,10 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { Guild guild = manager.getGuild(); VoiceChannel channel = guild.getAudioManager().getConnectedChannel(); - if (manager.getCurrentlyPlaying() == null && manager.getScheduler().getQueue().isEmpty()) { - manager.leave(); - return; - } - if (channel != null) { List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); - if (members.size() == 0) + if (members.size() == 0 || manager.getScheduler().getQueueManager().getQueue().isEmpty()) manager.leave(); } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 9c40b2b..6fb83be 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -107,7 +107,7 @@ public class MessageFunction { } public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user, boolean currentlyPlaying) { - ArrayList<AudioTrack> tracks = manager.getAllQueuedTrack(); + ArrayList<AudioTrack> tracks = manager.getScheduler().getQueueManager().getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); EmbedBuilder message = new EmbedBuilder(); diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index a68973d..fee8dee 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -22,12 +22,12 @@ public class MusicUtils { return false; } - VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); if (!manager.isConnected()) { context.reply("You are not in a voice channel"); return false; } + VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); if (!manager.isConnectedTo(vChannel)) { context.reply("You are not in a voice channel"); return false; @@ -36,13 +36,14 @@ public class MusicUtils { return true; } - public static boolean checkIfDj(MusicManager manager, CommandContext context) { - if (manager.getCurrentlyPlaying() != null) { - if (!UserFunction.isAdmin(context.getGuildUser()) || !manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) { + public static boolean isDj(MusicManager manager, CommandContext context) { + if (manager.isCurrentlyPlaying()) { + if (UserFunction.isAdmin(context.getGuildUser()) || manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) { + return true; + } else { context.reply("You are not powerful enough, scrub"); return false; - } else - return true; + } } return false; diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties index b859553..39aaad3 100644 --- a/src/main/resources/log4j2.properties +++ b/src/main/resources/log4j2.properties @@ -24,6 +24,12 @@ logger.hibernate.level = info logger.hibernate.additivity = false logger.hibernate.appenderRef.rolling.ref = LogToRollingFile +logger.jda.name = net.dv8tion.jda +logger.jda.level = info +logger.jda.additivity = false +logger.jda.appenderRef.rolling.ref = LogToRollingFile +logger.jda.appenderRef.console.ref = consoleLogger + logger.app.name = netneutrality logger.app.level = debug logger.app.additivity = false From 8325256e5ea9ee72873f7fb80c4024ff565a7c44 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Fri, 27 May 2022 18:16:22 -0400 Subject: [PATCH 083/155] Improve music manager and add more debug messages --- .../java/netneutrality/NetNeutrality.java | 8 +- .../command/crypto/BitcoinPriceCommand.java | 4 +- .../command/crypto/CryptoPriceCommand.java | 4 +- .../command/crypto/EthereumPriceCommand.java | 4 +- .../command/crypto/LitecoinPriceCommand.java | 4 +- .../command/message/BlacklistCommand.java | 2 +- .../command/music/DeleteQueueCommand.java | 7 +- .../command/music/JoinCommand.java | 6 +- .../command/music/LeaveCommand.java | 1 + .../command/music/PlayCommand.java | 3 - .../command/music/SkipCommand.java | 3 + .../command/music/StopCommand.java | 1 + .../command/specific/DatabaseCommand.java | 4 +- .../netneutrality/core/CommandManager.java | 4 +- .../java/netneutrality/core/GuildManager.java | 2 +- .../core/context/CommandContext.java | 29 +++ .../netneutrality/db/AbstractController.java | 7 - .../java/netneutrality/db/DBController.java | 72 +----- .../db/controllers/DBBlacklist.java | 5 - .../db/controllers/DBMessage.java | 6 - .../handler/hooks/message/EditHandler.java | 4 +- .../java/netneutrality/http/WebModule.java | 13 +- .../netneutrality/music/MusicManager.java | 233 +++++++++++++----- .../netneutrality/music/QueueManager.java | 58 ++++- .../netneutrality/music/TopicManager.java | 20 +- .../netneutrality/music/TrackScheduler.java | 14 +- .../music/loadable/AppleMostPlayed.java | 42 ++++ .../music/loadable/CachedSource.java | 40 +++ .../music/loadable/LoadableMusicSource.java | 26 ++ .../music/loadable/LoadableSong.java | 19 ++ .../music/loadable/LoadableSourceManager.java | 59 +++++ .../MusicPlayerAutoDisconnectThread.java | 5 +- .../netneutrality/utils/MessageFunction.java | 13 +- .../java/netneutrality/utils/MusicUtils.java | 2 +- .../music/LoadableSourceTest.java | 31 +++ 35 files changed, 557 insertions(+), 198 deletions(-) create mode 100644 src/main/java/netneutrality/music/loadable/AppleMostPlayed.java create mode 100644 src/main/java/netneutrality/music/loadable/CachedSource.java create mode 100644 src/main/java/netneutrality/music/loadable/LoadableMusicSource.java create mode 100644 src/main/java/netneutrality/music/loadable/LoadableSong.java create mode 100644 src/main/java/netneutrality/music/loadable/LoadableSourceManager.java create mode 100644 src/test/java/netneutrality/music/LoadableSourceTest.java diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index e4d5c4e..3b8f600 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -18,6 +18,8 @@ import netneutrality.thread.BaseThreadFactory; import netneutrality.thread.ShutdownThread; import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,8 +40,12 @@ public class NetNeutrality { options.setDebug(env.equals("dev")); }); - initJDA(); + if ("dev".equals(env)) { + Configurator.setLevel("net.dv8tion.jda", Level.DEBUG); + } + DBController.init(); + initJDA(); CommandManager.init(); MusicManager.initPlayerManager(); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index adba8db..8e31c2d 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -86,14 +86,14 @@ public class BitcoinPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); JSONObject json = http.getAsObject(); - if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); return; } price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { + } catch (JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); LogHandler.log(e); } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index c05a072..1a220bb 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -89,7 +89,7 @@ public class CryptoPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); JSONObject json = http.getAsObject(); - if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { t.editMessage("Crypto doesn't exist.. yet").queue(); return; } @@ -97,7 +97,7 @@ public class CryptoPriceCommand extends AbstractCommand { price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { + } catch (JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); LogHandler.log(e); } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 65948cf..414f445 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -86,14 +86,14 @@ public class EthereumPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); JSONObject json = http.getAsObject(); - if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); return; } price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (IOException | JSONException | IllegalArgumentException e) { + } catch (JSONException | IllegalArgumentException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); LogHandler.log(e); } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 165cc51..4a1efb7 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -86,14 +86,14 @@ public class LitecoinPriceCommand extends AbstractCommand { try { WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); JSONObject json = http.getAsObject(); - if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { + if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); return; } price = dollarFormat.format(json.getDouble(finalCurrency)); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { + } catch (JSONException | IllegalArgumentException | ArithmeticException e) { t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); LogHandler.log(e); } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index fc13906..920b88d 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -57,7 +57,7 @@ public class BlacklistCommand extends AbstractCommand { @Override public void execute(CommandContext context) { String[] args = context.getArgumentsAsArray(); - DBBlacklist controller = DBController.get("blacklist", DBBlacklist.class); + DBBlacklist controller = DBController.get(DBBlacklist.class); if (args.length > 0 && args.length < 3) { String word = (args.length == 2 ? args[1] : ""); diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 669bb6c..000d060 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -79,8 +79,11 @@ public class DeleteQueueCommand extends AbstractMusicCommand { int num = Integer.parseInt(context.getArg(0)); if (num > 0) { - player.removeFromQueue(num); - context.reply("Removing track #%d from the queue", num); + if (player.removeFromQueue(num)) { + context.reply("Removed track #%d from the queue", num); + } else { + context.reply("Error while removing track #%d from the queue", num); + } } else { context.reply("Number out of range"); } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index d9c9b57..c12784e 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -60,6 +60,10 @@ public class JoinCommand extends AbstractMusicCommand { } VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); - player.connect(vChannel); + if (vChannel != null) { + player.connect(vChannel); + context.reply("Joining current voice channel"); + } + } } diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 9a1d844..0b1df1f 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -50,6 +50,7 @@ public class LeaveCommand extends AbstractMusicCommand { if (MusicUtils.checkIfConnected(player, context)) { player.leave(); + context.reply("Leaving voice channel and clearing queue"); } } } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 07df0c2..9c219ac 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -12,8 +12,6 @@ import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; -import java.util.concurrent.TimeUnit; - public class PlayCommand extends AbstractMusicCommand { @Override @@ -47,7 +45,6 @@ public class PlayCommand extends AbstractMusicCommand { @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - context.getMessage().delete().queueAfter(1, TimeUnit.SECONDS); if (context.getArgs().length > 0) { player.play(context.getMessageText(), context, false, false); diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 86cab80..eb784f3 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -52,11 +52,14 @@ public class SkipCommand extends AbstractMusicCommand { try { int skips = Integer.parseInt(context.getArg(0)); player.skip(skips); + + context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : "")); } catch (NumberFormatException e) { context.reply("Please enter how many track(s) to skip"); } } else { player.skip(1); + context.reply("Skipping current track"); } } else { player.voteSkip(context); diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 3c23419..fe0c0e6 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -46,6 +46,7 @@ public class StopCommand extends AbstractMusicCommand { if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { player.stopTrack(); + context.reply("Stopping current track"); } } } diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index 210b317..edd2928 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -74,7 +74,7 @@ public class DatabaseCommand extends AbstractCommand { if (args.length > 1) { - OLogMessage message = DBController.get("message", DBMessage.class).getMessage(args[1]); + OLogMessage message = DBController.get(DBMessage.class).getMessage(args[1]); if (message != null) { EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.BLUE); @@ -88,7 +88,7 @@ public class DatabaseCommand extends AbstractCommand { //TODO: cached user lol xd User user = context.getJDA().getUserById(args[1]); if (user != null) { - List<OLogMessage> messages = DBController.get("message", DBMessage.class) + List<OLogMessage> messages = DBController.get(DBMessage.class) .getMessagesFromUser(user.getName(), context.getGuild().getName(), 10); EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.BLUE); diff --git a/src/main/java/netneutrality/core/CommandManager.java b/src/main/java/netneutrality/core/CommandManager.java index 16a5234..049becc 100644 --- a/src/main/java/netneutrality/core/CommandManager.java +++ b/src/main/java/netneutrality/core/CommandManager.java @@ -49,8 +49,8 @@ public class CommandManager { commands.put(command.getCommandName(), command); } } catch (InstantiationException | IllegalAccessException | IllegalArgumentException - | InvocationTargetException | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + LogHandler.log(e); } } diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 9e311ef..e0a5558 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -228,7 +228,7 @@ public class GuildManager { public void checkAndLogMessage(Message message, Member member, TextChannel channel) { if (isLoggingEnabled()) { - ThreadManager.getExecutor("log-messages").submit(() -> DBController.get("message", DBMessage.class).log(this, channel, member, message)); + ThreadManager.getExecutor("log-messages").submit(() -> DBController.get(DBMessage.class).log(this, channel, member, message)); } } diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 0dd780a..22a08d4 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -24,6 +24,7 @@ import netneutrality.utils.UserFunction; import java.util.Collection; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; public class CommandContext { @@ -153,6 +154,18 @@ public class CommandContext { } } + public void replyToMessage(String msg) { + if (channel != null && channel.canTalk() && message != null) { + replyToMessage(new MessageBuilder(msg).build()); + } + } + + public void replyToMessage(Message msg) { + if (channel != null && channel.canTalk() && message != null) { + message.reply(msg).queue(); + } + } + public void replyPrivate(String msg) { replyPrivate(new MessageBuilder(msg).build()); } @@ -169,6 +182,22 @@ public class CommandContext { user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); } + public void deleteMessage() { + if (message != null) { + message.delete().queueAfter(1, TimeUnit.SECONDS); + } + } + + public boolean isMessageFromOwner() { + return member.isOwner(); + } + + public boolean isMessageFromCreator() { + String creatorId = Settings.getInstance().getCreatorId(); + + return creatorId.equals(member.getId()); + } + public void dispatch(AbstractCommand command) { this.command = command; //TODO: Add usage check diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/netneutrality/db/AbstractController.java index 7b8deae..b282546 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/netneutrality/db/AbstractController.java @@ -14,13 +14,6 @@ public abstract class AbstractController { protected SessionFactory sessionFactory; - /** - * The controller name to be used in {@link DBController#get(String controller, Class returnType)} method - * - * @return String - */ - public abstract String getControllerName(); - public AbstractController() { sessionFactory = SessionManager.getSessionFactory(); } diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 2476b64..051db3e 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -8,86 +8,32 @@ package netneutrality.db; */ import netneutrality.core.SessionManager; -import netneutrality.thread.ThreadManager; -import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.Set; -/** - * When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class - * A simple thread can't be used in this case because overlapping actions might happen and won't be executed. - */ public class DBController { - - /** - * A map that contains all the controllers currently loaded - */ - private final static HashMap<String, AbstractController> controllers = new HashMap<>(); + private final static Logger logger = LoggerFactory.getLogger(DBController.class); - /** - * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method - * @return {@link AbstractController} The class with an AbstractController type - */ - @SuppressWarnings("unchecked") - public static <T> T get(String controller, Class<T> returnType) { + public static <T> T get(Class<T> returnType) { if (returnType == null) throw new IllegalArgumentException("return type is null"); - if (controllers.isEmpty()) - init(); - - if (controllers.containsKey(controller)) { - return (T) controllers.get(controller); - } else - throw new RuntimeException("Error getting database controller"); + try { + return returnType.getConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException(e); + } } public static void shutdown() { SessionManager.shutdown(); } - - /** - * Optional, will be called if the method {@link #get(String, Class) get()} is used - */ + public static void init() { - if (controllers.isEmpty()) - loadControllers(); + SessionManager.getSessionFactory(); } - /** - * Loads all the controllers which extends {@link AbstractController} - */ - private static void loadControllers() { - //TODO: to delete - logger.info("Loading databases controllers.."); - - Reflections reflections = new Reflections("netneutrality.db.controllers"); - Set<Class<? extends AbstractController>> classes = reflections.getSubTypesOf(AbstractController.class); - - for (Class<? extends AbstractController> s : classes) { - try { - if (Modifier.isAbstract(s.getModifiers())) { - continue; - } - - AbstractController c = s.getConstructor().newInstance(); - - if (!controllers.containsKey(c.getControllerName())) { - controllers.put(c.getControllerName(), c); - logger.debug("Loaded controller: " + c.getControllerName()); - } - - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) { - e.printStackTrace(); - } - } - } - - } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 9f381e7..725316e 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -128,9 +128,4 @@ public class DBBlacklist extends AbstractController { session.close(); return blacklist; } - - @Override - public String getControllerName() { - return "blacklist"; - } } diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 3978b45..84d2641 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -96,10 +96,4 @@ public class DBMessage extends AbstractController { return message.getMessage(); } - - - @Override - public String getControllerName() { - return "message"; - } } diff --git a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java index 1f0bd94..03cc806 100644 --- a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/EditHandler.java @@ -46,8 +46,8 @@ public class EditHandler extends ListenerAdapter { TextChannel channel = event.getGuild().getTextChannelById(guildEntity.getLogChannel()); if (channel != null) { - String originalMessage = DBController.get("message", DBMessage.class).getMessageString(event.getMessage().getId()); - DBController.get("message", DBMessage.class).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); + String originalMessage = DBController.get(DBMessage.class).getMessageString(event.getMessage().getId()); + DBController.get(DBMessage.class).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); channel.sendMessageEmbeds(MessageFunction.buildEditMessage(event.getMember(), event.getMessage(), originalMessage)).queue(); } diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index 38a0b84..376037b 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -2,6 +2,7 @@ package netneutrality.http; import io.sentry.Breadcrumb; import io.sentry.Sentry; +import netneutrality.core.LogHandler; import okhttp3.*; import org.json.JSONArray; import org.json.JSONException; @@ -144,11 +145,17 @@ public class WebModule { /** * @return the response as a JSONObject */ - public JSONObject getAsObject() throws JSONException, IOException { + public JSONObject getAsObject() { if (response == null) throw new RuntimeException("Request has not been sent"); - - return new JSONObject(response.body().string()); + + try { + ResponseBody body = response.body(); + return new JSONObject(body.string()); + } catch (IOException | NullPointerException e) { + LogHandler.log(e); + return new JSONObject(); + } } /** diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 64e0ca9..01c4eea 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -21,16 +21,14 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.core.GuildManager; -import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandErrorException; +import netneutrality.music.loadable.LoadableSong; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Queue; @@ -45,21 +43,19 @@ public class MusicManager { private final static Map<String, MusicManager> managers = new ConcurrentHashMap<>(); private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); + private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); private final Guild guild; private final AudioPlayer player; - private final AudioPlayerManager playerManager; private final TrackScheduler scheduler; private ScheduledFuture<?> autoDisconnectThread; private final int baseVolume; private MusicManager(Guild guild) { this.guild = guild; - this.playerManager = new DefaultAudioPlayerManager(); this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(player, guild); this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME)); - AudioSourceManagers.registerRemoteSources(playerManager); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); @@ -75,6 +71,8 @@ public class MusicManager { } public static void initPlayerManager() { + AudioSourceManagers.registerRemoteSources(playerManager); + YoutubeHttpContextFilter.setPAPISID(netneutrality.utils.Settings.getInstance().get("BOT_PAPISID", "")); YoutubeHttpContextFilter.setPSID(netneutrality.utils.Settings.getInstance().get("BOT_PSID", "")); } @@ -85,6 +83,7 @@ public class MusicManager { public synchronized void connect(VoiceChannel vChannel) { if (vChannel != null && !isConnectedTo(vChannel)) { + logger.debug("Guild {}: connecting to voice channel {}", vChannel.getGuild().getId(), vChannel.getId()); guild.getAudioManager().openAudioConnection(vChannel); guild.getAudioManager().setSelfDeafened(true); player.setVolume(baseVolume); @@ -124,6 +123,7 @@ public class MusicManager { public synchronized void leave() { if (isConnected()) { + logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId()); player.stopTrack(); guild.getAudioManager().closeAudioConnection(); } @@ -155,6 +155,100 @@ public class MusicManager { public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); TextChannel channel = context.getChannel(); + logger.debug("Guild {}: request to play by user {}, string=[{}]", guild.getId(), context.getGuildUser().getId(), url); + + if (member.getVoiceState() == null) { + context.deleteMessage(); + return; + } + + if (!member.getVoiceState().inVoiceChannel()) { + context.reply("You are not in a voice channel"); + context.deleteMessage(); + return; + } + + VoiceChannel vChannel = member.getVoiceState().getChannel(); + if (needToBeConnected && !isConnectedTo(vChannel)) { + context.reply("The player is not in your voice channel"); + context.deleteMessage(); + return; + } + + if (!isConnectedTo(vChannel)) { + connect(vChannel); + } + + String identifier = SourceFinder.getIdentifier(url); + scheduler.getTopicManager().attachTextChannel(channel); + + if (identifier != null) { + playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { + + @Override + public void trackLoaded(AudioTrack audioTrack) { + logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); + context.deleteMessage(); + + scheduler.getQueueManager().queue(audioTrack, member); + + if (!silent) { + //context.replyToMessage("Added track to queue"); + context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)); + } + } + + @Override + public void playlistLoaded(AudioPlaylist audioPlaylist) { + logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); + context.deleteMessage(); + + if (audioPlaylist.isSearchResult()) { + AudioTrack track = audioPlaylist.getTracks().get(0); + scheduler.getQueueManager().queue(track, member); + + if (!silent) { + //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); + context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))); + } + + } else { + if (!silent) { + //context.replyToMessage("Added playlist to queue"); + context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)); + } + + for (AudioTrack track : audioPlaylist.getTracks()) { + synchronized (scheduler.getQueueManager().getQueue()) { + scheduler.getQueueManager().queue(track, member); + } + } + } + + + } + + @Override + public void noMatches() { + logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); + context.replyToMessage("No matches found"); + } + + @Override + public void loadFailed(FriendlyException e) { + logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); + context.replyToMessage("Failed to load track: " + e.getMessage()); + } + + }); + } else { + context.replyToMessage("No source found to play the given url"); + } + } + + public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) { + Member member = context.getGuildUser(); + TextChannel channel = context.getChannel(); if (member.getVoiceState() == null) { return; @@ -175,72 +269,89 @@ public class MusicManager { connect(vChannel); } - String identifier = SourceFinder.getIdentifier(url); scheduler.getTopicManager().attachTextChannel(channel); + boolean fromOnlineSource = songs.size() > 1; - if (identifier != null) { + for (LoadableSong song : songs) { + String identifier = SourceFinder.getIdentifier(song.name()); - playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { + if (identifier != null) { + playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { + @Override + public void trackLoaded(AudioTrack track) { + if (!fromOnlineSource) { + logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); + context.deleteMessage(); - @Override - public void trackLoaded(AudioTrack audioTrack) { - logger.debug("Found results for identifier: {}", identifier); - scheduler.getQueueManager().queue(audioTrack, member); + scheduler.getQueueManager().queue(track, member); - if (!silent) { - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)).queue(); - } - } - - @Override - public void playlistLoaded(AudioPlaylist audioPlaylist) { - if (identifier.startsWith("ytsearch:")) { - AudioTrack track = audioPlaylist.getTracks().get(0); - logger.debug("Found results for identifier: {}", identifier); - scheduler.getQueueManager().queue(track, member); - - if (!silent) { - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); - } - - } else { - logger.debug("Found results for playlist identifier: {}", identifier); - - if (!silent) { - channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)).queue(); - } - - for (AudioTrack track : audioPlaylist.getTracks()) { - synchronized (scheduler.getQueueManager().getQueue()) { - scheduler.getQueueManager().queue(track, member); + if (!silent) { + //context.replyToMessage("Added track to queue"); + context.reply(MessageFunction.buildAddingTrackMessage(track, member, identifier)); } } } - } - @Override - public void noMatches() { - context.reply("No matches found"); - } + @Override + public void playlistLoaded(AudioPlaylist playlist) { + logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - @Override - public void loadFailed(FriendlyException e) { - context.reply("Failed to load track: " + e.getMessage()); - LogHandler.log(e); - } + if (!playlist.getTracks().isEmpty()) { + context.deleteMessage(); + + if (playlist.isSearchResult()) { + AudioTrack track = playlist.getTracks().get(0); + scheduler.getQueueManager().queue(track, member); + + if (!silent && !fromOnlineSource) { + //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); + context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))); + } + + } else { + if (!silent && !fromOnlineSource) { + //context.replyToMessage("Added playlist to queue"); + context.reply(MessageFunction.buildAddingPlaylistMessage(playlist, member, identifier)); + } + + for (AudioTrack track : playlist.getTracks()) { + synchronized (scheduler.getQueueManager().getQueue()) { + scheduler.getQueueManager().queue(track, member); + } + } + } + } else { + context.replyToMessage("Playlist is empty"); + } + + } + + @Override + public void noMatches() { + logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); + + if (fromOnlineSource) { + //TODO: + } + context.replyToMessage("No matches found"); + } + + @Override + public void loadFailed(FriendlyException e) { + logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); + context.replyToMessage("Failed to load track: " + e.getMessage()); + } + }); + } else { + context.replyToMessage("No source found to play the given url"); + } - }); - } else { - throw new CommandErrorException("No source found to play the given url", context, null); } + } - public synchronized void removeFromQueue(int num) { - if (num == 1) { - skip(1); - } else { - scheduler.getQueueManager().removeFromQueue(num); - } + public synchronized boolean removeFromQueue(int index) { + return scheduler.getQueueManager().removeFromQueue(index); } public synchronized void stopTrack() { @@ -253,6 +364,7 @@ public class MusicManager { nbTrack = 1; } + logger.debug("Guild {}: skipping tracks, toSkip={}", guild.getId(), nbTrack); scheduler.getQueueManager().skipAndPlay(nbTrack); } else { leave(); @@ -278,13 +390,14 @@ public class MusicManager { if (connected > 2) { double needed = connected / 2.1; - info.toggleSkip(context.getGuildUser()); + info.addSkip(context.getGuildUser()); + logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId()); if (info.getSkips().size() > needed) { context.reply("Skipping current track: %s", info.getTrack().getInfo().title); skip(1); } else { - context.reply("Current skips: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); + context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); } } else { diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index cf27ad5..6e67c78 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -9,6 +9,8 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.LinkedBlockingDeque; @@ -20,6 +22,7 @@ public class QueueManager { private final AudioTrack track; private final Member member; private final Set<String> skips; + private final Logger logger = LoggerFactory.getLogger(QueueManager.class); public TrackInfo(AudioTrack track, Member member) { this.track = track; @@ -35,11 +38,21 @@ public class QueueManager { return skips; } - public void toggleSkip(Member member) { - if (!hasSkip(member)) + public void addSkip(Member member) { + if (!hasSkip(member)) { + logger.debug("VoteSkip: user={}, skip doesn't exist, before={}, after={}", member.getId(), skips.size(), skips.size() + 1); skips.add(member.getId()); - else + } + } + + public void toggleSkip(Member member) { + if (hasSkip(member)) { + logger.debug("VoteSkip: user={}, skip already exist, before={}, after={}", member.getId(), skips.size(), skips.size() - 1); skips.remove(member.getId()); + } else { + logger.debug("VoteSkip: user={}, skip doesn't exist, before={}, after={}", member.getId(), skips.size(), skips.size() + 1); + skips.add(member.getId()); + } } public boolean hasSkip(Member member) { @@ -73,6 +86,7 @@ public class QueueManager { } } + private final Logger logger = LoggerFactory.getLogger(QueueManager.class); private final AudioPlayer player; private final Guild guild; private final Deque<TrackInfo> queue; @@ -120,7 +134,8 @@ public class QueueManager { } if (player.getPlayingTrack() == null) { - player.startTrack(queue.peek().getTrack(), false); + AudioTrack toPlay = (queue.peek() == null ? null : queue.peek().getTrack()); + player.startTrack(toPlay, true); } } } @@ -128,9 +143,15 @@ public class QueueManager { public void nextTrack(AudioPlayer player) { synchronized (queue) { TrackInfo last = queue.poll(); + TrackInfo next = queue.peek(); - if (queue.peek() != null) { - player.startTrack(queue.peek().getTrack(), false); + if (next != null) { + if (last != null && last.getTrack().equals(next.getTrack())) { + logger.debug("Guild {}: duplicate track in queue found, skipping to next. last={}, next={}", guild.getId(), last.getTrack().getIdentifier(), next.getTrack().getIdentifier()); + nextTrack(player); + } else { + player.startTrack(next.getTrack(), false); + } } else { player.stopTrack(); } @@ -159,7 +180,8 @@ public class QueueManager { public void shuffle() { synchronized (queue) { - if (queue.size() > 2) { + if (queue.size() > 3) { + logger.debug("Guild {}: shuffling queue", guild.getId()); TrackInfo current = queue.poll(); ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); @@ -174,13 +196,25 @@ public class QueueManager { } } - protected void removeFromQueue(int index) { + protected boolean removeFromQueue(int index) { synchronized (queue) { - ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); - newQueue.remove(index - 1); + if (queue.size() > 0 && index <= queue.size()) { + logger.debug("Guild {}: removing index {} from queue", guild.getId(), index - 1); - queue.clear(); - queue.addAll(newQueue); + if (index == 1) { + skipAndPlay(1); + return true; + } + + ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); + newQueue.remove(index - 1); + + queue.clear(); + queue.addAll(newQueue); + return true; + } + + return false; } } diff --git a/src/main/java/netneutrality/music/TopicManager.java b/src/main/java/netneutrality/music/TopicManager.java index 76e2b99..6a7e267 100644 --- a/src/main/java/netneutrality/music/TopicManager.java +++ b/src/main/java/netneutrality/music/TopicManager.java @@ -9,22 +9,18 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.GuildManager; -import netneutrality.thread.ThreadManager; import org.apache.logging.log4j.LogManager; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TopicManager { - private final ScheduledExecutorService service; private final Guild guild; private TextChannel channel; private String originalTopic; public TopicManager(Guild guild) { this.guild = guild; - this.service = (ScheduledExecutorService) ThreadManager.getExecutor("topic-management", ThreadManager.ExecutorType.SCHEDULED); } public Guild getGuild() { @@ -59,16 +55,24 @@ public class TopicManager { if (isEnabled() && channel != null) { if (track == null) { - LogManager.getLogger(TopicManager.class).debug("Resetting topic for channel [{}] in guild [{}]", channel.getId(), guild.getId()); - channel.getManager().setTopic(originalTopic).queueAfter(3, TimeUnit.SECONDS, service); + LogManager.getLogger(TopicManager.class).debug("Guild {}: Resetting topic for channel {}", guild.getId(), channel.getId()); + channel.getManager().setTopic(originalTopic).queueAfter(5, TimeUnit.SECONDS); } else { - channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(3, TimeUnit.SECONDS, service); + LogManager.getLogger(TopicManager.class).debug("Guild {}: Setting topic for channel {} to [{}]", guild.getId(), channel.getId(), track.getInfo().title); + channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(5, TimeUnit.SECONDS); } } } + public void sendMessageToChannel(String msg) { + if (channel != null) { + channel.sendMessage(msg).queue(); + } + } + private boolean isEnabled() { - return "1".equals(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_TOPIC)); + // rate limiting too much + return false; } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index a3e13de..4d499fe 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -55,16 +55,21 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { - logger.debug("Starting track on guild {}: {}", guild.getId(), track.getIdentifier()); + logger.debug("Guild {}: starting track: {}", guild.getId(), track.getIdentifier()); topicManager.updateTopic(track); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { + logger.debug("Guild {}: currently playing track ended: {}", guild.getId(), track.getIdentifier()); + + if (endReason == AudioTrackEndReason.LOAD_FAILED) { + logger.debug("Guild {}: failed loading track: {}", guild.getId(), track.getIdentifier()); + } + // check if mayStartNext if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { queueManager.nextTrack(player); - } if (endReason == AudioTrackEndReason.STOPPED) { @@ -84,13 +89,16 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { + logger.debug("Guild {}: exception while playing track [{}]: {}", guild.getId(), track.getIdentifier(), exception.getMessage()); topicManager.updateTopic(null); - topicManager.getTextChannel().sendMessage("Error while playing track: " + track.getInfo().title).queue(); + topicManager.sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage()); } @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { + logger.debug("Guild {}: currently playing track is stuck: {}", guild.getId(), track.getIdentifier()); topicManager.updateTopic(null); + topicManager.sendMessageToChannel("Current track is stuck, skipping to next"); queueManager.nextTrack(player); } } diff --git a/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java b/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java new file mode 100644 index 0000000..b6e961b --- /dev/null +++ b/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java @@ -0,0 +1,42 @@ +package netneutrality.music.loadable; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class AppleMostPlayed implements LoadableMusicSource { + @Override + public String url() { + return "https://rss.applemarketingtools.com/api/v2/ca/music/most-played/25/songs.json"; + } + + @Override + public List<LoadableSong> parse(JSONObject obj) { + List<LoadableSong> songs = new ArrayList<>(); + JSONArray results = obj.getJSONObject("feed").getJSONArray("results"); + + results.forEach(o -> { + JSONObject song = (JSONObject) o; + String artist = song.getString("artistName"); + String songName = song.getString("name"); + String artwork = song.getString("artworkUrl100"); + + songs.add(new LoadableSong(artist, songName, artwork)); + }); + + return songs; + } + + @Override + public String getIdentifier() { + return "apple"; + } +} diff --git a/src/main/java/netneutrality/music/loadable/CachedSource.java b/src/main/java/netneutrality/music/loadable/CachedSource.java new file mode 100644 index 0000000..2dc83c3 --- /dev/null +++ b/src/main/java/netneutrality/music/loadable/CachedSource.java @@ -0,0 +1,40 @@ +package netneutrality.music.loadable; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import java.time.OffsetDateTime; +import java.util.List; + +public class CachedSource { + private final LoadableMusicSource source; + private OffsetDateTime lastAccess; + private final List<LoadableSong> songs; + + public CachedSource(LoadableMusicSource source, List<LoadableSong> songs) { + this.source = source; + this.lastAccess = OffsetDateTime.now(); + this.songs = songs; + } + + public List<LoadableSong> getSongs() { + return songs; + } + + public OffsetDateTime getLastAccess() { + return lastAccess; + } + + public LoadableMusicSource getSource() { + return source; + } + + public void updateAccessTime() { + this.lastAccess = OffsetDateTime.now(); + } + +} diff --git a/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java b/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java new file mode 100644 index 0000000..c1f6cd4 --- /dev/null +++ b/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java @@ -0,0 +1,26 @@ +package netneutrality.music.loadable; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import org.json.JSONObject; + +import java.util.List; + +public interface LoadableMusicSource { + String url(); + + List<LoadableSong> parse(JSONObject obj); + + String getIdentifier(); +} diff --git a/src/main/java/netneutrality/music/loadable/LoadableSong.java b/src/main/java/netneutrality/music/loadable/LoadableSong.java new file mode 100644 index 0000000..d5e2872 --- /dev/null +++ b/src/main/java/netneutrality/music/loadable/LoadableSong.java @@ -0,0 +1,19 @@ +package netneutrality.music.loadable; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +public record LoadableSong(String artist, String name, String artworkUrl) { + + @Override + public String toString() { + return "LoadableSong{" + + "artist='" + artist + '\'' + + ", name='" + name + '\'' + + ", artworkUrl='" + artworkUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java new file mode 100644 index 0000000..4265a3d --- /dev/null +++ b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java @@ -0,0 +1,59 @@ +package netneutrality.music.loadable; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.http.WebModule; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LoadableSourceManager { + + private final Logger logger = LoggerFactory.getLogger(LoadableSourceManager.class); + private static final Map<String, CachedSource> cache = new HashMap<>(); + + public CachedSource get(LoadableMusicSource source) { + + if (cache.containsKey(source.getIdentifier())) { + CachedSource cachedSource = cache.get(source.getIdentifier()); + + if (OffsetDateTime.now().isAfter(cachedSource.getLastAccess().plusHours(4))) { + cachedSource.getSongs().clear(); + cachedSource.getSongs().addAll(loadFromUrl(source)); + cachedSource.updateAccessTime(); + } + + return cachedSource; + } else { + List<LoadableSong> songs = loadFromUrl(source); + CachedSource newCachedSource = new CachedSource(source, songs); + + cache.put(source.getIdentifier(), newCachedSource); + return newCachedSource; + } + + } + + private List<LoadableSong> loadFromUrl(LoadableMusicSource source) { + WebModule web = new WebModule(source.url()); + JSONObject obj = web.request().getAsObject(); + + if (obj == null) + return Collections.emptyList(); + + List<LoadableSong> songs = source.parse(obj); + Collections.shuffle(songs); + + return songs; + } +} diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index a7141c5..2a22301 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.NetNeutrality; import netneutrality.music.MusicManager; +import org.slf4j.LoggerFactory; import java.util.List; @@ -29,8 +30,10 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { if (channel != null) { List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); - if (members.size() == 0 || manager.getScheduler().getQueueManager().getQueue().isEmpty()) + if (members.size() == 0 || manager.getScheduler().getQueueManager().getQueue().isEmpty()) { + LoggerFactory.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); manager.leave(); + } } } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 6fb83be..1214cd7 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -9,6 +9,7 @@ package netneutrality.utils; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; @@ -69,7 +70,6 @@ public class MessageFunction { message.setTitle("Currently playing:"); message.setColor(Color.BLUE); message.addField("Track title: ", current.getInfo().title, false); - message.addField("Uploaded by: ", current.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + requester.getEffectiveName(), requester.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); @@ -84,7 +84,6 @@ public class MessageFunction { message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); message.addField("Track title: ", track.getInfo().title, false); - message.addField("Uploaded by: ", track.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); @@ -111,15 +110,17 @@ public class MessageFunction { AudioTrack current = manager.getCurrentlyPlaying(); EmbedBuilder message = new EmbedBuilder(); - message.setTitle("Current queue (showing max 10 items):"); + message.setTitle("Current queue (showing 10 out of " + tracks.size() + " items):"); message.setColor(Color.BLUE); int index = 0; for (AudioTrack track : tracks) { - if (track.getInfo().title.equals(current.getInfo().title) && currentlyPlaying) { - message.addField("Track #" + ++index + " (Currently playing)", track.getInfo().title, false); + AudioTrackInfo info = track.getInfo(); + + if (current != null && current.getInfo().title.equals(info.title) && currentlyPlaying) { + message.addField("Track #" + ++index + " (Currently playing)", info.title, false); } else { - message.addField("Track #" + ++index, track.getInfo().title, false); + message.addField("Track #" + ++index, info.title, false); } if (index == 10) break; diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index fee8dee..947ea00 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -41,7 +41,7 @@ public class MusicUtils { if (UserFunction.isAdmin(context.getGuildUser()) || manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) { return true; } else { - context.reply("You are not powerful enough, scrub"); + context.reply("You're not powerful enough, scrub"); return false; } } diff --git a/src/test/java/netneutrality/music/LoadableSourceTest.java b/src/test/java/netneutrality/music/LoadableSourceTest.java new file mode 100644 index 0000000..925408c --- /dev/null +++ b/src/test/java/netneutrality/music/LoadableSourceTest.java @@ -0,0 +1,31 @@ +package netneutrality.music; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.music.loadable.AppleMostPlayed; +import netneutrality.music.loadable.CachedSource; +import netneutrality.music.loadable.LoadableSong; +import netneutrality.music.loadable.LoadableSourceManager; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +public class LoadableSourceTest { + + @Test + public void getAppleMostPlayed() { + LoadableSourceManager loadableSourceManager = new LoadableSourceManager(); + CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed()); + + System.out.println(cachedSource.getLastAccess()); + System.out.println(cachedSource.getSongs()); + + assertTrue(cachedSource.getSongs().size() > 0); + } +} \ No newline at end of file From 6cceb7da16da9c565a6b180d01590daa116f22b4 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 29 May 2022 20:48:10 -0400 Subject: [PATCH 084/155] make the api listen on 0.0.0.0 --- src/main/java/netneutrality/http/server/WebApi.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index aec38c8..ccb21d3 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -28,8 +28,7 @@ public class WebApi { logger.info("Starting web server..."); try { - InetAddress localHost = InetAddress.getLoopbackAddress(); - InetSocketAddress sockAddr = new InetSocketAddress(localHost, port); + InetSocketAddress sockAddr = new InetSocketAddress(port); server = HttpServer.create(sockAddr, 0); } catch (IOException e) { e.printStackTrace(); From afb4bd9e89967973ed727fdd0490e59780db5051 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 18 Jun 2022 17:25:36 -0400 Subject: [PATCH 085/155] Add new alias for delete queue and improve logic --- bot.properties.example | 5 +- pom.xml | 26 +++-- sql/netneutrality_jpa.sql | 11 +- .../java/netneutrality/NetNeutrality.java | 3 +- .../command/music/DeleteQueueCommand.java | 5 +- .../netneutrality/music/MusicManager.java | 71 ++---------- .../netneutrality/music/QueueManager.java | 22 +++- .../netneutrality/music/TopicManager.java | 10 +- .../music/TrackLoadingHandler.java | 105 ++++++++++++++++++ .../netneutrality/music/TrackScheduler.java | 22 +++- src/main/resources/log4j2.properties | 8 ++ .../music/LoadableSourceTest.java | 3 - 12 files changed, 196 insertions(+), 95 deletions(-) create mode 100644 src/main/java/netneutrality/music/TrackLoadingHandler.java diff --git a/bot.properties.example b/bot.properties.example index 99dab96..0fa8fcf 100644 --- a/bot.properties.example +++ b/bot.properties.example @@ -4,9 +4,10 @@ BOT_PREFIX= BOT_OWNER= BOT_PAPISID= BOT_PSID= +API_PORT=9000 -MYSQL_HOST= -MYSQL_USER= +MYSQL_HOST=127.0.0.1 +MYSQL_USER=root MYSQL_PASSWORD= MYSQL_DATABASE= MYSQL_PORT=3306 diff --git a/pom.xml b/pom.xml index f3f8ee7..8e4b463 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,12 @@ </repositories> <dependencies> + <dependency> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.3.0</version> + </dependency> + <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> @@ -118,7 +124,7 @@ <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> - <version>4.9.3</version> + <version>4.10.0</version> </dependency> <dependency> @@ -134,7 +140,7 @@ <dependency> <groupId>io.sentry</groupId> <artifactId>sentry</artifactId> - <version>5.6.3</version> + <version>6.0.0</version> </dependency> <dependency> <groupId>p6spy</groupId> @@ -146,7 +152,7 @@ <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> - <version>20210307</version> + <version>20220320</version> </dependency> <dependency> @@ -158,17 +164,17 @@ <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>8.0.28</version> + <version>8.0.29</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> - <version>2.17.1</version> + <version>2.17.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> - <version>2.17.1</version> + <version>2.17.2</version> </dependency> <dependency> @@ -176,6 +182,12 @@ <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.15</version> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> @@ -185,7 +197,7 @@ <dependency> <groupId>org.openjdk.nashorn</groupId> <artifactId>nashorn-core</artifactId> - <version>15.3</version> + <version>15.4</version> </dependency> diff --git a/sql/netneutrality_jpa.sql b/sql/netneutrality_jpa.sql index 94ebd9a..61976ad 100644 --- a/sql/netneutrality_jpa.sql +++ b/sql/netneutrality_jpa.sql @@ -1,12 +1,3 @@ --- phpMyAdmin SQL Dump --- version 5.1.0 --- https://www.phpmyadmin.net/ --- --- Host: 127.0.0.1:3306 --- Generation Time: Mar 14, 2022 at 08:59 AM --- Server version: 10.4.10-MariaDB --- PHP Version: 7.4.19 - SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; START TRANSACTION; SET time_zone = "+00:00"; @@ -20,7 +11,9 @@ SET time_zone = "+00:00"; -- -- Database: `netneutrality` -- +CREATE DATABASE IF NOT EXISTS netneutrality CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +USE netneutrality; -- -------------------------------------------------------- -- diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 3b8f600..5d13e51 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -38,6 +38,7 @@ public class NetNeutrality { options.setEnvironment(env); options.setTracesSampleRate(1.0); options.setDebug(env.equals("dev")); + options.setRelease("netneutrality@2.0.0-alpha"); }); if ("dev".equals(env)) { @@ -49,7 +50,7 @@ public class NetNeutrality { CommandManager.init(); MusicManager.initPlayerManager(); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); - new WebApi(9000); + new WebApi(Integer.parseInt(Settings.getInstance().get("API_PORT", "9000"))); jda.getPresence().setActivity(Activity.watching("you")); Runtime.getRuntime().addShutdownHook(new BaseThreadFactory("shutdown").newThread(new ShutdownThread())); diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 000d060..9efd1bd 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -34,7 +34,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public String[] getAlias() { - return new String[] {"delq", "delqueue"}; + return new String[] {"delq", "delqueue", "clear"}; } @Override @@ -67,8 +67,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { if (context.getArg(0).equals("all")) { if (queueSize > 0) { - player.leave(); - player.getScheduler().getQueueManager().getQueue().clear(); + player.getScheduler().getQueueManager().clearQueue(); context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); } else { context.reply("Queue is empty!"); diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 01c4eea..225d276 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -47,13 +47,14 @@ public class MusicManager { private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; + private TrackLoadingHandler lastLoadingHandler; private ScheduledFuture<?> autoDisconnectThread; private final int baseVolume; private MusicManager(Guild guild) { this.guild = guild; this.player = playerManager.createPlayer(); - this.scheduler = new TrackScheduler(player, guild); + this.scheduler = new TrackScheduler(this); this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME)); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); @@ -117,10 +118,18 @@ public class MusicManager { return info.getRequester(); } + protected AudioPlayer getPlayer() { + return player; + } + public Guild getGuild() { return guild; } + public TrackLoadingHandler getLastLoadingHandler() { + return lastLoadingHandler; + } + public synchronized void leave() { if (isConnected()) { logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId()); @@ -183,64 +192,8 @@ public class MusicManager { scheduler.getTopicManager().attachTextChannel(channel); if (identifier != null) { - playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { - - @Override - public void trackLoaded(AudioTrack audioTrack) { - logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); - context.deleteMessage(); - - scheduler.getQueueManager().queue(audioTrack, member); - - if (!silent) { - //context.replyToMessage("Added track to queue"); - context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)); - } - } - - @Override - public void playlistLoaded(AudioPlaylist audioPlaylist) { - logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - context.deleteMessage(); - - if (audioPlaylist.isSearchResult()) { - AudioTrack track = audioPlaylist.getTracks().get(0); - scheduler.getQueueManager().queue(track, member); - - if (!silent) { - //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); - context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))); - } - - } else { - if (!silent) { - //context.replyToMessage("Added playlist to queue"); - context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)); - } - - for (AudioTrack track : audioPlaylist.getTracks()) { - synchronized (scheduler.getQueueManager().getQueue()) { - scheduler.getQueueManager().queue(track, member); - } - } - } - - - } - - @Override - public void noMatches() { - logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); - context.replyToMessage("No matches found"); - } - - @Override - public void loadFailed(FriendlyException e) { - logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); - context.replyToMessage("Failed to load track: " + e.getMessage()); - } - - }); + lastLoadingHandler = new TrackLoadingHandler(identifier, silent, this, context); + playerManager.loadItemOrdered(this, identifier, lastLoadingHandler); } else { context.replyToMessage("No source found to play the given url"); } diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 6e67c78..5b18728 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -87,13 +87,16 @@ public class QueueManager { } private final Logger logger = LoggerFactory.getLogger(QueueManager.class); + + private final TrackScheduler scheduler; private final AudioPlayer player; private final Guild guild; private final Deque<TrackInfo> queue; - public QueueManager(AudioPlayer player, Guild guild) { - this.player = player; - this.guild = guild; + public QueueManager(TrackScheduler scheduler) { + this.scheduler = scheduler; + this.player = scheduler.getPlayer(); + this.guild = scheduler.getGuild(); this.queue = new LinkedBlockingDeque<>(); } @@ -104,10 +107,23 @@ public class QueueManager { } } + public TrackScheduler getScheduler() { + return scheduler; + } + public Guild getGuild() { return guild; } + public void clearQueue() { + scheduler.getMusicManager().leave(); + scheduler.getMusicManager().getLastLoadingHandler().stopLoading(); + + synchronized (queue) { + queue.clear(); + } + } + public ArrayList<AudioTrack> getAllQueuedTrack() { synchronized (queue) { ArrayList<AudioTrack> tracks = new ArrayList<>(); diff --git a/src/main/java/netneutrality/music/TopicManager.java b/src/main/java/netneutrality/music/TopicManager.java index 6a7e267..d080d9a 100644 --- a/src/main/java/netneutrality/music/TopicManager.java +++ b/src/main/java/netneutrality/music/TopicManager.java @@ -15,12 +15,18 @@ import java.util.concurrent.TimeUnit; public class TopicManager { + private final TrackScheduler scheduler; private final Guild guild; private TextChannel channel; private String originalTopic; - public TopicManager(Guild guild) { - this.guild = guild; + public TopicManager(TrackScheduler scheduler) { + this.scheduler = scheduler; + this.guild = scheduler.getGuild(); + } + + public TrackScheduler getScheduler() { + return scheduler; } public Guild getGuild() { diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java new file mode 100644 index 0000000..d887a3b --- /dev/null +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -0,0 +1,105 @@ +package netneutrality.music; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import net.dv8tion.jda.api.entities.Guild; +import netneutrality.core.context.CommandContext; +import netneutrality.utils.MessageFunction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TrackLoadingHandler implements AudioLoadResultHandler { + private final Logger logger = LoggerFactory.getLogger(TrackLoadingHandler.class); + + private final String identifier; + private final boolean silent; + private boolean loadingDisabled = false; + private final Guild guild; + private final TrackScheduler scheduler; + private final CommandContext context; + + public TrackLoadingHandler(String identifier, boolean silent, MusicManager manager, CommandContext context) { + this.identifier = identifier; + this.silent = silent; + this.guild = manager.getGuild(); + this.scheduler = manager.getScheduler(); + this.context = context; + } + + public synchronized void stopLoading() { + logger.debug("Guild {}: stopped loading of new tracks", guild.getId()); + loadingDisabled = true; + } + + @Override + public void trackLoaded(AudioTrack audioTrack) { + if (loadingDisabled) { + return; + } + + logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); + context.deleteMessage(); + + scheduler.getQueueManager().queue(audioTrack, context.getGuildUser()); + + if (!silent) { + //context.replyToMessage("Added track to queue"); + context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), identifier)); + } + } + + @Override + public void playlistLoaded(AudioPlaylist audioPlaylist) { + if (loadingDisabled) { + return; + } + + logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); + context.deleteMessage(); + + if (audioPlaylist.isSearchResult()) { + AudioTrack track = audioPlaylist.getTracks().get(0); + scheduler.getQueueManager().queue(track, context.getGuildUser()); + + if (!silent) { + //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); + context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), String.format("https://youtu.be/%s", track.getIdentifier()))); + } + + } else { + if (!silent) { + //context.replyToMessage("Added playlist to queue"); + context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier)); + } + + for (AudioTrack track : audioPlaylist.getTracks()) { + synchronized (scheduler.getQueueManager().getQueue()) { + scheduler.getQueueManager().queue(track, context.getGuildUser()); + } + } + } + + + } + + @Override + public void noMatches() { + logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); + context.replyToMessage("No matches found"); + } + + @Override + public void loadFailed(FriendlyException e) { + logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); + context.replyToMessage("Failed to load track: " + e.getMessage()); + } +} diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 4d499fe..658d5d1 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -17,18 +17,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TrackScheduler extends AudioEventAdapter { - private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class); + private final QueueManager queueManager; private final TopicManager topicManager; + private final MusicManager manager; private final AudioPlayer player; private final Guild guild; - public TrackScheduler(AudioPlayer player, Guild guild) { - this.player = player; - this.guild = guild; - this.queueManager = new QueueManager(player, guild); - this.topicManager = new TopicManager(guild); + public TrackScheduler(MusicManager manager) { + this.manager = manager; + this.player = manager.getPlayer(); + this.guild = manager.getGuild(); + this.queueManager = new QueueManager(this); + this.topicManager = new TopicManager(this); } public QueueManager getQueueManager() { @@ -39,10 +41,18 @@ public class TrackScheduler extends AudioEventAdapter { return topicManager; } + public MusicManager getMusicManager() { + return manager; + } + public AudioPlayer getPlayer() { return player; } + public Guild getGuild() { + return guild; + } + @Override public void onPlayerPause(AudioPlayer player) { // Player was paused diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties index 39aaad3..42be505 100644 --- a/src/main/resources/log4j2.properties +++ b/src/main/resources/log4j2.properties @@ -30,6 +30,14 @@ logger.jda.additivity = false logger.jda.appenderRef.rolling.ref = LogToRollingFile logger.jda.appenderRef.console.ref = consoleLogger +logger.lavaplayer.name = com.sedmelluq.discord +logger.lavaplayer.level = info +logger.lavaplayer.additivity = false +logger.lavaplayer.appenderRef.rolling.ref = LogToRollingFile +logger.lavaplayer.appenderRef.console.ref = consoleLogger + + + logger.app.name = netneutrality logger.app.level = debug logger.app.additivity = false diff --git a/src/test/java/netneutrality/music/LoadableSourceTest.java b/src/test/java/netneutrality/music/LoadableSourceTest.java index 925408c..5a63ef4 100644 --- a/src/test/java/netneutrality/music/LoadableSourceTest.java +++ b/src/test/java/netneutrality/music/LoadableSourceTest.java @@ -23,9 +23,6 @@ public class LoadableSourceTest { LoadableSourceManager loadableSourceManager = new LoadableSourceManager(); CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed()); - System.out.println(cachedSource.getLastAccess()); - System.out.println(cachedSource.getSongs()); - assertTrue(cachedSource.getSongs().size() > 0); } } \ No newline at end of file From fae73951c7549e2e2d362ab616873c7f7f75a4c6 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 18 Jun 2022 17:29:55 -0400 Subject: [PATCH 086/155] fix logic :( --- src/main/java/netneutrality/music/TrackLoadingHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index d887a3b..97a84e5 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -82,6 +82,10 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { } for (AudioTrack track : audioPlaylist.getTracks()) { + if (loadingDisabled) { + break; + } + synchronized (scheduler.getQueueManager().getQueue()) { scheduler.getQueueManager().queue(track, context.getGuildUser()); } From 1d26918fb33e6ead7b90b23d0863729408b03a2f Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 18 Jun 2022 17:50:05 -0400 Subject: [PATCH 087/155] fix wording --- src/main/java/netneutrality/utils/MusicUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index 947ea00..b85bbee 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -23,13 +23,13 @@ public class MusicUtils { } if (!manager.isConnected()) { - context.reply("You are not in a voice channel"); + context.reply("The bot isn't connected to a voice channel"); return false; } VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); if (!manager.isConnectedTo(vChannel)) { - context.reply("You are not in a voice channel"); + context.reply("The bot isn't in your voice channel"); return false; } From 6544e982c624b4bc3b93266660eb69b535b2f4d6 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 23 Jun 2022 11:57:26 -0400 Subject: [PATCH 088/155] Update docker build process --- Dockerfile | 12 +++- docker-compose-webapp.yml | 60 +++++++++++++++++++ docker-compose.yml | 10 ++-- .../http/server/ActionHandler.java | 2 +- startup.sh | 55 +++++++++++++++++ 5 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 docker-compose-webapp.yml create mode 100644 startup.sh diff --git a/Dockerfile b/Dockerfile index c2823fe..86d2c03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,20 @@ FROM openjdk:17-jdk-slim +RUN apt-get -y update +RUN apt-get -y install netcat +RUN apt-get -y install curl + WORKDIR /app +ARG API_PORT=9000 +EXPOSE ${API_PORT} + COPY .mvn/ .mvn COPY mvnw pom.xml ./ COPY src ./src COPY bot.properties.example bot.properties ./ +COPY startup.sh ./ -RUN ./mvnw -q -Dmaven.test.skip=true package +RUN ./mvnw install -CMD ["java", "-jar", "target/netneutrality-jar-with-dependencies.jar"] \ No newline at end of file +CMD ["./startup.sh"] \ No newline at end of file diff --git a/docker-compose-webapp.yml b/docker-compose-webapp.yml new file mode 100644 index 0000000..ffec0e2 --- /dev/null +++ b/docker-compose-webapp.yml @@ -0,0 +1,60 @@ +version: '3.3' + +services: + db: + image: mariadb:10.7 + restart: always + volumes: + - netneutrality-db:/var/lib/mysql + - ./sql:/docker-entrypoint-initdb.d + environment: + MYSQL_USER: 'java' + MYSQL_PASSWORD: 'password' + MYSQL_DATABASE: 'netneutrality' + MYSQL_ROOT_PASSWORD: 'password' + ports: + - "3306" + networks: + - internal + + bot: + image: netneutrality:dev + build: ./ + restart: always + depends_on: + - db + environment: + MYSQL_HOST: 'db' + MYSQL_USER: 'java' + MYSQL_PASSWORD: 'password' + MYSQL_DATABASE: 'netneutrality' + ports: + - "9000:9000" + networks: + - internal + + webapp: + image: bot-webapp:dev + build: ../netneutrality-webapp + restart: always + depends_on: + - db + - bot + environment: + DB_CONNECTION: 'mysql' + DB_HOST: 'db' + DB_PORT: '3306' + DB_DATABASE: 'netneutrality' + DB_USERNAME: 'java' + DB_PASSWORD: 'password' + BOT_URL: 'http://bot:9000' + ports: + - '8080:80' + networks: + - internal + +volumes: + netneutrality-db: + +networks: + internal: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 4a56fe0..2a8d877 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,22 +2,24 @@ version: '3.3' services: db: - image: mysql:5.7 + image: mariadb:10.7 restart: always volumes: - netneutrality-db:/var/lib/mysql - - ./sql/netneutrality_jpa.sql:/docker-entrypoint-initdb.d/dump.sql + - ./sql:/docker-entrypoint-initdb.d environment: - MYSQL_DATABASE: 'netneutrality' MYSQL_USER: 'java' MYSQL_PASSWORD: 'password' + MYSQL_DATABASE: 'netneutrality' MYSQL_ROOT_PASSWORD: 'password' ports: - "3306" networks: - internal - app: + + bot: image: netneutrality:dev + build: ./ restart: always depends_on: - db diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 85bdb30..4cdb784 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -25,8 +25,8 @@ public class ActionHandler extends AbstractHandler { if (path.equals("/actions/shutdown")) { LoggerFactory.getLogger(NetNeutrality.class).info("Request to shutdown received"); - sendStringResponse(exchange, "Shutting down.."); NetNeutrality.shutdown(); + sendStringResponse(exchange, "Shutting down.."); System.exit(0); return; diff --git a/startup.sh b/startup.sh new file mode 100644 index 0000000..ae06536 --- /dev/null +++ b/startup.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +function prop { + grep "${1}" bot.properties | cut -d'=' -f2 +} + +function _term() { + echo "Caught SIGTERM/SIGINT signal, graceful shutdown of bot.." + if [ -z "$pid" ]; then + echo "Bot isn't running, exiting." + exit 0 + else + /usr/bin/curl --no-progress-meter http://localhost:"$API_PORT"/actions/shutdown + echo "Waiting 2 seconds for bot shutdown" + sleep 2 + fi +} + +trap _term SIGTERM +trap _term SIGINT + +if [ ! -f /bin/nc ]; then + echo "nc not found. Exiting." + exit 1 +fi + +if [ -z "$API_PORT" ]; then + API_PORT=9000; +fi + +if [ -z "$MYSQL_HOST" ]; then + MYSQL_HOST="$(prop 'MYSQL_HOST')" +fi + +if [ -z "$MYSQL_PORT" ]; then + MYSQL_PORT=$(prop 'MYSQL_PORT') +fi + +echo "Waiting 10 seconds for database to start.." +sleep 10 + +echo "Checking if MySQL / MariaDB is started.." +if /bin/nc -z "$MYSQL_HOST" "$MYSQL_PORT"; then + echo "Database OK. Starting bot.."; + /usr/local/openjdk-17/bin/java -jar target/netneutrality-jar-with-dependencies.jar & + + pid=$! + wait "$pid" +else + echo "No connection to database, shutting down.." + exit 1 +fi + + + From 5f1cbad0ee9f4913a3b9ff07e40c166c1b5715e2 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 23 Jun 2022 12:01:54 -0400 Subject: [PATCH 089/155] Update tests --- .../java/netneutrality/utils/Settings.java | 21 +++++++++--- .../music/LoadableSourceTest.java | 18 +++++++--- .../netneutrality/utils/SettingsTest.java | 33 +++++++++++++++++++ 3 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 src/test/java/netneutrality/utils/SettingsTest.java diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 17205be..f0c515e 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -1,5 +1,7 @@ package netneutrality.utils; +import org.apache.commons.io.FileUtils; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -12,17 +14,28 @@ public class Settings { private final Properties prop = new Properties(); public Settings() { - File file = new File("bot.properties"); + File propFile = new File("bot.properties"); + File exampleFile = new File("bot.properties.example"); FileInputStream fis = null; try { - file.createNewFile(); - fis = new FileInputStream(file); + if (!propFile.exists() && !exampleFile.exists()) { + System.err.println("Missing example config file in root directory."); + System.exit(1); + } + + if (!propFile.exists()) { + FileUtils.copyFile(exampleFile, propFile); + System.err.println("Config file was created, please edit bot.properties before launching bot"); + } + + fis = new FileInputStream(propFile); prop.load(fis); loadEnvironmentVariables(); } catch (IOException e) { - e.printStackTrace(); + System.err.println("Can't find config file: bot.properties"); + System.exit(1); } finally { try { if (fis != null) diff --git a/src/test/java/netneutrality/music/LoadableSourceTest.java b/src/test/java/netneutrality/music/LoadableSourceTest.java index 5a63ef4..826a477 100644 --- a/src/test/java/netneutrality/music/LoadableSourceTest.java +++ b/src/test/java/netneutrality/music/LoadableSourceTest.java @@ -10,6 +10,7 @@ import netneutrality.music.loadable.AppleMostPlayed; import netneutrality.music.loadable.CachedSource; import netneutrality.music.loadable.LoadableSong; import netneutrality.music.loadable.LoadableSourceManager; +import org.junit.Before; import org.junit.Test; import java.util.List; @@ -18,11 +19,18 @@ import static org.junit.Assert.*; public class LoadableSourceTest { - @Test - public void getAppleMostPlayed() { - LoadableSourceManager loadableSourceManager = new LoadableSourceManager(); - CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed()); + LoadableSourceManager loadableSourceManager; - assertTrue(cachedSource.getSongs().size() > 0); + @Before + public void setUp() throws Exception { + loadableSourceManager = new LoadableSourceManager(); + } + + @Test + public void cachedSourceAccess() { + CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed()); + CachedSource sameCachedSource = loadableSourceManager.get(new AppleMostPlayed()); + + assertTrue(cachedSource.getLastAccess().isEqual(sameCachedSource.getLastAccess())); } } \ No newline at end of file diff --git a/src/test/java/netneutrality/utils/SettingsTest.java b/src/test/java/netneutrality/utils/SettingsTest.java new file mode 100644 index 0000000..3c7f452 --- /dev/null +++ b/src/test/java/netneutrality/utils/SettingsTest.java @@ -0,0 +1,33 @@ +package netneutrality.utils; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SettingsTest { + + private Settings instance; + + @Before + public void setUp() { + instance = Settings.getInstance(); + } + + @Test + public void get() { + assertNotNull(instance.get("BOT_TOKEN")); + } + + @Test + public void getCreator() { + String creator = instance.getCreatorId(); + assertNotNull(creator); + } +} From 6f5451f37df560579f25e402020ae7ec954acc7f Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Fri, 24 Jun 2022 15:20:39 -0400 Subject: [PATCH 090/155] renamed a couple of things --- docker-compose.yml | 3 ++- .../netneutrality/command/basic/HelpCommand.java | 6 +++--- .../netneutrality/command/basic/PingCommand.java | 2 +- .../command/bot/ConfigureCommand.java | 16 ++++++++-------- .../command/crypto/BitcoinPriceCommand.java | 2 +- .../command/crypto/CryptoPriceCommand.java | 2 +- .../command/crypto/EthereumPriceCommand.java | 2 +- .../command/crypto/LitecoinPriceCommand.java | 2 +- .../command/message/BlacklistCommand.java | 2 +- .../command/message/PruneCommand.java | 4 ++-- .../command/music/DeleteQueueCommand.java | 8 ++++---- .../netneutrality/command/music/SkipCommand.java | 2 +- .../command/music/VolumeCommand.java | 2 +- .../command/specific/DatabaseCommand.java | 2 +- .../core/context/CommandContext.java | 8 ++------ src/main/java/netneutrality/utils/JpaUtils.java | 2 +- 16 files changed, 31 insertions(+), 34 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2a8d877..15a9e7b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ version: '3.3' services: db: image: mariadb:10.7 + container_name: db restart: always volumes: - netneutrality-db:/var/lib/mysql @@ -18,7 +19,7 @@ services: - internal bot: - image: netneutrality:dev + container_name: bot build: ./ restart: always depends_on: diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index c8eef3e..94e9e2f 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -59,15 +59,15 @@ public class HelpCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - if (context.getArgumentsAsArray().length == 0) { + if (context.getArgs().length == 0) { List<MessageEmbed> help = MessageFunction.buildHelpMessage(CommandManager.commands, UserFunction.isAdmin(context.getGuildUser())); context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); context.replyPrivate(help); } - if (context.getArgumentsAsArray().length == 1) { - String cmd = context.getArg(0); + if (context.getArgs().length == 1) { + String cmd = context.getArgument(0); if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 432c9bf..6551022 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -50,7 +50,7 @@ public class PingCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - if (context.getArgumentsAsArray().length == 0) + if (context.getArgs().length == 0) context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index b564262..9a1b550 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -57,13 +57,13 @@ public class ConfigureCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); GuildManager guildManager = GuildManager.getManager(context.getGuild()); if (args.length > 0) { // Role for music commands - if (context.getArg(0).equals("music-role")) { + if (context.getArgument(0).equals("music-role")) { if (args.length == 1) { String roleDb = guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE); Role role = null; @@ -76,7 +76,7 @@ public class ConfigureCommand extends AbstractCommand { } if (args.length == 2) { - if (context.getArg(1).equals("reset")) { + if (context.getArgument(1).equals("reset")) { if (!guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE).isEmpty()) { guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); } @@ -96,7 +96,7 @@ public class ConfigureCommand extends AbstractCommand { } // Role for music commands - if (context.getArg(0).equals("music-channel")) { + if (context.getArgument(0).equals("music-channel")) { if (args.length == 1) { String channelDb = guildManager.getSetting(GuildManager.Settings.MUSIC_CHANNEL); TextChannel channel = null; @@ -109,7 +109,7 @@ public class ConfigureCommand extends AbstractCommand { } if (args.length == 2) { - if (context.getArg(1).equals("reset")) { + if (context.getArgument(1).equals("reset")) { if (!guildManager.getSetting(GuildManager.Settings.MUSIC_CHANNEL).isEmpty()) { guildManager.setSettingValue(GuildManager.Settings.MUSIC_CHANNEL, null); } @@ -129,7 +129,7 @@ public class ConfigureCommand extends AbstractCommand { } // Default volume for music player - if (context.getArg(0).equals("music-volume")) { + if (context.getArgument(0).equals("music-volume")) { if (args.length == 1) { int volume = Integer.parseInt(guildManager.getSetting(GuildManager.Settings.MUSIC_VOLUME)); @@ -156,7 +156,7 @@ public class ConfigureCommand extends AbstractCommand { } // Music topic change - if (context.getArg(0).equals("music-topic")) { + if (context.getArgument(0).equals("music-topic")) { if (args.length == 1) { boolean enabled = "1".equals(guildManager.getSetting(GuildManager.Settings.MUSIC_TOPIC)); @@ -178,7 +178,7 @@ public class ConfigureCommand extends AbstractCommand { } // Debug - if (context.getArg(0).equals("debug")) { + if (context.getArgument(0).equals("debug")) { if (args.length == 1) { boolean debug = guildManager.isDebugEnabled(); diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 8e31c2d..f9a907e 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -63,7 +63,7 @@ public class BitcoinPriceCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); String currency = "USD"; if (args.length == 1) { diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 1a220bb..1706b26 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -63,7 +63,7 @@ public class CryptoPriceCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); String currency = "USD"; if (args.length > 0) { diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 414f445..214813f 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -63,7 +63,7 @@ public class EthereumPriceCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); String currency = "USD"; if (args.length == 1) { diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 4a1efb7..662d120 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -63,7 +63,7 @@ public class LitecoinPriceCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); String currency = "USD"; if (args.length == 1) { diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index 920b88d..d442c2e 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -56,7 +56,7 @@ public class BlacklistCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); DBBlacklist controller = DBController.get(DBBlacklist.class); if (args.length > 0 && args.length < 3) { diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java index e9179de..6cc7848 100644 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ b/src/main/java/netneutrality/command/message/PruneCommand.java @@ -53,8 +53,8 @@ public class PruneCommand extends AbstractCommand { @Override public void execute(CommandContext context) { - if (context.getArgumentsAsArray().length == 1) - ChannelFunction.bulkDeleteMessage(context.getChannel(), Integer.parseInt(context.getArgumentsAsArray()[0])); + if (context.getArgs().length == 1) + ChannelFunction.bulkDeleteMessage(context.getChannel(), Integer.parseInt(context.getArgument(0))); else context.getChannel().sendMessage("Failed to delete messages!").queue(); } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 9efd1bd..a44a62a 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -56,15 +56,15 @@ public class DeleteQueueCommand extends AbstractMusicCommand { if (!MusicUtils.checkIfConnected(player, context)) return; - if (context.getArgumentsAsArray().length == 0) { + if (context.getArgs().length == 0) { context.reply("Select the track you want to delete from the queue (track# or all)"); context.reply(MessageFunction.buildViewQueueMessage(player, context.getGuildUser(), true)); } - if (context.getArgumentsAsArray().length > 0) { + if (context.getArgs().length > 0) { int queueSize = player.getQueueSize(); - if (context.getArg(0).equals("all")) { + if (context.getArgument(0).equals("all")) { if (queueSize > 0) { player.getScheduler().getQueueManager().clearQueue(); @@ -75,7 +75,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { } else { try { - int num = Integer.parseInt(context.getArg(0)); + int num = Integer.parseInt(context.getArgument(0)); if (num > 0) { if (player.removeFromQueue(num)) { diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index eb784f3..09eab88 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -50,7 +50,7 @@ public class SkipCommand extends AbstractMusicCommand { if (UserFunction.isAdmin(context.getGuildUser())) { if (context.getArgs().length > 0) { try { - int skips = Integer.parseInt(context.getArg(0)); + int skips = Integer.parseInt(context.getArgument(0)); player.skip(skips); context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : "")); diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 95ac941..cafd404 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -46,7 +46,7 @@ public class VolumeCommand extends AbstractMusicCommand { if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { try { - int volume = Integer.parseInt(context.getArg(0)); + int volume = Integer.parseInt(context.getArgument(0)); if (volume > 0 && volume <= 100) { player.setVolume(volume); diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java index edd2928..965daa7 100644 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ b/src/main/java/netneutrality/command/specific/DatabaseCommand.java @@ -61,7 +61,7 @@ public class DatabaseCommand extends AbstractCommand { @Override public void execute(CommandContext context) { //TODO: Clean up the mess - String[] args = context.getArgumentsAsArray(); + String[] args = context.getArgs(); context.getMessage().delete().queue(); if (!context.getGuildUser().getId().equals(Settings.getInstance().getCreatorId())) diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 22a08d4..4173d53 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -64,15 +64,11 @@ public class CommandContext { return new CommandContext(message, member, user, guild, channel, jda); } - public String getArg(int index) { - return getArgumentsAsArray()[index]; + public String getArgument(int index) { + return getArgs()[index]; } public String[] getArgs() { - return getArgumentsAsArray(); - } - - public String[] getArgumentsAsArray() { String msg = message.getContentDisplay().trim(); msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); String cmd = msg.split(" ", 2)[0]; diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/netneutrality/utils/JpaUtils.java index 6ad9d58..29d004b 100644 --- a/src/main/java/netneutrality/utils/JpaUtils.java +++ b/src/main/java/netneutrality/utils/JpaUtils.java @@ -41,7 +41,7 @@ public class JpaUtils { if (object instanceof OGuild oGuild) { String cachedId = oGuild.getGuildId(); - Sentry.captureMessage("Trying to load Guild[" + cachedId + "] while deleted from database, reloading entity..", SentryLevel.ERROR); + Sentry.captureMessage("Trying to load Guild[" + cachedId + "] while entity doesn't exist in database, reloading..", SentryLevel.ERROR); GuildManager guildManager = GuildManager.getManager(cachedId); guildManager.reloadEntity(); From 054bff8c638f6d87983df034648976fce22a974c Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 7 Jul 2022 05:02:49 -0400 Subject: [PATCH 091/155] per-guild prefix --- .../command/AbstractMusicCommand.java | 6 +-- .../command/bot/ConfigureCommand.java | 53 ++++++++++++++----- .../netneutrality/core/CommandManager.java | 8 +++ .../java/netneutrality/core/GuildManager.java | 10 ++-- .../hooks/message/MessageReceivedHandler.java | 24 +++++---- .../netneutrality/music/MusicManager.java | 2 +- .../netneutrality/utils/MessageFunction.java | 10 +--- 7 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 13bfb6a..2c1a991 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -27,7 +27,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_ROLE); if (roleDb != null && !roleDb.isEmpty()) { if (UserFunction.isAdmin(member)) { @@ -37,7 +37,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { Role neededRole = guild.getRoleById(roleDb); if (neededRole == null) { // Role doesn't exist on guild anymore, remove from db - GuildManager.getManager(guild).setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); + GuildManager.getManager(guild).setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null); return true; } @@ -49,7 +49,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { - String channelDb = GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_CHANNEL); + String channelDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_CHANNEL); if (channelDb != null && !channelDb.isEmpty()) { return channelDb.equals(channel.getId()); diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 9a1b550..85dcd45 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -15,6 +15,7 @@ import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; +import java.util.Arrays; import java.util.List; public class ConfigureCommand extends AbstractCommand { @@ -65,7 +66,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-role")) { if (args.length == 1) { - String roleDb = guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE); + String roleDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -77,8 +78,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GuildManager.Settings.MUSIC_ROLE).isEmpty()) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, null); + if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE).isEmpty()) { + guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null); } context.reply("Successful reset of the role"); @@ -88,7 +89,7 @@ public class ConfigureCommand extends AbstractCommand { if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_ROLE, role.getId()); + guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, role.getId()); context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } @@ -98,7 +99,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-channel")) { if (args.length == 1) { - String channelDb = guildManager.getSetting(GuildManager.Settings.MUSIC_CHANNEL); + String channelDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL); TextChannel channel = null; if (!channelDb.isEmpty()) { channel = context.getGuild().getTextChannelById(channelDb); @@ -110,8 +111,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GuildManager.Settings.MUSIC_CHANNEL).isEmpty()) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_CHANNEL, null); + if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL).isEmpty()) { + guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, null); } context.reply("Successful reset of the channel"); @@ -121,7 +122,7 @@ public class ConfigureCommand extends AbstractCommand { if (channels.size() == 1) { TextChannel channel = channels.get(0); if (channel.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_CHANNEL, channel.getId()); + guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, channel.getId()); context.reply("Successfully set %s as the channel required to execute music command", channel.getAsMention()); } } @@ -131,7 +132,7 @@ public class ConfigureCommand extends AbstractCommand { // Default volume for music player if (context.getArgument(0).equals("music-volume")) { if (args.length == 1) { - int volume = Integer.parseInt(guildManager.getSetting(GuildManager.Settings.MUSIC_VOLUME)); + int volume = Integer.parseInt(guildManager.getSetting(GuildManager.GSettings.MUSIC_VOLUME)); context.reply("Default volume for music player: %d", volume); context.reply("Set using 'conf music-volume <value between 0 and 100>'"); @@ -142,7 +143,7 @@ public class ConfigureCommand extends AbstractCommand { int volume = Integer.parseInt(args[1]); if (volume > 0 && volume <= 100) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_VOLUME, String.valueOf(volume)); + guildManager.setSettingValue(GuildManager.GSettings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); context.reply("Default volume for music player is now %d", volume); @@ -158,7 +159,7 @@ public class ConfigureCommand extends AbstractCommand { // Music topic change if (context.getArgument(0).equals("music-topic")) { if (args.length == 1) { - boolean enabled = "1".equals(guildManager.getSetting(GuildManager.Settings.MUSIC_TOPIC)); + boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC)); context.reply("Set currently playing track in text channel topic: %s", (enabled ? "enabled" : "disabled")); context.reply("Use 'conf music-topic 0/1' to toggle between states (0 = disabled, 1 = enabled)."); @@ -166,9 +167,9 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { String str = args[1]; - boolean enabled = "1".equals(guildManager.getSetting(GuildManager.Settings.MUSIC_TOPIC)); + boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC)); if (str.equals("0") || str.equals("1")) { - guildManager.setSettingValue(GuildManager.Settings.MUSIC_TOPIC, str); + guildManager.setSettingValue(GuildManager.GSettings.MUSIC_TOPIC, str); enabled = "1".equals(str); } @@ -202,6 +203,32 @@ public class ConfigureCommand extends AbstractCommand { } } + + // Prefix + if (context.getArgument(0).equals("prefix")) { + String allowedPrefixes = "!$%?&*"; + + if (args.length == 1) { + String prefix = guildManager.getSetting(GuildManager.GSettings.PREFIX); + + context.reply("Current prefix for commands: '%s'", prefix); + context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray())); + + } + + if (args.length == 2) { + String prefix = args[1].trim(); + + if (prefix.length() == 1 && allowedPrefixes.contains(prefix)) { + guildManager.setSettingValue(GuildManager.GSettings.PREFIX, prefix); + + context.reply("Prefix for commands is now '%s'", prefix); + } else { + context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray())); + } + + } + } } else { context.reply(getUsage()); } diff --git a/src/main/java/netneutrality/core/CommandManager.java b/src/main/java/netneutrality/core/CommandManager.java index 049becc..c6ee03b 100644 --- a/src/main/java/netneutrality/core/CommandManager.java +++ b/src/main/java/netneutrality/core/CommandManager.java @@ -28,6 +28,14 @@ public class CommandManager { initAlias(); } + public static boolean isValidCommand(String commandString) { + return commands.containsKey(commandString) || commandsAlias.containsKey(commandString); + } + + public static AbstractCommand getCommand(String commandString) { + return commands.containsKey(commandString) ? commands.get(commandString) : commandsAlias.get(commandString); + } + private static void initCommands() { logger.info("Loading commands.."); diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index e0a5558..877debf 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -21,6 +21,7 @@ import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; +import netneutrality.utils.Settings; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.slf4j.Logger; @@ -34,7 +35,8 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { - public enum Settings { + public enum GSettings { + PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")), MUSIC_ROLE("MUSIC_ROLE", ""), MUSIC_CHANNEL("MUSIC_CHANNEL", ""), MUSIC_VOLUME("MUSIC_VOLUME", "30"), @@ -44,7 +46,7 @@ public class GuildManager { private final String name; private final String defaultValue; - Settings(String name, String defaultValue) { + GSettings(String name, String defaultValue) { this.name = name; this.defaultValue = defaultValue; } @@ -140,7 +142,7 @@ public class GuildManager { return settingsCache; } - public String getSetting(Settings setting) { + public String getSetting(GSettings setting) { String value = settingsCache.get(setting.getName()); if (value == null) { @@ -150,7 +152,7 @@ public class GuildManager { return value; } - public void setSettingValue(Settings setting, String value) { + public void setSettingValue(GSettings setting, String value) { Session session = sessionFactory.openSession(); JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index 52ab9ce..4816ff6 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -22,15 +22,14 @@ public class MessageReceivedHandler extends ListenerAdapter { @Override public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + if (event.getAuthor().isBot()) return; + if (event.isWebhookMessage()) return; + Message message = event.getMessage(); Member member = event.getMember(); - User user = event.getAuthor(); Guild guild = event.getGuild(); TextChannel channel = event.getChannel(); - if (user.isBot()) return; - if (event.isWebhookMessage()) return; - Sentry.addBreadcrumb(Breadcrumb.info("New message from " + member.getEffectiveName())); CommandContext context = CommandContext.createContext(event); @@ -38,17 +37,20 @@ public class MessageReceivedHandler extends ListenerAdapter { GuildManager.getManager(guild).getRateLimiter().check(member, message, channel); GuildManager.getManager(guild).checkAndLogMessage(message, member, channel); - String msg = message.getContentDisplay().trim(); + String rawMessage = message.getContentDisplay().trim(); + //String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); + String prefix = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.PREFIX); - if (msg.startsWith(Settings.getInstance().get("BOT_PREFIX", "$"))) { - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); - String cmd = msg.split(" ", 2)[0]; + if (rawMessage.startsWith(prefix)) { + rawMessage = rawMessage.replaceFirst(String.format("^[%s\\s]{1,}", prefix), "").trim(); + // rawMessage = rawMessage.substring(prefix.length()).trim(); + String commandString = rawMessage.split(" ", 2)[0]; - if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { - AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); + if (CommandManager.isValidCommand(commandString)) { + AbstractCommand command = CommandManager.getCommand(commandString); - context.dispatch(c); + context.dispatch(command); } } else { diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 225d276..b145c38 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -55,7 +55,7 @@ public class MusicManager { this.guild = guild; this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(this); - this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME)); + this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_VOLUME)); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 1214cd7..4c214b0 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -30,20 +30,12 @@ public class MessageFunction { private final static Logger logger = LoggerFactory.getLogger(MessageFunction.class); - public static void logMessageIfNeeded(Guild guild, TextChannel channel, User author, Message message) { - - - } - - public static Member getStartingMention(Message message) { if (isStartingWithMention(message)) { return message.getMentionedMembers().get(0); } return null; - - } public static boolean isStartingWithMention(Message message) { @@ -188,7 +180,7 @@ public class MessageFunction { message.setColor(Color.BLUE); } - message.addField(String.format("%s%s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommandName(), availAlias), description, false); + message.addField(String.format("%s %s", command.getCommandName(), availAlias), description, false); } } From 54ab7269bb476880dcd3ac303446b93f2f1785a0 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 7 Jul 2022 05:29:10 -0400 Subject: [PATCH 092/155] fix youtube searching --- bot.properties.example | 4 ++-- pom.xml | 2 +- src/main/java/netneutrality/music/MusicManager.java | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/bot.properties.example b/bot.properties.example index 0fa8fcf..66a5f53 100644 --- a/bot.properties.example +++ b/bot.properties.example @@ -2,8 +2,8 @@ BOT_ENV=dev BOT_TOKEN= BOT_PREFIX= BOT_OWNER= -BOT_PAPISID= -BOT_PSID= +GG_EMAIL= +GG_PASS= API_PORT=9000 MYSQL_HOST=127.0.0.1 diff --git a/pom.xml b/pom.xml index 8e4b463..9420926 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,7 @@ <dependency> <groupId>com.github.walkyst</groupId> <artifactId>lavaplayer-fork</artifactId> - <version>1.3.97</version> + <version>1.3.98.1</version> </dependency> <dependency> diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index b145c38..ba63d4e 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -12,7 +12,8 @@ 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.youtube.YoutubeHttpContextFilter; +import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; @@ -26,6 +27,7 @@ import netneutrality.music.loadable.LoadableSong; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; import netneutrality.utils.MessageFunction; +import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,8 +76,11 @@ public class MusicManager { public static void initPlayerManager() { AudioSourceManagers.registerRemoteSources(playerManager); - YoutubeHttpContextFilter.setPAPISID(netneutrality.utils.Settings.getInstance().get("BOT_PAPISID", "")); - YoutubeHttpContextFilter.setPSID(netneutrality.utils.Settings.getInstance().get("BOT_PSID", "")); + playerManager.registerSourceManager(new YoutubeAudioSourceManager( + true, + Settings.getInstance().get("GG_EMAIL", ""), + Settings.getInstance().get("GG_PASS", ""))); + playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); } public boolean isConnectedTo(VoiceChannel vChannel) { From 812d8b0b760c81c97335c9188c4e08005e61dc0a Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 13 Aug 2022 18:48:06 -0400 Subject: [PATCH 093/155] Update lavaplayer-fork to fix n function regex --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9420926..4ba5e5f 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,7 @@ <dependency> <groupId>com.github.walkyst</groupId> <artifactId>lavaplayer-fork</artifactId> - <version>1.3.98.1</version> + <version>1.3.98.3</version> </dependency> <dependency> From 4b26acc63a65b8ef7284d6d432ccc170c4d0e2f6 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 20 Aug 2022 19:23:55 -0400 Subject: [PATCH 094/155] Remove admin requirement of the view queue command --- .../java/netneutrality/command/music/ViewQueueCommand.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index c6afbbc..87acb1e 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -1,5 +1,4 @@ package netneutrality.command.music; - /* * Copyright (c) anthorob * @@ -15,10 +14,6 @@ import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; public class ViewQueueCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { From 02c1eab6e3abbe797d231b507852f15a9d3f164a Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 20 Aug 2022 19:59:11 -0400 Subject: [PATCH 095/155] Adjust permission of music commands --- .../command/music/SkipCommand.java | 14 +++++++++++--- .../command/music/StopCommand.java | 8 +++++++- .../command/music/VolumeCommand.java | 6 +++++- .../java/netneutrality/utils/MusicUtils.java | 17 ++++++++--------- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 09eab88..18a6ae6 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -15,6 +15,7 @@ import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; public class SkipCommand extends AbstractMusicCommand { + @Override public boolean isEnabled() { return true; @@ -32,7 +33,14 @@ public class SkipCommand extends AbstractMusicCommand { @Override public CommandUsage getUsage() { - return CommandUsage.create(this, new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[]{"number"}, "Number of tracks to skip")); + return CommandUsage.create( + this, + new CommandUsage.Argument( + CommandUsage.Argument.Type.OPTIONAL, + new String[]{"number"}, + "Number of tracks to skip" + ) + ); } @Override @@ -47,8 +55,8 @@ public class SkipCommand extends AbstractMusicCommand { if (!MusicUtils.checkIfConnected(player, context)) return; - if (UserFunction.isAdmin(context.getGuildUser())) { - if (context.getArgs().length > 0) { + if (UserFunction.isAdmin(context.getGuildUser()) || MusicUtils.isUserDj(context.getGuildUser())) { + if (UserFunction.isAdmin(context.getGuildUser()) && context.getArgs().length > 0) { try { int skips = Integer.parseInt(context.getArgument(0)); player.skip(skips); diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index fe0c0e6..89adceb 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -12,6 +12,7 @@ import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; +import netneutrality.utils.UserFunction; public class StopCommand extends AbstractMusicCommand { @@ -44,7 +45,12 @@ public class StopCommand extends AbstractMusicCommand { public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { + if (!MusicUtils.checkIfConnected(player, context)) + return; + + // Need a resume command before + // if (UserFunction.isAdmin(context.getGuildUser()) || MusicUtils.isUserDj(context.getGuildUser())) { + if (UserFunction.isAdmin(context.getGuildUser())) { player.stopTrack(); context.reply("Stopping current track"); } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index cafd404..4010c1a 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -12,6 +12,7 @@ import netneutrality.command.CommandUsage; import netneutrality.core.context.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; +import netneutrality.utils.UserFunction; public class VolumeCommand extends AbstractMusicCommand { @@ -44,7 +45,10 @@ public class VolumeCommand extends AbstractMusicCommand { public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); - if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { + if (!MusicUtils.checkIfConnected(player, context)) + return; + + if (UserFunction.isAdmin(context.getGuildUser()) || MusicUtils.isUserDj(context.getGuildUser())) { try { int volume = Integer.parseInt(context.getArgument(0)); diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index b85bbee..a4caf74 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -1,10 +1,12 @@ -package netneutrality.utils;/* +package netneutrality.utils; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandExecutionException; @@ -28,7 +30,7 @@ public class MusicUtils { } VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); - if (!manager.isConnectedTo(vChannel)) { + if (manager.isNotConnectedTo(vChannel)) { context.reply("The bot isn't in your voice channel"); return false; } @@ -36,14 +38,11 @@ public class MusicUtils { return true; } - public static boolean isDj(MusicManager manager, CommandContext context) { + public static boolean isUserDj(Member member) { + MusicManager manager = MusicManager.get(member.getGuild()); + if (manager.isCurrentlyPlaying()) { - if (UserFunction.isAdmin(context.getGuildUser()) || manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) { - return true; - } else { - context.reply("You're not powerful enough, scrub"); - return false; - } + return manager.getRequesterOfCurrentTrack().equals(member); } return false; From 64dd0da604a0950dec1c9c54da328b6402a9fd0a Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Fri, 26 Aug 2022 11:08:28 -0400 Subject: [PATCH 096/155] Refactored music manager --- .../java/netneutrality/NetNeutrality.java | 1 + .../command/AbstractMusicCommand.java | 7 +- .../command/bot/ConfigureCommand.java | 31 +-- .../command/crypto/BitcoinPriceCommand.java | 1 - .../command/crypto/CryptoPriceCommand.java | 1 - .../command/crypto/EthereumPriceCommand.java | 1 - .../command/crypto/LitecoinPriceCommand.java | 1 - .../java/netneutrality/core/BotState.java | 79 +++++++ .../java/netneutrality/core/GuildManager.java | 27 +-- .../java/netneutrality/core/LogHandler.java | 30 ++- .../netneutrality/core/SessionManager.java | 5 +- .../netneutrality/core/UnsafeShutdown.java | 67 ------ .../core/context/CommandContext.java | 4 + src/main/java/netneutrality/db/GSettings.java | 36 +++ .../hooks/message/MessageReceivedHandler.java | 3 +- .../hooks/voice/VoiceEventHandler.java | 8 +- .../ratelimiter/MessageRateLimiterImpl.java | 9 +- .../music/AudioPlayerSendHandler.java | 1 - .../netneutrality/music/MusicManager.java | 214 +++++------------- .../netneutrality/music/QueueManager.java | 2 +- .../netneutrality/music/SourceFinder.java | 15 +- .../netneutrality/music/TopicManager.java | 84 ------- .../java/netneutrality/music/TrackLoader.java | 116 ++++++++++ .../music/TrackLoadingHandler.java | 67 ++++-- .../netneutrality/music/TrackScheduler.java | 44 ++-- .../music/loadable/CachedSource.java | 2 +- .../music/loadable/LoadableSourceManager.java | 11 +- .../netneutrality/utils/MessageFunction.java | 53 +++-- .../java/netneutrality/utils/MiscUtils.java | 26 +++ 29 files changed, 503 insertions(+), 443 deletions(-) create mode 100644 src/main/java/netneutrality/core/BotState.java delete mode 100644 src/main/java/netneutrality/core/UnsafeShutdown.java create mode 100644 src/main/java/netneutrality/db/GSettings.java delete mode 100644 src/main/java/netneutrality/music/TopicManager.java create mode 100644 src/main/java/netneutrality/music/TrackLoader.java create mode 100644 src/main/java/netneutrality/utils/MiscUtils.java diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 5d13e51..80e804d 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -58,6 +58,7 @@ public class NetNeutrality { } public static void initJDA() { + // When upgrading JDA -> GatewayIntent.MESSAGE_CONTENT try { jda = JDABuilder .createDefault(Settings.getInstance().get("BOT_TOKEN")) diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 2c1a991..44bbf20 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.GuildManager; +import netneutrality.db.GSettings; import netneutrality.utils.UserFunction; public abstract class AbstractMusicCommand extends AbstractCommand { @@ -27,7 +28,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_ROLE); if (roleDb != null && !roleDb.isEmpty()) { if (UserFunction.isAdmin(member)) { @@ -37,7 +38,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { Role neededRole = guild.getRoleById(roleDb); if (neededRole == null) { // Role doesn't exist on guild anymore, remove from db - GuildManager.getManager(guild).setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null); + GuildManager.getManager(guild).setSettingValue(GSettings.MUSIC_ROLE, null); return true; } @@ -49,7 +50,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { - String channelDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_CHANNEL); + String channelDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_CHANNEL); if (channelDb != null && !channelDb.isEmpty()) { return channelDb.equals(channel.getId()); diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 85dcd45..a038154 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -13,6 +13,7 @@ import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; +import netneutrality.db.GSettings; import netneutrality.music.MusicManager; import java.util.Arrays; @@ -66,7 +67,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-role")) { if (args.length == 1) { - String roleDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE); + String roleDb = guildManager.getSetting(GSettings.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -78,8 +79,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE).isEmpty()) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null); + if (!guildManager.getSetting(GSettings.MUSIC_ROLE).isEmpty()) { + guildManager.setSettingValue(GSettings.MUSIC_ROLE, null); } context.reply("Successful reset of the role"); @@ -89,7 +90,7 @@ public class ConfigureCommand extends AbstractCommand { if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, role.getId()); + guildManager.setSettingValue(GSettings.MUSIC_ROLE, role.getId()); context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } @@ -99,7 +100,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-channel")) { if (args.length == 1) { - String channelDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL); + String channelDb = guildManager.getSetting(GSettings.MUSIC_CHANNEL); TextChannel channel = null; if (!channelDb.isEmpty()) { channel = context.getGuild().getTextChannelById(channelDb); @@ -111,8 +112,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL).isEmpty()) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, null); + if (!guildManager.getSetting(GSettings.MUSIC_CHANNEL).isEmpty()) { + guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, null); } context.reply("Successful reset of the channel"); @@ -122,7 +123,7 @@ public class ConfigureCommand extends AbstractCommand { if (channels.size() == 1) { TextChannel channel = channels.get(0); if (channel.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, channel.getId()); + guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); context.reply("Successfully set %s as the channel required to execute music command", channel.getAsMention()); } } @@ -132,7 +133,7 @@ public class ConfigureCommand extends AbstractCommand { // Default volume for music player if (context.getArgument(0).equals("music-volume")) { if (args.length == 1) { - int volume = Integer.parseInt(guildManager.getSetting(GuildManager.GSettings.MUSIC_VOLUME)); + int volume = Integer.parseInt(guildManager.getSetting(GSettings.MUSIC_VOLUME)); context.reply("Default volume for music player: %d", volume); context.reply("Set using 'conf music-volume <value between 0 and 100>'"); @@ -143,7 +144,7 @@ public class ConfigureCommand extends AbstractCommand { int volume = Integer.parseInt(args[1]); if (volume > 0 && volume <= 100) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_VOLUME, String.valueOf(volume)); + guildManager.setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); context.reply("Default volume for music player is now %d", volume); @@ -159,7 +160,7 @@ public class ConfigureCommand extends AbstractCommand { // Music topic change if (context.getArgument(0).equals("music-topic")) { if (args.length == 1) { - boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC)); + boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC)); context.reply("Set currently playing track in text channel topic: %s", (enabled ? "enabled" : "disabled")); context.reply("Use 'conf music-topic 0/1' to toggle between states (0 = disabled, 1 = enabled)."); @@ -167,9 +168,9 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { String str = args[1]; - boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC)); + boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC)); if (str.equals("0") || str.equals("1")) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_TOPIC, str); + guildManager.setSettingValue(GSettings.MUSIC_TOPIC, str); enabled = "1".equals(str); } @@ -209,7 +210,7 @@ public class ConfigureCommand extends AbstractCommand { String allowedPrefixes = "!$%?&*"; if (args.length == 1) { - String prefix = guildManager.getSetting(GuildManager.GSettings.PREFIX); + String prefix = guildManager.getSetting(GSettings.PREFIX); context.reply("Current prefix for commands: '%s'", prefix); context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray())); @@ -220,7 +221,7 @@ public class ConfigureCommand extends AbstractCommand { String prefix = args[1].trim(); if (prefix.length() == 1 && allowedPrefixes.contains(prefix)) { - guildManager.setSettingValue(GuildManager.GSettings.PREFIX, prefix); + guildManager.setSettingValue(GSettings.PREFIX, prefix); context.reply("Prefix for commands is now '%s'", prefix); } else { diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index f9a907e..f94fafb 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 1706b26..be13696 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 214813f..6e7c768 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 662d120..bf33780 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/core/BotState.java b/src/main/java/netneutrality/core/BotState.java new file mode 100644 index 0000000..dd06023 --- /dev/null +++ b/src/main/java/netneutrality/core/BotState.java @@ -0,0 +1,79 @@ +package netneutrality.core;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.music.MusicManager; +import netneutrality.music.TrackScheduler; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Map; + +public class BotState { + public static boolean SAFE = false; + + //TODO: is it needed? + private static void saveGuildsState() { + Map<String, GuildManager> managers = GuildManager.getManagers(); + + JSONObject main = new JSONObject(); + JSONArray guildsArray = new JSONArray(); + + for (GuildManager manager : managers.values()) { + MusicManager musicManager = MusicManager.get(manager.getGuild()); + TrackScheduler trackScheduler = musicManager.getScheduler(); + + JSONObject guild = new JSONObject(); + JSONObject music = new JSONObject(); + guild.put("id", manager.getGuild().getId()); + + TextChannel currentChannel = trackScheduler.getTextChannel(); + if (currentChannel == null) { + music.put("current_channel", "null"); + } else { + music.put("current_channel", currentChannel.getId()); + } + + guild.put("music", music); + + guildsArray.put(guild); + } + + main.put("guilds", guildsArray); + + File state = new File("state.json"); + try { + if (!state.exists()) { + state.createNewFile(); + } + + try (FileWriter writer = new FileWriter(state)) { + writer.write(main.toString()); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void dump() { + if (!SAFE) { + saveGuildsState(); + } + } +} diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 877debf..63e951d 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -12,6 +12,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.NetNeutrality; import netneutrality.db.DBController; +import netneutrality.db.GSettings; import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OBlacklist; import netneutrality.db.entities.OGuild; @@ -21,7 +22,6 @@ import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; -import netneutrality.utils.Settings; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.slf4j.Logger; @@ -35,31 +35,6 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { - public enum GSettings { - PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")), - MUSIC_ROLE("MUSIC_ROLE", ""), - MUSIC_CHANNEL("MUSIC_CHANNEL", ""), - MUSIC_VOLUME("MUSIC_VOLUME", "30"), - MUSIC_TOPIC("MUSIC_TOPIC", "0"), - BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); - - private final String name; - private final String defaultValue; - - GSettings(String name, String defaultValue) { - this.name = name; - this.defaultValue = defaultValue; - } - - public String getName() { - return name; - } - - public String getDefaultValue() { - return defaultValue; - } - } - private static final Logger logger = LoggerFactory.getLogger(GuildManager.class); private static final Map<String, GuildManager> managers = new ConcurrentHashMap<>(); private static final SessionFactory sessionFactory = SessionManager.getSessionFactory(); diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 1319974..2165707 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -7,9 +7,11 @@ package netneutrality.core; */ import io.sentry.Sentry; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.utils.MessageFunction; import org.slf4j.Logger; @@ -27,15 +29,19 @@ public class LogHandler { public static void log(Exception e) { if (e instanceof CommandErrorException) { sendMessageToChannel((CommandErrorException) e); - } else if (e instanceof CommandExecutionException) { + logInternally((CommandErrorException) e); + return; + } + + if (e instanceof CommandExecutionException) { Sentry.captureException(e); logInternally((CommandExecutionException) e); tryLogToDebugChannel((CommandExecutionException) e); - } else { - Sentry.captureException(e); - logger.error(e.getMessage(), e); + return; } + Sentry.captureException(e); + logger.error(e.getMessage(), e); } public static void log(String s, Exception e) { @@ -47,12 +53,22 @@ public class LogHandler { log((Exception) e); } - private static void logInternally(CommandExecutionException error) { + public static void sendMessageToDebugChannel(Guild guild, String message) { + if (GuildManager.getManager(guild).isDebugEnabled()) { + guild.getTextChannels() + .stream() + .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .filter(TextChannel::canTalk) + .forEach(textChannel -> textChannel.sendMessage(message).queue()); + } + } + + private static void logInternally(CommandException error) { CommandContext context = error.getCommandContext(); logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage(), error); } - private static void tryLogToDebugChannel(CommandExecutionException error) { + private static void tryLogToDebugChannel(CommandException error) { CommandContext context = error.getCommandContext(); if (context.getGuild() != null) { @@ -65,12 +81,10 @@ public class LogHandler { .forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, error)).queue()); } } - } private static void sendMessageToChannel(CommandErrorException error) { CommandContext context = error.getCommandContext(); - logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage()); context.reply(error.getMessage()); } } diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index 69e990d..249f459 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -47,7 +47,10 @@ public class SessionManager { sessionFactory = metadata.getSessionFactoryBuilder().build(); } catch (Exception e) { - Sentry.captureException(e); + String env = Settings.getInstance().get("BOT_ENV", "dev"); + if (!"dev".equals(env)) { + Sentry.captureException(e); + } shutdown(); logger.error("Error connecting to database. Shutting down..", e); diff --git a/src/main/java/netneutrality/core/UnsafeShutdown.java b/src/main/java/netneutrality/core/UnsafeShutdown.java deleted file mode 100644 index 9b5e016..0000000 --- a/src/main/java/netneutrality/core/UnsafeShutdown.java +++ /dev/null @@ -1,67 +0,0 @@ -package netneutrality.core;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.music.MusicManager; -import netneutrality.music.TrackScheduler; -import org.json.JSONArray; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Map; - -public class UnsafeShutdown { - public static boolean SAFE = false; - - //TODO: finish - private static void saveGuildsState() { - Map<String, GuildManager> managers = GuildManager.getManagers(); - - for (GuildManager manager : managers.values()) { - File state = new File("state.json"); - - try { - if (!state.exists()) { - state.createNewFile(); - } - - FileWriter writer = new FileWriter(state); - JSONArray array = new JSONArray(); - - - - MusicManager musicManager = MusicManager.get(manager.getGuild()); - TrackScheduler trackScheduler = musicManager.getScheduler(); - - JSONObject music = new JSONObject(); - - music.put("current_channel", ""); - music.put("current_topic", ""); - music.put("current_topic", ""); - } catch (IOException e) { - e.printStackTrace(); - } - - - - - } - } - - public static void saveState() { - saveGuildsState(); - } -} diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 4173d53..40d3395 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -156,6 +156,10 @@ public class CommandContext { } } + public void replyToMessage(String format, Object... arguments) { + replyToMessage(String.format(format, arguments)); + } + public void replyToMessage(Message msg) { if (channel != null && channel.canTalk() && message != null) { message.reply(msg).queue(); diff --git a/src/main/java/netneutrality/db/GSettings.java b/src/main/java/netneutrality/db/GSettings.java new file mode 100644 index 0000000..8ec59c0 --- /dev/null +++ b/src/main/java/netneutrality/db/GSettings.java @@ -0,0 +1,36 @@ +package netneutrality.db; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import netneutrality.utils.Settings; + +public enum GSettings { + //TODO: description + PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")), + MUSIC_ROLE("MUSIC_ROLE", ""), + MUSIC_CHANNEL("MUSIC_CHANNEL", ""), + MUSIC_VOLUME("MUSIC_VOLUME", "30"), + MUSIC_TOPIC("MUSIC_TOPIC", "0"), + BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); + + private final String name; + private final String defaultValue; + + GSettings(String name, String defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public String getDefaultValue() { + return defaultValue; + } +} diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index 4816ff6..62bb276 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -15,6 +15,7 @@ import netneutrality.command.AbstractCommand; import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; +import netneutrality.db.GSettings; import netneutrality.utils.Settings; import org.jetbrains.annotations.NotNull; @@ -39,7 +40,7 @@ public class MessageReceivedHandler extends ListenerAdapter { String rawMessage = message.getContentDisplay().trim(); //String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); - String prefix = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.PREFIX); + String prefix = GuildManager.getManager(guild).getSetting(GSettings.PREFIX); if (rawMessage.startsWith(prefix)) { rawMessage = rawMessage.replaceFirst(String.format("^[%s\\s]{1,}", prefix), "").trim(); diff --git a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java b/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java index 338977e..7a42370 100644 --- a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java +++ b/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java @@ -1,10 +1,4 @@ -package netneutrality.handler.hooks.voice;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - +package netneutrality.handler.hooks.voice; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java index fd51090..bd0d641 100644 --- a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java +++ b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java @@ -1,10 +1,4 @@ -package netneutrality.handler.ratelimiter;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - +package netneutrality.handler.ratelimiter; /* * Copyright (c) anthorob * @@ -18,6 +12,7 @@ import net.dv8tion.jda.api.entities.TextChannel; import java.time.OffsetDateTime; +//TODO: to remove? or atleast make it useful public class MessageRateLimiterImpl implements IMessageRateLimiter { private final int messagePerSecond = 5; private static Member lastSender; diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index 688fb46..b36e4d5 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -1,5 +1,4 @@ package netneutrality.music; - /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index ba63d4e..de0ea5e 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -7,33 +7,30 @@ package netneutrality.music; * https://discord.gg/CdFcyQ */ -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.source.AudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; -import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; -import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.core.GuildManager; +import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; +import netneutrality.db.GSettings; +import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.loadable.LoadableSong; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; -import netneutrality.utils.MessageFunction; import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; -import java.util.Map; -import java.util.Queue; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -46,10 +43,11 @@ public class MusicManager { private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + private final static Map<String, AudioSourceManager> sources = new HashMap<>(); private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; - private TrackLoadingHandler lastLoadingHandler; + private TrackLoader lastTrackLoader; private ScheduledFuture<?> autoDisconnectThread; private final int baseVolume; @@ -57,7 +55,7 @@ public class MusicManager { this.guild = guild; this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(this); - this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_VOLUME)); + this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GSettings.MUSIC_VOLUME)); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); @@ -74,21 +72,23 @@ public class MusicManager { } public static void initPlayerManager() { - AudioSourceManagers.registerRemoteSources(playerManager); - - playerManager.registerSourceManager(new YoutubeAudioSourceManager( - true, + YoutubeAudioSourceManager youtubeSource = new YoutubeAudioSourceManager(true, Settings.getInstance().get("GG_EMAIL", ""), - Settings.getInstance().get("GG_PASS", ""))); - playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); + Settings.getInstance().get("GG_PASS", "")); + SoundCloudAudioSourceManager soundcloudSource = SoundCloudAudioSourceManager.createDefault(); + + sources.put("youtube", youtubeSource); + sources.put("soundcloud", soundcloudSource); + playerManager.registerSourceManager(youtubeSource); + playerManager.registerSourceManager(soundcloudSource); } - public boolean isConnectedTo(VoiceChannel vChannel) { - return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); + public boolean isNotConnectedTo(VoiceChannel vChannel) { + return vChannel == null || !vChannel.equals(guild.getAudioManager().getConnectedChannel()); } public synchronized void connect(VoiceChannel vChannel) { - if (vChannel != null && !isConnectedTo(vChannel)) { + if (vChannel != null && isNotConnectedTo(vChannel)) { logger.debug("Guild {}: connecting to voice channel {}", vChannel.getGuild().getId(), vChannel.getId()); guild.getAudioManager().openAudioConnection(vChannel); guild.getAudioManager().setSelfDeafened(true); @@ -131,24 +131,22 @@ public class MusicManager { return guild; } - public TrackLoadingHandler getLastLoadingHandler() { - return lastLoadingHandler; + public void stopLoading() { + lastTrackLoader.stopLoading(); } public synchronized void leave() { - if (isConnected()) { + if (guild != null && guild.getAudioManager().getConnectedChannel() != null) { logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId()); player.stopTrack(); guild.getAudioManager().closeAudioConnection(); } - scheduler.getTopicManager().detachTextChannel(); + scheduler.detachTextChannel(); if (autoDisconnectThread != null) { - boolean cancel = autoDisconnectThread.cancel(true); - - if (cancel) - autoDisconnectThread = null; + autoDisconnectThread.cancel(true); + autoDisconnectThread = null; } } @@ -167,41 +165,12 @@ public class MusicManager { } public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { - Member member = context.getGuildUser(); - TextChannel channel = context.getChannel(); - logger.debug("Guild {}: request to play by user {}, string=[{}]", guild.getId(), context.getGuildUser().getId(), url); + logger.debug("Guild {}: request to play {} by user {}", guild.getId(), url, context.getGuildUser().getId()); - if (member.getVoiceState() == null) { - context.deleteMessage(); - return; - } + List<LoadableSong> toLoad = new ArrayList<>(); + toLoad.add(new LoadableSong(null, url, null)); - if (!member.getVoiceState().inVoiceChannel()) { - context.reply("You are not in a voice channel"); - context.deleteMessage(); - return; - } - - VoiceChannel vChannel = member.getVoiceState().getChannel(); - if (needToBeConnected && !isConnectedTo(vChannel)) { - context.reply("The player is not in your voice channel"); - context.deleteMessage(); - return; - } - - if (!isConnectedTo(vChannel)) { - connect(vChannel); - } - - String identifier = SourceFinder.getIdentifier(url); - scheduler.getTopicManager().attachTextChannel(channel); - - if (identifier != null) { - lastLoadingHandler = new TrackLoadingHandler(identifier, silent, this, context); - playerManager.loadItemOrdered(this, identifier, lastLoadingHandler); - } else { - context.replyToMessage("No source found to play the given url"); - } + play(toLoad, context, needToBeConnected, silent); } public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) { @@ -209,103 +178,33 @@ public class MusicManager { TextChannel channel = context.getChannel(); if (member.getVoiceState() == null) { + logger.error("Guild {}: Voice state is null", guild.getId()); + context.replyToMessage("Voice state is null, something has gone wrong."); + LogHandler.log(new CommandExecutionException("Voice state is null", context, null)); + return; } if (!member.getVoiceState().inVoiceChannel()) { - context.reply("You are not in a voice channel"); + context.replyToMessage("You are not in a voice channel"); return; } VoiceChannel vChannel = member.getVoiceState().getChannel(); - if (needToBeConnected && !isConnectedTo(vChannel)) { - context.reply("The player is not in your voice channel"); + if (needToBeConnected && isNotConnectedTo(vChannel)) { + context.replyToMessage("The player is not in your voice channel"); return; } - if (!isConnectedTo(vChannel)) { + if (isNotConnectedTo(vChannel)) { connect(vChannel); + scheduler.attachTextChannel(channel); } - scheduler.getTopicManager().attachTextChannel(channel); - boolean fromOnlineSource = songs.size() > 1; - - for (LoadableSong song : songs) { - String identifier = SourceFinder.getIdentifier(song.name()); - - if (identifier != null) { - playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { - @Override - public void trackLoaded(AudioTrack track) { - if (!fromOnlineSource) { - logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); - context.deleteMessage(); - - scheduler.getQueueManager().queue(track, member); - - if (!silent) { - //context.replyToMessage("Added track to queue"); - context.reply(MessageFunction.buildAddingTrackMessage(track, member, identifier)); - } - } - } - - @Override - public void playlistLoaded(AudioPlaylist playlist) { - logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - - if (!playlist.getTracks().isEmpty()) { - context.deleteMessage(); - - if (playlist.isSearchResult()) { - AudioTrack track = playlist.getTracks().get(0); - scheduler.getQueueManager().queue(track, member); - - if (!silent && !fromOnlineSource) { - //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); - context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))); - } - - } else { - if (!silent && !fromOnlineSource) { - //context.replyToMessage("Added playlist to queue"); - context.reply(MessageFunction.buildAddingPlaylistMessage(playlist, member, identifier)); - } - - for (AudioTrack track : playlist.getTracks()) { - synchronized (scheduler.getQueueManager().getQueue()) { - scheduler.getQueueManager().queue(track, member); - } - } - } - } else { - context.replyToMessage("Playlist is empty"); - } - - } - - @Override - public void noMatches() { - logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); - - if (fromOnlineSource) { - //TODO: - } - context.replyToMessage("No matches found"); - } - - @Override - public void loadFailed(FriendlyException e) { - logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); - context.replyToMessage("Failed to load track: " + e.getMessage()); - } - }); - } else { - context.replyToMessage("No source found to play the given url"); - } - - } + TrackLoader loader = new TrackLoader(this, context, playerManager, silent); + lastTrackLoader = loader; + loader.loadAllSongs(songs); } public synchronized boolean removeFromQueue(int index) { @@ -345,22 +244,23 @@ public class MusicManager { // Minus the bot itself int connected = voiceChannel.getMembers().size() - 1; - if (connected > 2) { - double needed = connected / 2.1; - - info.addSkip(context.getGuildUser()); - logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId()); - - if (info.getSkips().size() > needed) { - context.reply("Skipping current track: %s", info.getTrack().getInfo().title); - skip(1); - } else { - context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); - } - - } else { + if (connected < 3) { context.reply("Skipping current track since not enough people are connected to the voice channel."); skip(1); + + return; + } + + double needed = connected / 2.1; + + info.addSkip(context.getGuildUser()); + logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId()); + + if (info.getSkips().size() > needed) { + context.reply("Skipping current track: %s", info.getTrack().getInfo().title); + skip(1); + } else { + context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); } } @@ -368,7 +268,7 @@ public class MusicManager { player.setVolume(volume); } - public int getQueueSize () { + public int getQueueSize() { synchronized (scheduler.getQueueManager().getQueue()) { return scheduler.getQueueManager().getQueue().size(); } diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 5b18728..550449f 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -117,7 +117,7 @@ public class QueueManager { public void clearQueue() { scheduler.getMusicManager().leave(); - scheduler.getMusicManager().getLastLoadingHandler().stopLoading(); + scheduler.getMusicManager().stopLoading(); synchronized (queue) { queue.clear(); diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index eca65df..e18eb07 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -12,7 +12,7 @@ import java.util.regex.Pattern; public class SourceFinder { - public enum AvailableSource { + public enum AudioSourceType { Youtube, Soundcloud, Bandcamp, @@ -24,23 +24,22 @@ public class SourceFinder { private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); - private static Matcher BandcampMatcher; - private static Matcher vimeoMatcher; + private static Matcher twitchMatcher; - public static AvailableSource getSource(String url) { + public static AudioSourceType getSource(String url) { Matcher youtubeMatcher = youtubePattern.matcher(url); Matcher soundcloudMatcher = soundcloudPattern.matcher(url); if (youtubeMatcher.find()) - return AvailableSource.Youtube; + return AudioSourceType.Youtube; if (soundcloudMatcher.find()) - return AvailableSource.Soundcloud; + return AudioSourceType.Soundcloud; if (!(url.startsWith("http://") || url.startsWith("https://"))) - return AvailableSource.YTSearch; + return AudioSourceType.YTSearch; - return AvailableSource.Nothing; + return AudioSourceType.Nothing; } public static String getIdentifier(String url) { diff --git a/src/main/java/netneutrality/music/TopicManager.java b/src/main/java/netneutrality/music/TopicManager.java deleted file mode 100644 index d080d9a..0000000 --- a/src/main/java/netneutrality/music/TopicManager.java +++ /dev/null @@ -1,84 +0,0 @@ -package netneutrality.music;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.core.GuildManager; -import org.apache.logging.log4j.LogManager; - -import java.util.concurrent.TimeUnit; - -public class TopicManager { - - private final TrackScheduler scheduler; - private final Guild guild; - private TextChannel channel; - private String originalTopic; - - public TopicManager(TrackScheduler scheduler) { - this.scheduler = scheduler; - this.guild = scheduler.getGuild(); - } - - public TrackScheduler getScheduler() { - return scheduler; - } - - public Guild getGuild() { - return guild; - } - - public TextChannel getTextChannel() { - return channel; - } - - public String getOriginalTopic() { - return originalTopic; - } - - public synchronized void attachTextChannel(TextChannel channel) { - this.channel = channel; - - if (originalTopic == null) { - String current = channel.getTopic(); - originalTopic = (current == null ? "" : current); - } - } - - public synchronized void detachTextChannel() { - updateTopic(null); - - this.channel = null; - this.originalTopic = null; - } - - public synchronized void updateTopic(AudioTrack track) { - if (isEnabled() && channel != null) { - - if (track == null) { - LogManager.getLogger(TopicManager.class).debug("Guild {}: Resetting topic for channel {}", guild.getId(), channel.getId()); - channel.getManager().setTopic(originalTopic).queueAfter(5, TimeUnit.SECONDS); - } else { - LogManager.getLogger(TopicManager.class).debug("Guild {}: Setting topic for channel {} to [{}]", guild.getId(), channel.getId(), track.getInfo().title); - channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(5, TimeUnit.SECONDS); - } - - } - } - - public void sendMessageToChannel(String msg) { - if (channel != null) { - channel.sendMessage(msg).queue(); - } - } - - private boolean isEnabled() { - // rate limiting too much - return false; - } -} diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/netneutrality/music/TrackLoader.java new file mode 100644 index 0000000..462f0f2 --- /dev/null +++ b/src/main/java/netneutrality/music/TrackLoader.java @@ -0,0 +1,116 @@ +package netneutrality.music; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; +import netneutrality.music.loadable.CachedSource; +import netneutrality.music.loadable.LoadableMusicSource; +import netneutrality.music.loadable.LoadableSong; +import netneutrality.thread.ThreadManager; + +import java.util.List; + +public class TrackLoader implements Runnable { + + private final CommandContext context; + private final MusicManager musicManager; + private final AudioPlayerManager audioPlayerManager; + private TrackLoadingHandler lastLoadingHandler; + private List<LoadableSong> songs; + private LoadableMusicSource source; + private int numberOfTracksLoaded; + private int totalNumberOfTracks; + private boolean loadingDisabled = false; + private boolean silent; + private final Object sync = new Object(); + + public TrackLoader(MusicManager musicManager, CommandContext context, AudioPlayerManager playerManager, boolean silent) { + this.musicManager = musicManager; + this.context = context; + this.audioPlayerManager = playerManager; + this.silent = silent; + } + + public void loadAllSongs(List<LoadableSong> songs) { + this.songs = songs; + if (songs.size() > 1) { + silent = true; + } + + ThreadManager.getExecutor("Track loader").submit(this); + } + + public void loadAllSongs(CachedSource cachedSource) { + this.source = cachedSource.getSource(); + + loadAllSongs(cachedSource.getSongs()); + } + + public void stopLoading() { + loadingDisabled = true; + + if (lastLoadingHandler != null) { + lastLoadingHandler.stopLoading(); + } + } + + @Override + public void run() { + for (LoadableSong song : songs) { + if (loadingDisabled) { + break; + } + + SourceFinder.AudioSourceType type = SourceFinder.getSource(song.name()); + String identifier = SourceFinder.getIdentifier(song.name()); + + if (identifier != null) { + TrackLoadingHandler loadingHandler = new TrackLoadingHandler(context, musicManager, identifier, type, silent); + loadingHandler.useCallbackOnLoad(success -> { + + synchronized (sync) { + if (success) { + numberOfTracksLoaded++; + } + + totalNumberOfTracks++; + + System.out.println("notify, loaded: " + numberOfTracksLoaded + ", total: " + totalNumberOfTracks); + sync.notify(); + } + + }); + lastLoadingHandler = loadingHandler; + + audioPlayerManager.loadItemOrdered(this, identifier, loadingHandler); + } else { + if (songs.size() == 1) { + context.replyToMessage("No source found to play the given url"); + } + } + } + + try { + synchronized (sync) { + while (!(songs.size() == totalNumberOfTracks)) { + System.out.println("wait"); + sync.wait(); + } + + //TODO: logic + if (songs.size() > 1 && source != null && !loadingDisabled) { + context.replyToMessage("Loaded %d of %d tracks from online source", numberOfTracksLoaded, totalNumberOfTracks); + } + } + } catch (InterruptedException exception) { + LogHandler.log(exception); + } + + } +} diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index 97a84e5..6d7f853 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -12,23 +12,29 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; +import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.function.Consumer; + public class TrackLoadingHandler implements AudioLoadResultHandler { private final Logger logger = LoggerFactory.getLogger(TrackLoadingHandler.class); private final String identifier; + private final SourceFinder.AudioSourceType type; private final boolean silent; + private Consumer<Boolean> loadConsumer; private boolean loadingDisabled = false; private final Guild guild; private final TrackScheduler scheduler; private final CommandContext context; - public TrackLoadingHandler(String identifier, boolean silent, MusicManager manager, CommandContext context) { + public TrackLoadingHandler(CommandContext context, MusicManager manager, String identifier, SourceFinder.AudioSourceType type, boolean silent) { this.identifier = identifier; + this.type = type; this.silent = silent; this.guild = manager.getGuild(); this.scheduler = manager.getScheduler(); @@ -40,45 +46,59 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { loadingDisabled = true; } + public void useCallbackOnLoad(Consumer<Boolean> consumer) { + this.loadConsumer = consumer; + } + @Override public void trackLoaded(AudioTrack audioTrack) { + if (loadConsumer != null) { + loadConsumer.accept(true); + } + if (loadingDisabled) { return; } - logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); context.deleteMessage(); + logger.debug("Guild {}: track loaded: {}", guild.getId(), audioTrack.getIdentifier()); scheduler.getQueueManager().queue(audioTrack, context.getGuildUser()); if (!silent) { - //context.replyToMessage("Added track to queue"); - context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), identifier)); + scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type)); + // context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type)); } } @Override public void playlistLoaded(AudioPlaylist audioPlaylist) { + if (loadConsumer != null) { + loadConsumer.accept(true); + } + if (loadingDisabled) { return; } - logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - context.deleteMessage(); - if (audioPlaylist.isSearchResult()) { - AudioTrack track = audioPlaylist.getTracks().get(0); - scheduler.getQueueManager().queue(track, context.getGuildUser()); + if (!audioPlaylist.getTracks().isEmpty()) { + if (audioPlaylist.isSearchResult()) { + AudioTrack track = audioPlaylist.getTracks().get(0); + scheduler.getQueueManager().queue(track, context.getGuildUser()); - if (!silent) { - //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); - context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), String.format("https://youtu.be/%s", track.getIdentifier()))); + if (!silent) { + scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type)); + // context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type)); + } + + return; } - } else { + context.deleteMessage(); if (!silent) { - //context.replyToMessage("Added playlist to queue"); - context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier)); + scheduler.sendMessageToChannel(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type)); + // context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type)); } for (AudioTrack track : audioPlaylist.getTracks()) { @@ -91,19 +111,28 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { } } } - - } @Override public void noMatches() { logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); - context.replyToMessage("No matches found"); + + if (!silent) + context.replyToMessage("No matches found"); + + if (loadConsumer != null) + loadConsumer.accept(false); } @Override public void loadFailed(FriendlyException e) { logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); - context.replyToMessage("Failed to load track: " + e.getMessage()); + LogHandler.log(e); + + if (!silent) + context.replyToMessage("Failed to load track: " + e.getMessage()); + + if (loadConsumer != null) + loadConsumer.accept(false); } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 658d5d1..da3031b 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -1,5 +1,4 @@ package netneutrality.music; - /* * Copyright (c) anthorob * @@ -13,6 +12,9 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.core.LogHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,9 +22,9 @@ public class TrackScheduler extends AudioEventAdapter { private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class); private final QueueManager queueManager; - private final TopicManager topicManager; private final MusicManager manager; private final AudioPlayer player; + private TextChannel currentChannel; private final Guild guild; public TrackScheduler(MusicManager manager) { @@ -30,17 +32,12 @@ public class TrackScheduler extends AudioEventAdapter { this.player = manager.getPlayer(); this.guild = manager.getGuild(); this.queueManager = new QueueManager(this); - this.topicManager = new TopicManager(this); } public QueueManager getQueueManager() { return queueManager; } - public TopicManager getTopicManager() { - return topicManager; - } - public MusicManager getMusicManager() { return manager; } @@ -53,6 +50,30 @@ public class TrackScheduler extends AudioEventAdapter { return guild; } + public TextChannel getTextChannel() { + return currentChannel; + } + + public synchronized void attachTextChannel(TextChannel channel) { + this.currentChannel = channel; + } + + public synchronized void detachTextChannel() { + this.currentChannel = null; + } + + public void sendMessageToChannel(String msg) { + if (currentChannel != null && currentChannel.canTalk()) { + currentChannel.sendMessage(msg).queue(); + } + } + + public void sendMessageToChannel(MessageEmbed embed, MessageEmbed... embeds) { + if (currentChannel != null && currentChannel.canTalk()) { + currentChannel.sendMessageEmbeds(embed, embeds).queue(); + } + } + @Override public void onPlayerPause(AudioPlayer player) { // Player was paused @@ -66,7 +87,6 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { logger.debug("Guild {}: starting track: {}", guild.getId(), track.getIdentifier()); - topicManager.updateTopic(track); } @Override @@ -84,7 +104,6 @@ public class TrackScheduler extends AudioEventAdapter { if (endReason == AudioTrackEndReason.STOPPED) { synchronized (queueManager.getQueue()) { - topicManager.updateTopic(null); queueManager.getQueue().poll(); } } @@ -100,15 +119,14 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { logger.debug("Guild {}: exception while playing track [{}]: {}", guild.getId(), track.getIdentifier(), exception.getMessage()); - topicManager.updateTopic(null); - topicManager.sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage()); + LogHandler.log(exception); + sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage()); } @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { logger.debug("Guild {}: currently playing track is stuck: {}", guild.getId(), track.getIdentifier()); - topicManager.updateTopic(null); - topicManager.sendMessageToChannel("Current track is stuck, skipping to next"); + sendMessageToChannel("Current track is stuck, skipping to next"); queueManager.nextTrack(player); } } diff --git a/src/main/java/netneutrality/music/loadable/CachedSource.java b/src/main/java/netneutrality/music/loadable/CachedSource.java index 2dc83c3..3be39ed 100644 --- a/src/main/java/netneutrality/music/loadable/CachedSource.java +++ b/src/main/java/netneutrality/music/loadable/CachedSource.java @@ -15,7 +15,7 @@ public class CachedSource { private OffsetDateTime lastAccess; private final List<LoadableSong> songs; - public CachedSource(LoadableMusicSource source, List<LoadableSong> songs) { + protected CachedSource(LoadableMusicSource source, List<LoadableSong> songs) { this.source = source; this.lastAccess = OffsetDateTime.now(); this.songs = songs; diff --git a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java index 4265a3d..ff2c46e 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java +++ b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java @@ -34,14 +34,13 @@ public class LoadableSourceManager { } return cachedSource; - } else { - List<LoadableSong> songs = loadFromUrl(source); - CachedSource newCachedSource = new CachedSource(source, songs); - - cache.put(source.getIdentifier(), newCachedSource); - return newCachedSource; } + List<LoadableSong> songs = loadFromUrl(source); + CachedSource newCachedSource = new CachedSource(source, songs); + + cache.put(source.getIdentifier(), newCachedSource); + return newCachedSource; } private List<LoadableSong> loadFromUrl(LoadableMusicSource source) { diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 4c214b0..a6069ca 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -15,8 +15,11 @@ import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; import netneutrality.core.context.CommandContext; +import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; +import netneutrality.music.SourceFinder; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,40 +72,62 @@ public class MessageFunction { return message.build(); } - public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user, String identifier) { + public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member member, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); - message.setAuthor("Link to track", identifier); - message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); + String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); + String url = track.getIdentifier(); + String thumbnail = null; + + if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { + url = String.format("https://youtu.be/%s", track.getIdentifier()); + thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier()); + } + + if (thumbnail != null) { + message.setThumbnail(thumbnail); + } message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); - message.addField("Track title: ", track.getInfo().title, false); + message.addField("Track title: ", String.format("[**`%s`**](%s)", track.getInfo().title, url), false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); - message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); + message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user, String identifier) { + public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member member, String identifier, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); - message.setAuthor("Link to playlist", identifier); - message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier())); + String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); + String url = identifier; + String thumbnail = null; + + if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { + url = String.format("https://youtu.be/%s", playlist.getSelectedTrack().getIdentifier()); + thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier()); + } + + if (thumbnail != null) { + message.setThumbnail(thumbnail); + } message.setTitle("Adding playlist to queue.."); message.setColor(Color.BLUE); - message.addField("Playlist: ", playlist.getName(), false); + message.addField("Playlist: ", String.format("[**`%s`**](%s)", playlist.getName(), url), false); message.addField("Number of tracks: ", String.valueOf(playlist.getTracks().size()), false); - message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); + message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user, boolean currentlyPlaying) { + public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member member, boolean currentlyPlaying) { + String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); ArrayList<AudioTrack> tracks = manager.getScheduler().getQueueManager().getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); + int numberofTracksShown = Math.min(tracks.size(), 10); EmbedBuilder message = new EmbedBuilder(); - message.setTitle("Current queue (showing 10 out of " + tracks.size() + " items):"); + message.setTitle(String.format("Current queue (showing %d out of %d items):", numberofTracksShown, tracks.size())); message.setColor(Color.BLUE); int index = 0; @@ -118,7 +143,7 @@ public class MessageFunction { if (index == 10) break; } - message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); + message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); @@ -191,7 +216,7 @@ public class MessageFunction { return messages; } - public static MessageEmbed buildDebugMessage(CommandContext context, CommandExecutionException error) { + public static MessageEmbed buildDebugMessage(CommandContext context, CommandException error) { EmbedBuilder message = new EmbedBuilder(); message.setColor(Color.RED); message.setTitle(":warning: Exception in command execution"); diff --git a/src/main/java/netneutrality/utils/MiscUtils.java b/src/main/java/netneutrality/utils/MiscUtils.java new file mode 100644 index 0000000..1ff5648 --- /dev/null +++ b/src/main/java/netneutrality/utils/MiscUtils.java @@ -0,0 +1,26 @@ +package netneutrality.utils; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +public class MiscUtils { + + public static boolean isValidUrl(String url) { + try { + URL object = new URL(url); + object.toURI(); + + return true; + } catch (MalformedURLException | URISyntaxException e) { + return false; + } + } +} From b5b0e209c747d3c51e9964091780376bb0222497 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 5 Sep 2022 18:18:18 -0400 Subject: [PATCH 097/155] Improve currency validation by using java.util.Currency Remove unused commands Update dependencies --- pom.xml | 12 +- .../command/crypto/BitcoinPriceCommand.java | 8 +- .../command/crypto/CryptoPriceCommand.java | 11 +- .../command/crypto/Currency.java | 52 -------- .../command/crypto/EthereumPriceCommand.java | 8 +- .../command/crypto/LitecoinPriceCommand.java | 8 +- .../command/specific/DatabaseCommand.java | 115 ------------------ .../command/specific/LoggingCommand.java | 55 --------- 8 files changed, 23 insertions(+), 246 deletions(-) delete mode 100644 src/main/java/netneutrality/command/crypto/Currency.java delete mode 100644 src/main/java/netneutrality/command/specific/DatabaseCommand.java delete mode 100644 src/main/java/netneutrality/command/specific/LoggingCommand.java diff --git a/pom.xml b/pom.xml index 4ba5e5f..1450722 100644 --- a/pom.xml +++ b/pom.xml @@ -102,7 +102,7 @@ <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>3.3.0</version> + <version>3.4.2</version> </dependency> <dependency> @@ -118,7 +118,7 @@ <dependency> <groupId>com.github.walkyst</groupId> <artifactId>lavaplayer-fork</artifactId> - <version>1.3.98.3</version> + <version>1.3.98.4</version> </dependency> <dependency> @@ -140,7 +140,7 @@ <dependency> <groupId>io.sentry</groupId> <artifactId>sentry</artifactId> - <version>6.0.0</version> + <version>6.4.0</version> </dependency> <dependency> <groupId>p6spy</groupId> @@ -164,17 +164,17 @@ <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>8.0.29</version> + <version>8.0.30</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> - <version>2.17.2</version> + <version>2.18.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> - <version>2.17.2</version> + <version>2.18.0</version> </dependency> <dependency> diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index f94fafb..c30adaf 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -16,6 +16,7 @@ import org.json.JSONException; import org.json.JSONObject; import java.text.NumberFormat; +import java.util.Currency; import java.util.Locale; public class BitcoinPriceCommand extends AbstractCommand { @@ -66,13 +67,12 @@ public class BitcoinPriceCommand extends AbstractCommand { String currency = "USD"; if (args.length == 1) { - if (Currency.isCurrency(args[0].toUpperCase())) - currency = args[0].toUpperCase(); - else { + try { + currency = Currency.getInstance(args[0].toUpperCase()).getCurrencyCode(); + } catch (IllegalArgumentException exception) { context.reply("Please enter a valid currency"); return; } - } String finalCurrency = currency; diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index be13696..bce1e27 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -16,6 +16,7 @@ import org.json.JSONException; import org.json.JSONObject; import java.text.NumberFormat; +import java.util.Currency; import java.util.Locale; public class CryptoPriceCommand extends AbstractCommand { @@ -52,7 +53,7 @@ public class CryptoPriceCommand extends AbstractCommand { @Override public String getDescription() { - return "Get the price of cryptocurrrency"; + return "Get the price of cryptocurrencies"; } @Override @@ -66,15 +67,13 @@ public class CryptoPriceCommand extends AbstractCommand { String currency = "USD"; if (args.length > 0) { - if (args.length == 2) { - if (Currency.isCurrency(args[1].toUpperCase())) - currency = args[1].toUpperCase(); - else { + try { + currency = Currency.getInstance(args[1].toUpperCase()).getCurrencyCode(); + } catch (IllegalArgumentException exception) { context.reply("Please enter a valid currency"); return; } - } String crypto = args[0].toUpperCase(); diff --git a/src/main/java/netneutrality/command/crypto/Currency.java b/src/main/java/netneutrality/command/crypto/Currency.java deleted file mode 100644 index 20c4013..0000000 --- a/src/main/java/netneutrality/command/crypto/Currency.java +++ /dev/null @@ -1,52 +0,0 @@ -package netneutrality.command.crypto; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ -public enum Currency { - - AED("AED"), AFN("AFN"), ALL("ALL"), AMD("AMD"), ANG("ANG"), AOA("AOA"), ARS("ARS"), AUD("AUD"), AWG("AWG"), AZN("AZN"), BAM("BAM"), BBD("BBD"), - BDT("BDT"), BGN("BGN"), BHD("BHD"), BIF("BIF"), BMD("BMD"), BND("BND"), BOB("BOB"), BOV("BOV"), BRL("BRL"), BSD("BSD"), BTN("BTN"), BWP("BWP"), - BYN("BYN"), BYR("BYR"), BZD("BZD"), CAD("CAD"), CDF("CDF"), CHE("CHE"), CHF("CHF"), CHW("CHW"), CLF("CLF"), CLP("CLP"), CNY("CNY"), COP("COP"), - COU("COU"), CRC("CRC"), CUC("CUC"), CUP("CUP"), CVE("CVE"), CZK("CZK"), DJF("DJF"), DKK("DKK"), DOP("DOP"), DZD("DZD"), EGP("EGP"), ERN("ERN"), - ETB("ETB"), EUR("EUR"), FJD("FJD"), FKP("FKP"), GBP("GBP"), GEL("GEL"), GHS("GHS"), GIP("GIP"), GMD("GMD"), GNF("GNF"), GTQ("GTQ"), GYD("GYD"), - HKD("HKD"), HNL("HNL"), HRK("HRK"), HTG("HTG"), HUF("HUF"), IDR("IDR"), ILS("ILS"), INR("INR"), IQD("IQD"), IRR("IRR"), ISK("ISK"), JMD("JMD"), - JOD("JOD"), JPY("JPY"), KES("KES"), KGS("KGS"), KHR("KHR"), KMF("KMF"), KPW("KPW"), KRW("KRW"), KWD("KWD"), KYD("KYD"), KZT("KZT"), LAK("LAK"), - LBP("LBP"), LKR("LKR"), LRD("LRD"), LSL("LSL"), LYD("LYD"), MAD("MAD"), MDL("MDL"), MGA("MGA"), MKD("MKD"), MMK("MMK"), MNT("MNT"), MOP("MOP"), - MRO("MRO"), MUR("MUR"), MVR("MVR"), MWK("MWK"), MXN("MXN"), MXV("MXV"), MYR("MYR"), MZN("MZN"), NAD("NAD"), NGN("NGN"), NIO("NIO"), NOK("NOK"), - NPR("NPR"), NZD("NZD"), OMR("OMR"), PAB("PAB"), PEN("PEN"), PGK("PGK"), PHP("PHP"), PKR("PKR"), PLN("PLN"), PYG("PYG"), QAR("QAR"), RON("RON"), - RSD("RSD"), RUB("RUB"), RWF("RWF"), SAR("SAR"), SBD("SBD"), SCR("SCR"), SDG("SDG"), SEK("SEK"), SGD("SGD"), SHP("SHP"), SLL("SLL"), SOS("SOS"), - SRD("SRD"), SSP("SSP"), STD("STD"), SYP("SYP"), SZL("SZL"), THB("THB"), TJS("TJS"), TMT("TMT"), TND("TND"), TOP("TOP"), TRY("TRY"), TTD("TTD"), - TWD("TWD"), TZS("TZS"), UAH("UAH"), UGX("UGX"), USD("USD"), USN("USN"), UYI("UYI"), UYU("UYU"), UZS("UZS"), VEF("VEF"), VND("VND"), VUV("VUV"), - WST("WST"), XAF("XAF"), XAG("XAG"), XAU("XAU"), XBA("XBA"), XBB("XBB"), XBC("XBC"), XBD("XBD"), XCD("XCD"), XDR("XDR"), XFU("XFU"), XOF("XOF"), - XPD("XPD"), XPF("XPF"), XPT("XPT"), XSU("XSU"), XTS("XTS"), XUA("XUA"), XXX("XXX"), YER("YER"), ZAR("ZAR"), ZMW("ZMW"); - - private final String iso4217Code; - - Currency(String code) { - this.iso4217Code = code; - } - - public String getIso4217Code() { - return iso4217Code; - } - - @Override - public String toString() { - return "Currency{" + - "iso4217Code='" + iso4217Code + '\'' + - '}'; - } - - public static boolean isCurrency(String str) { - for (Currency c : Currency.values()) { - if (c.name().equals(str.toUpperCase())) - return true; - } - - return false; - } -} diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 6e7c768..a29ccf8 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -16,6 +16,7 @@ import org.json.JSONException; import org.json.JSONObject; import java.text.NumberFormat; +import java.util.Currency; import java.util.Locale; public class EthereumPriceCommand extends AbstractCommand { @@ -66,13 +67,12 @@ public class EthereumPriceCommand extends AbstractCommand { String currency = "USD"; if (args.length == 1) { - if (Currency.isCurrency(args[0].toUpperCase())) - currency = args[0].toUpperCase(); - else { + try { + currency = Currency.getInstance(args[0].toUpperCase()).getCurrencyCode(); + } catch (IllegalArgumentException exception) { context.reply("Please enter a valid currency"); return; } - } String finalCurrency = currency; diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index bf33780..c782d67 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -16,6 +16,7 @@ import org.json.JSONException; import org.json.JSONObject; import java.text.NumberFormat; +import java.util.Currency; import java.util.Locale; public class LitecoinPriceCommand extends AbstractCommand { @@ -66,13 +67,12 @@ public class LitecoinPriceCommand extends AbstractCommand { String currency = "USD"; if (args.length == 1) { - if (Currency.isCurrency(args[0].toUpperCase())) - currency = args[0].toUpperCase(); - else { + try { + currency = Currency.getInstance(args[0].toUpperCase()).getCurrencyCode(); + } catch (IllegalArgumentException exception) { context.reply("Please enter a valid currency"); return; } - } String finalCurrency = currency; diff --git a/src/main/java/netneutrality/command/specific/DatabaseCommand.java b/src/main/java/netneutrality/command/specific/DatabaseCommand.java deleted file mode 100644 index 965daa7..0000000 --- a/src/main/java/netneutrality/command/specific/DatabaseCommand.java +++ /dev/null @@ -1,115 +0,0 @@ -package netneutrality.command.specific; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.User; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBMessage; -import netneutrality.db.entities.OLogMessage; -import netneutrality.utils.Settings; - -import java.awt.*; -import java.time.OffsetDateTime; -import java.util.List; - -public class DatabaseCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "database"; - } - - @Override - public String[] getAlias() { - return new String[]{"db"}; - } - - @Override - public CommandUsage getUsage() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @Override - public CommandType getType() { - return CommandType.UNLISTED; - } - - @Override - public void execute(CommandContext context) { - //TODO: Clean up the mess - String[] args = context.getArgs(); - context.getMessage().delete().queue(); - - if (!context.getGuildUser().getId().equals(Settings.getInstance().getCreatorId())) - return; - - if (args.length > 0) { - switch (args[0]) { - - case "message": - - if (args.length > 1) { - - OLogMessage message = DBController.get(DBMessage.class).getMessage(args[1]); - if (message != null) { - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.BLUE); - embed.setTimestamp(message.getDateSent()); - embed.setFooter("Guild : " + context.getGuild().getId() + " | ID : " + message.getMessageId(), null); - embed.setDescription( - "Message from " + message.getUserId() + " on the channel " + message.getChannelId()); - embed.addField("Message: ", "" + message.getMessage(), false); - context.reply(embed.build()); - } else { - //TODO: cached user lol xd - User user = context.getJDA().getUserById(args[1]); - if (user != null) { - List<OLogMessage> messages = DBController.get(DBMessage.class) - .getMessagesFromUser(user.getName(), context.getGuild().getName(), 10); - EmbedBuilder embed = new EmbedBuilder(); - embed.setColor(Color.BLUE); - embed.setTimestamp(OffsetDateTime.now()); - for (OLogMessage message1 : messages) { - embed.addField( - "Message in channel \"" + message1.getChannelId() + "\" sent on " - + message1.getDateSent(), - "" + message1.getMessage(), false); - } - embed.setFooter("Guild : " + context.getGuild().getName(), null); - - context.replyPrivate(embed.build()); - } - } - - } - - break; - } - } - } - -} diff --git a/src/main/java/netneutrality/command/specific/LoggingCommand.java b/src/main/java/netneutrality/command/specific/LoggingCommand.java deleted file mode 100644 index 5d11f47..0000000 --- a/src/main/java/netneutrality/command/specific/LoggingCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package netneutrality.command.specific; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; - -public class LoggingCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return false; - } - - @Override - public String getCommandName() { - return "logging"; - } - - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @Override - public CommandType getType() { - return CommandType.UNLISTED; - } - - @Override - public void execute(CommandContext context) { - - } -} From 63556d608150928ac971eec485eebb813af75409 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sun, 18 Sep 2022 20:04:57 -0400 Subject: [PATCH 098/155] Implement slash commands Update JDA to 5.0.0-alpha.18 Simplify commands by removing aliases and usage Remove prefix config option Separate skip and voteskip commands Add new shuffle command Remove duplicate crypto commands --- pom.xml | 4 +- .../java/netneutrality/NetNeutrality.java | 16 +- .../command/AbstractCommand.java | 21 +- .../command/AbstractMusicCommand.java | 15 +- .../netneutrality/command/CommandUsage.java | 103 -------- .../java/netneutrality/command/ICommand.java | 48 ++-- .../netneutrality/command/Visibility.java | 30 --- .../command/admin/BlacklistCommand.java | 111 +++++++++ .../command/admin/PurgeCommand.java | 95 ++++++++ .../command/basic/HelpCommand.java | 59 ++--- .../command/basic/PingCommand.java | 32 ++- .../command/bot/ConfigureCommand.java | 170 ++++++++----- .../command/crypto/BitcoinPriceCommand.java | 101 -------- .../command/crypto/CryptoPriceCommand.java | 75 ++++-- .../command/crypto/EthereumPriceCommand.java | 101 -------- .../command/crypto/LitecoinPriceCommand.java | 101 -------- .../command/message/BlacklistCommand.java | 93 -------- .../command/message/PruneCommand.java | 62 ----- .../command/music/BitconnectCommand.java | 35 +-- ...eueCommand.java => ClearQueueCommand.java} | 50 ++-- .../music/CurrentlyPlayingCommand.java | 38 +-- .../command/music/JoinCommand.java | 54 +++-- .../command/music/LeaveCommand.java | 34 ++- .../command/music/PlayCommand.java | 39 +-- .../command/music/QueueCommand.java | 180 ++++++++++++++ .../command/music/ShuffleCommand.java | 45 ++++ .../command/music/SkipCommand.java | 56 +++-- .../command/music/StopCommand.java | 33 ++- .../command/music/ViewQueueCommand.java | 40 ++-- .../command/music/VolumeCommand.java | 37 ++- .../command/music/VoteSkipCommand.java | 37 +-- .../netneutrality/core/CommandManager.java | 35 ++- .../java/netneutrality/core/GuildManager.java | 9 - .../java/netneutrality/core/LogHandler.java | 12 - .../core/context/CommandContext.java | 222 ++--------------- .../core/context/MessageCommandContext.java | 225 ++++++++++++++++++ .../core/context/SlashCommandContext.java | 203 ++++++++++++++++ src/main/java/netneutrality/db/GSettings.java | 8 +- .../db/controllers/DBBlacklist.java | 5 +- .../exceptions/CommandErrorException.java | 27 --- .../hooks/message/ReactionHandler.java | 32 --- .../ratelimiter/IMessageRateLimiter.java | 16 -- .../ratelimiter/MessageRateLimiterImpl.java | 47 ---- .../hooks/SlashCommandHooks.java | 23 ++ .../hooks/guilds/ServerJoinHandler.java | 2 +- .../hooks/message/EditHandler.java | 2 +- .../hooks/message/MessageReceivedHandler.java | 27 ++- .../hooks/message/ReactionHandler.java | 32 +++ .../hooks/voice/VoiceEventHandler.java | 2 +- .../netneutrality/http/server/WebApi.java | 1 - .../netneutrality/music/MusicManager.java | 51 ++-- .../netneutrality/music/QueueManager.java | 88 ++++++- .../music/TrackLoadingHandler.java | 15 +- .../netneutrality/music/TrackScheduler.java | 8 +- .../MusicPlayerAutoDisconnectThread.java | 4 +- .../netneutrality/utils/ChannelFunction.java | 95 -------- .../utils/ChannelMessagePurger.java | 171 +++++++++++++ .../netneutrality/utils/MessageFunction.java | 81 +++---- .../java/netneutrality/utils/MusicUtils.java | 5 +- 59 files changed, 1835 insertions(+), 1528 deletions(-) delete mode 100644 src/main/java/netneutrality/command/CommandUsage.java delete mode 100644 src/main/java/netneutrality/command/Visibility.java create mode 100644 src/main/java/netneutrality/command/admin/BlacklistCommand.java create mode 100644 src/main/java/netneutrality/command/admin/PurgeCommand.java delete mode 100644 src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java delete mode 100644 src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java delete mode 100644 src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java delete mode 100644 src/main/java/netneutrality/command/message/BlacklistCommand.java delete mode 100644 src/main/java/netneutrality/command/message/PruneCommand.java rename src/main/java/netneutrality/command/music/{DeleteQueueCommand.java => ClearQueueCommand.java} (67%) create mode 100644 src/main/java/netneutrality/command/music/QueueCommand.java create mode 100644 src/main/java/netneutrality/command/music/ShuffleCommand.java create mode 100644 src/main/java/netneutrality/core/context/MessageCommandContext.java create mode 100644 src/main/java/netneutrality/core/context/SlashCommandContext.java delete mode 100644 src/main/java/netneutrality/exceptions/CommandErrorException.java delete mode 100644 src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java delete mode 100644 src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java delete mode 100644 src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java create mode 100644 src/main/java/netneutrality/hooks/SlashCommandHooks.java rename src/main/java/netneutrality/{handler => }/hooks/guilds/ServerJoinHandler.java (93%) rename src/main/java/netneutrality/{handler => }/hooks/message/EditHandler.java (97%) rename src/main/java/netneutrality/{handler => }/hooks/message/MessageReceivedHandler.java (65%) create mode 100644 src/main/java/netneutrality/hooks/message/ReactionHandler.java rename src/main/java/netneutrality/{handler => }/hooks/voice/VoiceEventHandler.java (95%) delete mode 100644 src/main/java/netneutrality/utils/ChannelFunction.java create mode 100644 src/main/java/netneutrality/utils/ChannelMessagePurger.java diff --git a/pom.xml b/pom.xml index 1450722..4dd727e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ <groupId>com.xtremcommunity.discord</groupId> <artifactId>netneutrality</artifactId> - <version>1.0.0</version> + <version>2.0.0</version> <name>netneutrality-discord-bot</name> <description>Discord bot</description> <packaging>jar</packaging> @@ -108,7 +108,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>4.4.0_350</version> + <version>5.0.0-alpha.18</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 80e804d..95acf1e 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -9,9 +9,10 @@ import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.core.CommandManager; import netneutrality.core.LogHandler; import netneutrality.db.DBController; -import netneutrality.handler.hooks.guilds.ServerJoinHandler; -import netneutrality.handler.hooks.message.EditHandler; -import netneutrality.handler.hooks.message.MessageReceivedHandler; +import netneutrality.hooks.SlashCommandHooks; +import netneutrality.hooks.guilds.ServerJoinHandler; +import netneutrality.hooks.message.EditHandler; +import netneutrality.hooks.message.MessageReceivedHandler; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; import netneutrality.thread.BaseThreadFactory; @@ -37,8 +38,9 @@ public class NetNeutrality { options.setDsn(sentryDsn); options.setEnvironment(env); options.setTracesSampleRate(1.0); - options.setDebug(env.equals("dev")); - options.setRelease("netneutrality@2.0.0-alpha"); + //options.setDebug(env.equals("dev")); + options.setDebug(false); + options.setRelease("netneutrality@2.0.0"); }); if ("dev".equals(env)) { @@ -50,6 +52,7 @@ public class NetNeutrality { CommandManager.init(); MusicManager.initPlayerManager(); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); + jda.addEventListener(new SlashCommandHooks()); new WebApi(Integer.parseInt(Settings.getInstance().get("API_PORT", "9000"))); jda.getPresence().setActivity(Activity.watching("you")); @@ -58,11 +61,10 @@ public class NetNeutrality { } public static void initJDA() { - // When upgrading JDA -> GatewayIntent.MESSAGE_CONTENT try { jda = JDABuilder .createDefault(Settings.getInstance().get("BOT_TOKEN")) - .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) + .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES, GatewayIntent.MESSAGE_CONTENT) .setActivity(Activity.watching("me load...")) .build(); jda.awaitReady(); diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 252a597..68575d2 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -2,17 +2,34 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import netneutrality.core.context.MessageCommandContext; public abstract class AbstractCommand implements ICommand { + @Override + public boolean isSlashCommand() { + return true; + } + + @Override + public DefaultMemberPermissions getSlashCommandPermission() { + return DefaultMemberPermissions.ENABLED; + } + @Override public boolean canBeExecutedBy(Guild guild, Member member) { return true; } @Override - public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { + public boolean canBeExecutedFrom(Guild guild, MessageChannel channel) { return true; } + + @Override + public void execute(MessageCommandContext context) { + // Prefer slash commands + } } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 44bbf20..61ec61a 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -6,10 +6,7 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import netneutrality.core.GuildManager; import netneutrality.db.GSettings; import netneutrality.utils.UserFunction; @@ -21,6 +18,11 @@ public abstract class AbstractMusicCommand extends AbstractCommand { return false; } + @Override + public boolean isGuildOnly() { + return true; + } + @Override public CommandType getType() { return CommandType.MUSIC; @@ -49,7 +51,10 @@ public abstract class AbstractMusicCommand extends AbstractCommand { } @Override - public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { + public boolean canBeExecutedFrom(Guild guild, MessageChannel channel) { + if (channel.getType() != ChannelType.TEXT) + return false; + String channelDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_CHANNEL); if (channelDb != null && !channelDb.isEmpty()) { diff --git a/src/main/java/netneutrality/command/CommandUsage.java b/src/main/java/netneutrality/command/CommandUsage.java deleted file mode 100644 index b5b82dc..0000000 --- a/src/main/java/netneutrality/command/CommandUsage.java +++ /dev/null @@ -1,103 +0,0 @@ -package netneutrality.command; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public class CommandUsage { - - public static class Argument { - public enum Type { - OPTIONAL, REQUIRED - } - - private final Type type; - private final String[] values; - private final String description; - - public Argument(Type t, String[] values, String desc) { - if (t == Type.REQUIRED && (values == null || values.length == 0)) - throw new IllegalArgumentException("Command usage: values can't be null if type is required"); - - if (t == Type.OPTIONAL && (desc == null || desc.isEmpty())) - throw new IllegalArgumentException("Command usage: description can't be null if type is optional"); - - this.type = t; - this.values = values; - this.description = desc; - } - - public String[] getValues() { - return values; - } - - public String getDescription() { - return description; - } - - public Type getType() { - return type; - } - } - - private final AbstractCommand command; - private final Set<Argument> args = new HashSet<>(); - - public CommandUsage(AbstractCommand command, Argument... arguments) { - this.command = command; - Collections.addAll(args, arguments); - } - - public CommandUsage addArgument(Argument argument) { - args.add(argument); - return this; - } - - public static CommandUsage create(AbstractCommand command, Argument... arguments) { - return new CommandUsage(command, arguments); - } - - public AbstractCommand getCommand() { - return command; - } - - public int getRequiredArguments() { - return args.size(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Available arguments: ").append(args.size()).append("\n"); - sb.append(command.getCommandName()).append(" "); - for (Argument arg : args) { - sb.append("<"); - if (arg.getType() == Argument.Type.OPTIONAL) { - sb.append("optional: "); - - if (arg.getValues() != null || arg.getValues().length != 0) - sb.append(Arrays.toString(arg.getValues())).append(": "); - - sb.append(arg.getDescription()); - } - - if (arg.getType() == Argument.Type.REQUIRED) { - sb.append("required: ").append(Arrays.toString(arg.getValues())); - - if (arg.getDescription() != null && !arg.getDescription().isEmpty()) - sb.append(": ").append(arg.getDescription()); - } - - sb.append("> "); - } - - return sb.toString(); - } -} diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 91fed50..bb8b86c 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -8,51 +8,37 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandErrorException; -import netneutrality.exceptions.CommandExecutionException; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; public interface ICommand { - /** - * @return if the command needs administrator privilege - */ boolean needAdmin(); - /** - * @return if the command should be loaded at runtime - */ boolean isEnabled(); - /** - * The command name that a user will write in a channel - * - * @return the name of the command. - */ + boolean isGuildOnly(); + + boolean isSlashCommand(); + String getCommandName(); - /** - * @return all the aliases the command has - */ - String[] getAlias(); - - CommandUsage getUsage(); - String getDescription(); + DefaultMemberPermissions getSlashCommandPermission(); + + void registerSlashCommandOptions(SlashCommandData data); + CommandType getType(); boolean canBeExecutedBy(Guild guild, Member member); - boolean canBeExecutedFrom(Guild guild, TextChannel channel); + boolean canBeExecutedFrom(Guild guild, MessageChannel channel); - /** - * Command is executed with this function. - * - * @param context The context for the command - * @throws CommandErrorException Used to reply with a message in the text channel where the command was executed - * @throws CommandExecutionException Logs the error internally, without sending a message - */ - void execute(CommandContext context) throws CommandErrorException, CommandExecutionException; + void execute(MessageCommandContext context); + + void execute(SlashCommandContext context); } diff --git a/src/main/java/netneutrality/command/Visibility.java b/src/main/java/netneutrality/command/Visibility.java deleted file mode 100644 index 71b7d73..0000000 --- a/src/main/java/netneutrality/command/Visibility.java +++ /dev/null @@ -1,30 +0,0 @@ -package netneutrality.command; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.MessageChannel; -import net.dv8tion.jda.api.entities.PrivateChannel; -import net.dv8tion.jda.api.entities.TextChannel; - -public enum Visibility { - - PRIVATE, CHANNEL, BOTH; - - public static boolean check(MessageChannel channel, Visibility v) { - if (v == BOTH && (channel instanceof TextChannel || channel instanceof PrivateChannel)) - return true; - - if (v == PRIVATE && channel instanceof PrivateChannel) - return true; - - if (v == CHANNEL && channel instanceof TextChannel) - return true; - - return false; - } -} diff --git a/src/main/java/netneutrality/command/admin/BlacklistCommand.java b/src/main/java/netneutrality/command/admin/BlacklistCommand.java new file mode 100644 index 0000000..6762834 --- /dev/null +++ b/src/main/java/netneutrality/command/admin/BlacklistCommand.java @@ -0,0 +1,111 @@ +package netneutrality.command.admin; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; +import netneutrality.core.LogHandler; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; +import netneutrality.db.DBController; +import netneutrality.db.controllers.DBBlacklist; +import netneutrality.db.entities.OBlacklist; + +import java.util.ArrayList; + +public class BlacklistCommand extends AbstractCommand { + + @Override + public boolean needAdmin() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public boolean isGuildOnly() { + return true; + } + + @Override + public String getCommandName() { + return "blacklist"; + } + + @Override + public String getDescription() { + return "Manages the blacklist of your server."; + } + + @Override + public DefaultMemberPermissions getSlashCommandPermission() { + return DefaultMemberPermissions.DISABLED; + } + + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + data.addSubcommands( + new SubcommandData("get", "Get all blacklisted words for this guild"), + new SubcommandData("add", "Add a word to the blacklist") + .addOption(OptionType.STRING, "word", "Word to add"), + new SubcommandData("remove", "Remove a word from the blacklist") + .addOption(OptionType.STRING, "word", "Word to remove") + ); + } + + @Override + public CommandType getType() { + return CommandType.ADMINISTRATION; + } + + @Override + public void execute(MessageCommandContext context) { + + } + + @Override + public void execute(SlashCommandContext context) { + String sub = context.getEvent().getCommandPath().split("/")[1]; + DBBlacklist controller = DBController.get(DBBlacklist.class); + String word = context.getEvent().getOption("word", "", OptionMapping::getAsString); + context.ackAndWait(true); + + switch (sub) { + case "get" -> { + + context.getHook().editOriginal("Retrieving list, please wait...").queue(t -> { + ArrayList<OBlacklist> blacklists = new ArrayList<>(); + try { + blacklists = controller.getBlacklistForGuild(context.getGuild()); + } catch (Exception e) { + LogHandler.log(e); + } + + StringBuilder sb = new StringBuilder(); + for (OBlacklist bl : blacklists) { + sb.append(bl.getWord()).append(" -> ").append(bl.getEnabled() ? "enabled" : "disabled").append("\n"); + } + + t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (blacklists.isEmpty() ? "No word found" : sb.toString())).queue(); + + }); + } + case "add" -> controller.add(word, context); + case "remove" -> controller.delete(word, context); + case "disable" -> controller.disable(word, context); + case "enable" -> controller.enable(word, context); + } + } +} diff --git a/src/main/java/netneutrality/command/admin/PurgeCommand.java b/src/main/java/netneutrality/command/admin/PurgeCommand.java new file mode 100644 index 0000000..a4ddd6d --- /dev/null +++ b/src/main/java/netneutrality/command/admin/PurgeCommand.java @@ -0,0 +1,95 @@ +package netneutrality.command.admin; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.GuildMessageChannel; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandType; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; +import netneutrality.utils.ChannelMessagePurger; + +public class PurgeCommand extends AbstractCommand { + + @Override + public boolean needAdmin() { + return true; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public boolean isGuildOnly() { + return true; + } + + @Override + public String getCommandName() { + return "purge"; + } + + @Override + public String getDescription() { + return "Delete messages from the channel you are currently on"; + } + + @Override + public DefaultMemberPermissions getSlashCommandPermission() { + return DefaultMemberPermissions.DISABLED; + } + + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + + data.addOptions( + new OptionData(OptionType.INTEGER, "to-purge", "Number of messages to delete (max 2500)", true) + .setRequiredRange(1, 2500)); + } + + @Override + public CommandType getType() { + return CommandType.ADMINISTRATION; + } + + @Override + public void execute(MessageCommandContext context) { + if (context.getArgs().length == 1) { + GuildMessageChannel messageChannel = context.getEvent().getGuildChannel(); + ChannelMessagePurger channelMessagePurger = ChannelMessagePurger.getPurger(messageChannel); + channelMessagePurger.purgeMessages(context, Integer.parseInt(context.getArgument(0))); + } else { + context.getChannel().sendMessage("Failed to delete messages!").queue(); + } + } + + @Override + public void execute(SlashCommandContext context) { + int toDelete = context.getEvent().getOption("to-purge", 0, OptionMapping::getAsInt); + context.ackAndWait(true); + + if (toDelete > 0) { + GuildMessageChannel messageChannel = context.getEvent().getGuildChannel(); + ChannelMessagePurger channelMessagePurger = ChannelMessagePurger.getPurger(messageChannel); + boolean lock = channelMessagePurger.canLockBeAcquired(); + channelMessagePurger.purgeMessages(context, toDelete); + + context.replyEphemeral("Processing purge command.. This can take some time."); + + if (!lock) { + context.replyEphemeral("Another purge is currently in progress on this channel, please wait before purging again"); + } + } + } +} diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 94e9e2f..8ec34f4 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -6,15 +6,14 @@ package netneutrality.command.basic; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.CommandManager; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.utils.MessageFunction; -import netneutrality.utils.UserFunction; import java.util.List; @@ -30,59 +29,47 @@ public class HelpCommand extends AbstractCommand { return true; } + @Override + public boolean isGuildOnly() { + return false; + } + @Override public String getCommandName() { return "help"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"command"}, "Name of command to get help with") - ); - } - @Override public String getDescription() { return "Get every command with its usage"; } + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + + } + @Override public CommandType getType() { return CommandType.UTILITY; } @Override - public void execute(CommandContext context) { + public void execute(MessageCommandContext context) { if (context.getArgs().length == 0) { - List<MessageEmbed> help = MessageFunction.buildHelpMessage(CommandManager.commands, UserFunction.isAdmin(context.getGuildUser())); + List<MessageEmbed> help = MessageFunction.buildHelpMessage(context.getGuildUser()); - context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); + context.reply(new MessageCreateBuilder().addContent(context.getDiscordUser().getAsMention()).addContent(" help has been sent your way!").build()); context.replyPrivate(help); } - if (context.getArgs().length == 1) { - String cmd = context.getArgument(0); - - if (CommandManager.commands.containsKey(cmd) || CommandManager.commandsAlias.containsKey(cmd)) { - AbstractCommand c = CommandManager.commands.containsKey(cmd) ? CommandManager.commands.get(cmd) : CommandManager.commandsAlias.get(cmd); - - if (c.needAdmin() && !UserFunction.isAdmin(context.getGuildUser())) { - context.replyPrivate("Command [" + c.getCommandName() + "] requires admin privileges"); - } - - MessageEmbed help = MessageFunction.buildHelpMessage(c); - context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); - context.replyPrivate(help); - } - } - + } + @Override + public void execute(SlashCommandContext context) { + List<MessageEmbed> help = MessageFunction.buildHelpMessage(context.getGuildUser()); + context.replyEphemeral("Help has been sent in DM!"); + context.sendMessageInPrivate(help); } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 6551022..8a943a9 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -6,10 +6,11 @@ package netneutrality.command.basic; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; public class PingCommand extends AbstractCommand { @@ -23,35 +24,40 @@ public class PingCommand extends AbstractCommand { return true; } + @Override + public boolean isGuildOnly() { + return false; + } + @Override public String getCommandName() { return "ping"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { return "Pong!"; } + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + + } + @Override public CommandType getType() { return CommandType.UTILITY; } @Override - public void execute(CommandContext context) { + public void execute(MessageCommandContext context) { if (context.getArgs().length == 0) context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); } + @Override + public void execute(SlashCommandContext context) { + context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); + } + } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index a038154..42b1cc8 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -8,18 +8,27 @@ package netneutrality.command.bot; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; import netneutrality.core.GuildManager; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.db.GSettings; import netneutrality.music.MusicManager; -import java.util.Arrays; import java.util.List; +import java.util.Map; public class ConfigureCommand extends AbstractCommand { + @Override public boolean needAdmin() { return true; @@ -30,21 +39,14 @@ public class ConfigureCommand extends AbstractCommand { return true; } + @Override + public boolean isGuildOnly() { + return true; + } + @Override public String getCommandName() { - return "configure"; - } - - @Override - public String[] getAlias() { - return new String[]{"conf"}; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"music-role", "music-channel", "music-volume", "music-topic", "debug"}, "") - ); + return "config"; } @Override @@ -52,13 +54,33 @@ public class ConfigureCommand extends AbstractCommand { return "Used to configure the bot on this server"; } + @Override + public DefaultMemberPermissions getSlashCommandPermission() { + return DefaultMemberPermissions.DISABLED; + } + + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + data.addSubcommands( + new SubcommandData("music-volume", "Volume for the music player") + .addOptions(new OptionData(OptionType.INTEGER, "volume", "Integer between 0 and 100", true) + .setRequiredRange(0, 100)), + new SubcommandData("error-logging", "Send errors to #error and/or #log channel") + .addOption(OptionType.BOOLEAN, "debug", "Enable or disable the fonctionnality", true), + new SubcommandData("music-role", "Role needed to use music commands") + .addOption(OptionType.ROLE, "role", "Name of role", true), + new SubcommandData("music-channel", "Only allow music commands on this channel") + .addOption(OptionType.CHANNEL, "channel", "Leave empty to allow everywhere") + ); + } + @Override public CommandType getType() { return CommandType.ADMINISTRATION; } @Override - public void execute(CommandContext context) { + public void execute(MessageCommandContext context) { String[] args = context.getArgs(); GuildManager guildManager = GuildManager.getManager(context.getGuild()); @@ -86,7 +108,7 @@ public class ConfigureCommand extends AbstractCommand { context.reply("Successful reset of the role"); } - List<Role> roles = context.getMessage().getMentionedRoles(); + List<Role> roles = context.getMessage().getMentions().getRoles(); if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { @@ -119,7 +141,7 @@ public class ConfigureCommand extends AbstractCommand { context.reply("Successful reset of the channel"); } - List<TextChannel> channels = context.getMessage().getMentionedChannels(); + List<TextChannel> channels = context.getMessage().getMentions().getChannels(TextChannel.class); if (channels.size() == 1) { TextChannel channel = channels.get(0); if (channel.getGuild().getId().equals(context.getGuild().getId())) { @@ -157,28 +179,6 @@ public class ConfigureCommand extends AbstractCommand { } } - // Music topic change - if (context.getArgument(0).equals("music-topic")) { - if (args.length == 1) { - boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC)); - - context.reply("Set currently playing track in text channel topic: %s", (enabled ? "enabled" : "disabled")); - context.reply("Use 'conf music-topic 0/1' to toggle between states (0 = disabled, 1 = enabled)."); - } - - if (args.length == 2) { - String str = args[1]; - boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC)); - if (str.equals("0") || str.equals("1")) { - guildManager.setSettingValue(GSettings.MUSIC_TOPIC, str); - enabled = "1".equals(str); - } - - context.reply("Set currently playing track in text channel topic is now %s for this guild", (enabled ? "enabled" : "disabled")); - - } - } - // Debug if (context.getArgument(0).equals("debug")) { if (args.length == 1) { @@ -204,34 +204,84 @@ public class ConfigureCommand extends AbstractCommand { } } + } + } - // Prefix - if (context.getArgument(0).equals("prefix")) { - String allowedPrefixes = "!$%?&*"; + @Override + public void execute(SlashCommandContext context) { + String sub = context.getEvent().getCommandPath().split("/")[1]; + GuildManager guildManager = GuildManager.getManager(context.getGuild()); + context.ackAndWait(true); - if (args.length == 1) { - String prefix = guildManager.getSetting(GSettings.PREFIX); + if ("music-role".equals(sub)) { + Role role = context.getEvent().getOption("role", OptionMapping::getAsRole); + assert role != null; - context.reply("Current prefix for commands: '%s'", prefix); - context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray())); + if (role.getPosition() == -1) { + guildManager.setSettingValue(GSettings.MUSIC_ROLE, null); + context.replyEphemeral("Everyone can now use music commands"); + return; + } - } + if (role.getGuild().getId().equals(context.getGuild().getId())) { + guildManager.setSettingValue(GSettings.MUSIC_ROLE, role.getId()); + context.replyEphemeral("Successfully set %s as the role needed for music command", role.getAsMention()); + return; + } + } - if (args.length == 2) { - String prefix = args[1].trim(); + if ("music-channel".equals(sub)) { + GuildChannelUnion channel = context.getEvent().getOption("channel", OptionMapping::getAsChannel); - if (prefix.length() == 1 && allowedPrefixes.contains(prefix)) { - guildManager.setSettingValue(GSettings.PREFIX, prefix); - - context.reply("Prefix for commands is now '%s'", prefix); - } else { - context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray())); - } + if (channel == null) { + guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, null); + context.replyEphemeral("No channel restrictions for music commands"); + return; + } + if (channel instanceof TextChannel) { + if (channel.getGuild().getId().equals(context.getGuild().getId())) { + guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); + context.replyEphemeral("Successfully set %s as the channel required to execute music command", channel.getAsMention()); + return; } } - } else { - context.reply(getUsage()); + + } + + if ("music-volume".equals(sub)) { + int volume = context.getEvent().getOption("volume", 30, OptionMapping::getAsInt); + guildManager.setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); + MusicManager.get(context.getGuild()).setVolume(volume); + + context.replyEphemeral("Default volume for music player is now %d", volume); + return; + } + + if ("debug".equals(sub)) { + boolean debug = context.getEvent().getOption("debug", true, OptionMapping::getAsBoolean); + + guildManager.setDebug(debug); + context.reply("Error logging is now %s for this guild", (debug ? "enabled" : "disabled")); + return; + } + + if ("show-all".equals(sub)) { + Map<String, String> settings = guildManager.getSettings(); + MessageCreateBuilder builder = new MessageCreateBuilder(); + + for (GSettings o : GSettings.values()) { + String value = o.getDefaultValue(); + + if (settings.containsKey(o.getName())) { + value = settings.get(o.getName()); + } + + builder.addContent(o.getName()).addContent(": ").addContent(value); + builder.addContent("\n"); + } + + context.replyEphemeral(builder.build()); } } } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java deleted file mode 100644 index c30adaf..0000000 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ /dev/null @@ -1,101 +0,0 @@ -package netneutrality.command.crypto; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.http.WebModule; -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.NumberFormat; -import java.util.Currency; -import java.util.Locale; - -public class BitcoinPriceCommand extends AbstractCommand { - - private final String baseURL = "https://min-api.cryptocompare.com/data/price"; - private final String crypto = "BTC"; - - @Override - public boolean needAdmin() { - return false; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "bitcoin"; - } - - @Override - public String[] getAlias() { - return new String[]{"btc"}; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") - ); - } - - @Override - public String getDescription() { - return "Get the price of bitcoin"; - } - - @Override - public CommandType getType() { - return CommandType.CRYPTO; - } - - @Override - public void execute(CommandContext context) { - String[] args = context.getArgs(); - String currency = "USD"; - - if (args.length == 1) { - try { - currency = Currency.getInstance(args[0].toUpperCase()).getCurrencyCode(); - } catch (IllegalArgumentException exception) { - context.reply("Please enter a valid currency"); - return; - } - } - - String finalCurrency = currency; - context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price; - Locale usa = new Locale("en", "US"); - NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); - dollarFormat.setMaximumFractionDigits(24); - - try { - WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - JSONObject json = http.getAsObject(); - if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { - t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); - return; - } - - price = dollarFormat.format(json.getDouble(finalCurrency)); - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (JSONException | IllegalArgumentException | ArithmeticException e) { - t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - LogHandler.log(e); - } - }); - } -} diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index bce1e27..ffa0098 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -6,11 +6,14 @@ package netneutrality.command.crypto; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; @@ -33,36 +36,34 @@ public class CryptoPriceCommand extends AbstractCommand { return true; } + @Override + public boolean isGuildOnly() { + return false; + } + @Override public String getCommandName() { return "crypto"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"crypto"}, "Symbol of crypto"), - new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") - ); - } - @Override public String getDescription() { return "Get the price of cryptocurrencies"; } + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + data.addOption(OptionType.STRING, "symbol", "The crypto symbol to fetch price for", true); + data.addOption(OptionType.STRING, "currency", "In which currency should the price be displayed"); + } + @Override public CommandType getType() { return CommandType.CRYPTO; } @Override - public void execute(CommandContext context) { + public void execute(MessageCommandContext context) { String[] args = context.getArgs(); String currency = "USD"; @@ -102,4 +103,46 @@ public class CryptoPriceCommand extends AbstractCommand { }); } } + + @Override + public void execute(SlashCommandContext context) { + Locale usa = new Locale("en", "US"); + NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); + dollarFormat.setMaximumFractionDigits(24); + + String symbol = context.getEvent().getOption("symbol", OptionMapping::getAsString); + String currency = context.getEvent().getOption("currency", "USD", OptionMapping::getAsString); + + try { + currency = Currency.getInstance(currency).getCurrencyCode(); + } catch (IllegalArgumentException exception) { + context.reply("Please enter a valid currency"); + return; + } + + String finalCurrency = currency.toUpperCase(); + context.getEvent().deferReply().queue(interactionHook -> { + try { + + WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, symbol, finalCurrency)).request(); + JSONObject json = http.getAsObject(); + + if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { + interactionHook.editOriginal("Crypto doesn't exist.. yet").queue(); + return; + } + + double value = json.getDouble(finalCurrency); + String price = dollarFormat.format(value); + + interactionHook.editOriginal(String.format("The current price of %s in %s is %s", symbol, finalCurrency, price)).queue(); + + } catch (JSONException | IllegalArgumentException | ArithmeticException e) { + interactionHook.editOriginal(String.format("Error getting price of %s!", symbol)).queue(); + LogHandler.log(e); + } + + + }); + } } diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java deleted file mode 100644 index a29ccf8..0000000 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ /dev/null @@ -1,101 +0,0 @@ -package netneutrality.command.crypto; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.http.WebModule; -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.NumberFormat; -import java.util.Currency; -import java.util.Locale; - -public class EthereumPriceCommand extends AbstractCommand { - - private final String baseURL = "https://min-api.cryptocompare.com/data/price"; - private final String crypto = "ETH"; - - @Override - public boolean needAdmin() { - return false; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "ethereum"; - } - - @Override - public String[] getAlias() { - return new String[]{"eth"}; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") - ); - } - - @Override - public String getDescription() { - return "Get the ethereum price"; - } - - @Override - public CommandType getType() { - return CommandType.CRYPTO; - } - - @Override - public void execute(CommandContext context) { - String[] args = context.getArgs(); - String currency = "USD"; - - if (args.length == 1) { - try { - currency = Currency.getInstance(args[0].toUpperCase()).getCurrencyCode(); - } catch (IllegalArgumentException exception) { - context.reply("Please enter a valid currency"); - return; - } - } - - String finalCurrency = currency; - context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price; - Locale usa = new Locale("en", "US"); - NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); - dollarFormat.setMaximumFractionDigits(24); - - try { - WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - JSONObject json = http.getAsObject(); - if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { - t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); - return; - } - - price = dollarFormat.format(json.getDouble(finalCurrency)); - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (JSONException | IllegalArgumentException e) { - t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - LogHandler.log(e); - } - }); - } -} diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java deleted file mode 100644 index c782d67..0000000 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ /dev/null @@ -1,101 +0,0 @@ -package netneutrality.command.crypto; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.http.WebModule; -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.NumberFormat; -import java.util.Currency; -import java.util.Locale; - -public class LitecoinPriceCommand extends AbstractCommand { - - private final String baseURL = "https://min-api.cryptocompare.com/data/price"; - private final String crypto = "LTC"; - - @Override - public boolean needAdmin() { - return false; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "litecoin"; - } - - @Override - public String[] getAlias() { - return new String[]{"ltc"}; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"currency"}, "defaults to USD") - ); - } - - @Override - public String getDescription() { - return "Get the litecoin price"; - } - - @Override - public CommandType getType() { - return CommandType.CRYPTO; - } - - @Override - public void execute(CommandContext context) { - String[] args = context.getArgs(); - String currency = "USD"; - - if (args.length == 1) { - try { - currency = Currency.getInstance(args[0].toUpperCase()).getCurrencyCode(); - } catch (IllegalArgumentException exception) { - context.reply("Please enter a valid currency"); - return; - } - } - - String finalCurrency = currency; - context.getChannel().sendMessage("Retreiving price, please wait...").queue(t -> { - String price; - Locale usa = new Locale("en", "US"); - NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); - dollarFormat.setMaximumFractionDigits(24); - - try { - WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); - JSONObject json = http.getAsObject(); - if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) { - t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); - return; - } - - price = dollarFormat.format(json.getDouble(finalCurrency)); - t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); - } catch (JSONException | IllegalArgumentException | ArithmeticException e) { - t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); - LogHandler.log(e); - } - }); - } -} diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java deleted file mode 100644 index d442c2e..0000000 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ /dev/null @@ -1,93 +0,0 @@ -package netneutrality.command.message; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBBlacklist; -import netneutrality.db.entities.OBlacklist; - -import java.util.ArrayList; - -public class BlacklistCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "blacklist"; - } - - @Override - public String[] getAlias() { - return new String[]{"bl"}; - } - - @Override - public CommandUsage getUsage() { - return null; - } - - @Override - public String getDescription() { - return "Manages the blacklist of your server."; - } - - @Override - public CommandType getType() { - return CommandType.ADMINISTRATION; - } - - @Override - public void execute(CommandContext context) { - String[] args = context.getArgs(); - DBBlacklist controller = DBController.get(DBBlacklist.class); - - if (args.length > 0 && args.length < 3) { - String word = (args.length == 2 ? args[1] : ""); - - switch (args[0]) { - case "get" -> { - - context.getChannel().sendMessage("Retrieving list, please wait...").queue(t -> { - ArrayList<OBlacklist> blacklists = new ArrayList<>(); - try { - blacklists = controller.getBlacklistForGuild(context); - } catch (Exception e) { - LogHandler.log(e); - } - - StringBuilder sb = new StringBuilder(); - for (OBlacklist bl : blacklists) { - sb.append(bl.getWord()).append(" -> ").append(bl.getEnabled() ? "enabled" : "disabled").append("\n"); - } - - t.editMessage("List of blacklisted words for this server [" + context.getGuild().getName() + "] :\n" + (blacklists.isEmpty() ? "No word found" : sb.toString())).queue(); - - }); - } - case "add" -> controller.add(word, context); - case "remove" -> controller.delete(word, context); - case "disable" -> controller.disable(word, context); - case "enable" -> controller.enable(word, context); - } - } - } - -} diff --git a/src/main/java/netneutrality/command/message/PruneCommand.java b/src/main/java/netneutrality/command/message/PruneCommand.java deleted file mode 100644 index 6cc7848..0000000 --- a/src/main/java/netneutrality/command/message/PruneCommand.java +++ /dev/null @@ -1,62 +0,0 @@ -package netneutrality.command.message; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; -import netneutrality.utils.ChannelFunction; - -public class PruneCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommandName() { - return "prune"; - } - - @Override - public String[] getAlias() { - return new String[]{"purge"}; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"number"}, "Max 2499") - ); - } - - @Override - public String getDescription() { - return "Delete n messages from the channel you are currently on"; - } - - @Override - public CommandType getType() { - return CommandType.ADMINISTRATION; - } - - @Override - public void execute(CommandContext context) { - if (context.getArgs().length == 1) - ChannelFunction.bulkDeleteMessage(context.getChannel(), Integer.parseInt(context.getArgument(0))); - else - context.getChannel().sendMessage("Failed to delete messages!").queue(); - } - -} diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index c66aeba..b2e0269 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -7,10 +7,11 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandType; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; public class BitconnectCommand extends AbstractMusicCommand { @@ -25,19 +26,14 @@ public class BitconnectCommand extends AbstractMusicCommand { return "bitconnect"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { - return null; + return "Ready to invest?"; + } + + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + } @Override @@ -46,10 +42,19 @@ public class BitconnectCommand extends AbstractMusicCommand { } @Override - public void execute(CommandContext context) { + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", context, false, true); - context.getMessage().delete().queue(); + context.deleteMessage(); + } + + @Override + public void execute(SlashCommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", context, false, true); + context.reply("Ready to invest?"); } } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/ClearQueueCommand.java similarity index 67% rename from src/main/java/netneutrality/command/music/DeleteQueueCommand.java rename to src/main/java/netneutrality/command/music/ClearQueueCommand.java index a44a62a..54a1b96 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ClearQueueCommand.java @@ -7,15 +7,15 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandErrorException; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; -public class DeleteQueueCommand extends AbstractMusicCommand { +public class ClearQueueCommand extends AbstractMusicCommand { @Override public boolean needAdmin() { @@ -29,19 +29,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public String getCommandName() { - return "deletequeue"; - } - - @Override - public String[] getAlias() { - return new String[] {"delq", "delqueue", "clear"}; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, - new CommandUsage.Argument(CommandUsage.Argument.Type.OPTIONAL, new String[] {"track #", "all"}, "") - ); + return "clearqueue"; } @Override @@ -50,7 +38,12 @@ public class DeleteQueueCommand extends AbstractMusicCommand { } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) @@ -58,7 +51,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { if (context.getArgs().length == 0) { context.reply("Select the track you want to delete from the queue (track# or all)"); - context.reply(MessageFunction.buildViewQueueMessage(player, context.getGuildUser(), true)); + context.reply(MessageFunction.buildViewQueueMessage(player, true)); } if (context.getArgs().length > 0) { @@ -88,9 +81,26 @@ public class DeleteQueueCommand extends AbstractMusicCommand { } } catch (NumberFormatException e) { - throw new CommandErrorException("Please enter a number", context, e); + context.reply("Please enter a number"); } } } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (!MusicUtils.checkIfConnected(manager, context)) + return; + + int queueSize = manager.getQueueSize(); + if (queueSize > 0) { + manager.getScheduler().getQueueManager().clearQueue(); + context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); + } else { + context.reply("Queue is empty!"); + } + } } diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index 57ee083..68f4738 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -7,9 +7,10 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; @@ -23,17 +24,7 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { @Override public String getCommandName() { - return "playing"; - } - - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; + return "nowplaying"; } @Override @@ -42,14 +33,29 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + // no arguments + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(player, context) && player.isCurrentlyPlaying()) { - context.reply(MessageFunction.buildCurrentlyPlayingMessage(player, context.getGuildUser())); + context.reply(MessageFunction.buildCurrentlyPlayingMessage(player)); } else { - context.reply("Player is not playing any tracks right now"); + context.reply("Bot isn't playing any tracks right now"); } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (MusicUtils.checkIfConnected(manager, context) && manager.isCurrentlyPlaying()) { + context.reply(MessageFunction.buildCurrentlyPlayingMessage(manager)); + } + } } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index c12784e..10d044a 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -8,9 +8,10 @@ package netneutrality.command.music; */ import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; @@ -26,30 +27,25 @@ public class JoinCommand extends AbstractMusicCommand { return "join"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { - return "Make the bot join the current voice channel (if no music is playing, bot will disconnect automatically)"; + return "Make the bot join your current voice channel"; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (context.getGuildUser().getVoiceState() == null) { throw new CommandExecutionException("Voice state is null, this should not happen", context, null); } - if (!context.getGuildUser().getVoiceState().inVoiceChannel()) { + if (!context.getGuildUser().getVoiceState().inAudioChannel()) { context.reply("You are not in a voice channel"); return; } @@ -59,11 +55,37 @@ public class JoinCommand extends AbstractMusicCommand { return; } - VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); + VoiceChannel vChannel = (VoiceChannel) context.getGuildUser().getVoiceState().getChannel(); if (vChannel != null) { player.connect(vChannel); context.reply("Joining current voice channel"); } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (context.getGuildUser().getVoiceState() == null) { + throw new CommandExecutionException("Voice state is null, this should not happen", context, null); + } + + if (!context.getGuildUser().getVoiceState().inAudioChannel()) { + context.reply("You are not in a voice channel"); + return; + } + + if (player.isConnected()) { + context.reply("Player is already in a voice channel"); + return; + } + + VoiceChannel vChannel = (VoiceChannel) context.getGuildUser().getVoiceState().getChannel(); + if (vChannel != null) { + player.connect(vChannel); + context.reply("Joining current voice channel"); + } + } } diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 0b1df1f..f62e07d 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -7,13 +7,15 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; public class LeaveCommand extends AbstractMusicCommand { + @Override public boolean needAdmin() { return true; @@ -29,23 +31,18 @@ public class LeaveCommand extends AbstractMusicCommand { return "leave"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { return "Make the bot leave the voice channel"; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(player, context)) { @@ -53,4 +50,15 @@ public class LeaveCommand extends AbstractMusicCommand { context.reply("Leaving voice channel and clearing queue"); } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (MusicUtils.checkIfConnected(player, context)) { + player.leave(); + context.reply("Leaving voice channel and clearing queue"); + } + } } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 9c219ac..0ef8ec5 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -7,9 +7,12 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; public class PlayCommand extends AbstractMusicCommand { @@ -24,34 +27,32 @@ public class PlayCommand extends AbstractMusicCommand { return "play"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create( - this, - new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"url"}, "Youtube/Soundcloud link or search string") - ); - } - @Override public String getDescription() { return "Get the party going!"; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + data.addOption(OptionType.STRING, "query", "URL or search query", true); + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (context.getArgs().length > 0) { player.play(context.getMessageText(), context, false, false); - } else { - //TODO: resume queue - context.reply(getUsage()); } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + String query = context.getEvent().getOption("query", OptionMapping::getAsString); + context.ackAndWait(); + + manager.play(query, context, false, false); + } } diff --git a/src/main/java/netneutrality/command/music/QueueCommand.java b/src/main/java/netneutrality/command/music/QueueCommand.java new file mode 100644 index 0000000..5bc534c --- /dev/null +++ b/src/main/java/netneutrality/command/music/QueueCommand.java @@ -0,0 +1,180 @@ +package netneutrality.command.music; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; +import netneutrality.command.AbstractMusicCommand; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; +import netneutrality.music.MusicManager; +import netneutrality.utils.MessageFunction; +import netneutrality.utils.MusicUtils; + +public class QueueCommand extends AbstractMusicCommand { + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getCommandName() { + return "queue"; + } + + @Override + public String getDescription() { + return "Manage the music queue"; + } + + @Override + public DefaultMemberPermissions getSlashCommandPermission() { + return DefaultMemberPermissions.DISABLED; + } + + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + data.addSubcommands( + new SubcommandData("clear-all", "Clear all queued tracks"), + new SubcommandData("delete-track", "Remove a single track from the queue") + .addOptions(new OptionData(OptionType.INTEGER, "position", "Position of track", true) + .setMinValue(1)), + new SubcommandData("show-queue", "Display current queue"), + new SubcommandData("shuffle", "Shuffle the queue"), + new SubcommandData("from-user", "View tracks added by a user") + .addOption(OptionType.USER, "user", "Which user?", true), + new SubcommandData("remove-from-user", "Remove all tracks added by a user") + .addOption(OptionType.USER, "user", "Which user?", true) + ); + } + + @Override + public void execute(MessageCommandContext context) { + MusicManager player = MusicManager.get(context.getGuild()); + + if (!MusicUtils.checkIfConnected(player, context)) + return; + + if (context.getArgs().length == 0) { + context.reply("Select the track you want to delete from the queue (track# or all)"); + context.reply(MessageFunction.buildViewQueueMessage(player, true)); + } + + if (context.getArgs().length > 0) { + + int queueSize = player.getQueueSize(); + if (context.getArgument(0).equals("all")) { + + if (queueSize > 0) { + player.getScheduler().getQueueManager().clearQueue(); + context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); + } else { + context.reply("Queue is empty!"); + } + } else { + + try { + int num = Integer.parseInt(context.getArgument(0)); + + if (num > 0) { + if (player.removeFromQueue(num)) { + context.reply("Removed track #%d from the queue", num); + } else { + context.reply("Error while removing track #%d from the queue", num); + } + } else { + context.reply("Number out of range"); + } + + } catch (NumberFormatException e) { + context.reply("Please enter a number"); + } + } + } + } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + context.ackAndWait(); + String sub = context.getEvent().getCommandPath().split("/")[1]; + + if (!MusicUtils.checkIfConnected(manager, context)) { + return; + } + + switch (sub) { + case "clear-all" -> { + int queueSize = manager.getQueueSize(); + + if (queueSize > 0) { + manager.getScheduler().getQueueManager().clearQueue(); + context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); + } else { + context.reply("Queue is already empty!"); + } + } + + case "delete-track" -> { + int position = context.getEvent().getOption("position", 0, OptionMapping::getAsInt); + + if (position > 0) { + if (manager.removeFromQueue(position)) { + context.reply("Removed track #%d from the queue", position); + } else { + context.reply("Position is out of bounds"); + } + } + } + + case "show-queue" -> context.reply(MessageFunction.buildViewQueueMessage(manager, true)); + + case "shuffle" -> { + manager.getScheduler().getQueueManager().shuffle(); + context.reply("Queue is now shuffled."); + } + + case "from-user" -> { + Member user = context.getEvent().getOption("user", OptionMapping::getAsMember); + if (user == null) { + context.reply("The user isn't from this guild"); + break; + } + + context.reply(MessageFunction.buildUserTracksMessage(manager, user)); + } + + case "remove-from-user" -> { + Member member = context.getEvent().getOption("user", OptionMapping::getAsMember); + if (member == null) { + context.reply("The user isn't from this guild"); + break; + } + + int size = manager.getScheduler() + .getQueueManager() + .getQueueWithFilter(trackInfo -> member.equals(trackInfo.getRequester())) + .size(); + + if (size == 0) { + context.reply("No tracks added by user %s", member.getEffectiveName()); + } else { + manager.getScheduler().getQueueManager().removeTracksFromUser(member); + context.reply("Removed all tracks from user %s", member.getEffectiveName()); + } + } + } + + + } +} diff --git a/src/main/java/netneutrality/command/music/ShuffleCommand.java b/src/main/java/netneutrality/command/music/ShuffleCommand.java new file mode 100644 index 0000000..57e3a2a --- /dev/null +++ b/src/main/java/netneutrality/command/music/ShuffleCommand.java @@ -0,0 +1,45 @@ +package netneutrality.command.music;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import netneutrality.command.AbstractMusicCommand; +import netneutrality.core.context.SlashCommandContext; +import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; + +public class ShuffleCommand extends AbstractMusicCommand { + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getCommandName() { + return "shuffle"; + } + + @Override + public String getDescription() { + return "Shuffle the music queue"; + } + + @Override + public void registerSlashCommandOptions(SlashCommandData data) { + + } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (MusicUtils.checkIfConnected(manager, context)) { + manager.getScheduler().getQueueManager().shuffle(); + context.reply("Queue is now shuffled."); + } + } +} diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 18a6ae6..ac22c57 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -7,9 +7,13 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -26,30 +30,19 @@ public class SkipCommand extends AbstractMusicCommand { return "skip"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create( - this, - new CommandUsage.Argument( - CommandUsage.Argument.Type.OPTIONAL, - new String[]{"number"}, - "Number of tracks to skip" - ) - ); - } - @Override public String getDescription() { - return "Used to skip to the next track in the queue (if no admin privileges, vote skip instead)"; + return "Skip to the next track in the queue"; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + data.addOptions(new OptionData(OptionType.INTEGER, "skip", "Number of tracks to skip") + .setMinValue(1)); + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) @@ -59,14 +52,14 @@ public class SkipCommand extends AbstractMusicCommand { if (UserFunction.isAdmin(context.getGuildUser()) && context.getArgs().length > 0) { try { int skips = Integer.parseInt(context.getArgument(0)); - player.skip(skips); + player.getScheduler().getQueueManager().skip(skips); context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : "")); } catch (NumberFormatException e) { context.reply("Please enter how many track(s) to skip"); } } else { - player.skip(1); + player.getScheduler().getQueueManager().skip(1); context.reply("Skipping current track"); } } else { @@ -74,4 +67,21 @@ public class SkipCommand extends AbstractMusicCommand { } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + int skips = context.getEvent().getOption("skip", 0, OptionMapping::getAsInt); + context.ackAndWait(); + + if (!MusicUtils.checkIfConnected(manager, context)) { + if (skips > 0) { + context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : "")); + manager.getScheduler().getQueueManager().skip(skips); + } else { + context.reply("Skipping current track"); + manager.getScheduler().getQueueManager().skip(1); + } + } + } } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 89adceb..4d869e2 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -7,9 +7,10 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -26,23 +27,18 @@ public class StopCommand extends AbstractMusicCommand { return "stop"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { return "Stop the music player, keeping the current queue."; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) @@ -55,4 +51,15 @@ public class StopCommand extends AbstractMusicCommand { context.reply("Stopping current track"); } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (MusicUtils.checkIfConnected(manager, context)) { + manager.stopTrack(); + context.reply("Stopping music playback"); + } + } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 87acb1e..429930a 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -6,9 +6,10 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MessageFunction; import netneutrality.utils.MusicUtils; @@ -25,33 +26,44 @@ public class ViewQueueCommand extends AbstractMusicCommand { return "viewqueue"; } - @Override - public String[] getAlias() { - return new String[]{"viewq", "queue"}; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { return "Get the current queue for the music player"; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(player, context)) { int queueSize = player.getQueueSize(); if (queueSize > 0) { - context.reply(MessageFunction.buildViewQueueMessage(player, context.getGuildUser(), true)); + context.reply(MessageFunction.buildViewQueueMessage(player, true)); } else { context.reply("Queue is empty!"); } } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + context.ackAndWait(); + + if (MusicUtils.checkIfConnected(manager, context)) { + int queueSize = manager.getQueueSize(); + + if (queueSize > 0) { + context.reply(MessageFunction.buildViewQueueMessage(manager, true)); + } else { + context.reply("Queue is empty!"); + } + } + } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 4010c1a..29bd9d2 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -7,9 +7,13 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; import netneutrality.utils.UserFunction; @@ -26,23 +30,19 @@ public class VolumeCommand extends AbstractMusicCommand { return "volume"; } - @Override - public String[] getAlias() { - return new String[] { "vol" }; - } - - @Override - public CommandUsage getUsage() { - return CommandUsage.create(this, new CommandUsage.Argument(CommandUsage.Argument.Type.REQUIRED, new String[] {"0-100"}, "")); - } - @Override public String getDescription() { return "Sets the volume for the music player"; } @Override - public void execute(CommandContext context) { + public void registerSlashCommandOptions(SlashCommandData data) { + data.addOptions(new OptionData(OptionType.INTEGER, "volume", "Playback volume for this session", true) + .setRequiredRange(0, 100)); + } + + @Override + public void execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) @@ -63,4 +63,15 @@ public class VolumeCommand extends AbstractMusicCommand { } } } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + int volume = context.getEvent().getOption("volume", 30, OptionMapping::getAsInt); + + if (MusicUtils.checkIfConnected(manager, context)) { + context.reply("Volume set to %s", volume); + manager.setVolume(volume); + } + } } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index 65606b7..a27c612 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -6,9 +6,10 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -24,27 +25,31 @@ public class VoteSkipCommand extends AbstractMusicCommand { return "voteskip"; } - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public CommandUsage getUsage() { - return null; - } - @Override public String getDescription() { return "Cast a vote to skip the currently playing track"; } @Override - public void execute(CommandContext context) { - MusicManager player = MusicManager.get(context.getGuild()); + public void registerSlashCommandOptions(SlashCommandData data) { - if (MusicUtils.checkIfConnected(player, context)) { - player.voteSkip(context); + } + + @Override + public void execute(MessageCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + + if (MusicUtils.checkIfConnected(manager, context)) { + manager.voteSkip(context); + } + } + + @Override + public void execute(SlashCommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + + if (MusicUtils.checkIfConnected(manager, context)) { + manager.voteSkip(context); } } } diff --git a/src/main/java/netneutrality/core/CommandManager.java b/src/main/java/netneutrality/core/CommandManager.java index c6ee03b..5cb70f4 100644 --- a/src/main/java/netneutrality/core/CommandManager.java +++ b/src/main/java/netneutrality/core/CommandManager.java @@ -7,6 +7,11 @@ package netneutrality.core; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; +import netneutrality.NetNeutrality; import netneutrality.command.AbstractCommand; import org.reflections.Reflections; import org.slf4j.Logger; @@ -14,26 +19,27 @@ import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Set; public class CommandManager { private final static Logger logger = LoggerFactory.getLogger(CommandManager.class); public static final HashMap<String, AbstractCommand> commands = new HashMap<>(); - public static final HashMap<String, AbstractCommand> commandsAlias = new HashMap<>(); public static void init() { initCommands(); - initAlias(); + registerSlashCommands(); } public static boolean isValidCommand(String commandString) { - return commands.containsKey(commandString) || commandsAlias.containsKey(commandString); + return commands.containsKey(commandString); } public static AbstractCommand getCommand(String commandString) { - return commands.containsKey(commandString) ? commands.get(commandString) : commandsAlias.get(commandString); + return commands.get(commandString); } private static void initCommands() { @@ -65,14 +71,23 @@ public class CommandManager { logger.info("Loaded " + commands.size() + " commands!"); } - private static void initAlias() { + private static void registerSlashCommands() { + CommandListUpdateAction commandListUpdateAction = NetNeutrality.getJDA().updateCommands(); + List<CommandData> slashCommands = new ArrayList<>(); for (AbstractCommand command : commands.values()) { - for (String alias : command.getAlias()) { - if (!commandsAlias.containsKey(alias)) - commandsAlias.put(alias, command); + if (!command.isEnabled() || !command.isSlashCommand()) { + continue; } - } - } + SlashCommandData data = Commands.slash(command.getCommandName(), command.getDescription()); + data.setDefaultPermissions(command.getSlashCommandPermission()); + data.setGuildOnly(command.isGuildOnly()); + command.registerSlashCommandOptions(data); + + slashCommands.add(data); + } + + commandListUpdateAction.addCommands(slashCommands).queue(); + } } diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 63e951d..32708b4 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -17,8 +17,6 @@ import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OBlacklist; import netneutrality.db.entities.OGuild; import netneutrality.db.entities.OGuildSetting; -import netneutrality.handler.ratelimiter.IMessageRateLimiter; -import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; @@ -42,12 +40,10 @@ public class GuildManager { private final Set<String> blacklistCache = new HashSet<>(); private final Guild guild; private OGuild guildEntity; - private final IMessageRateLimiter rateLimiter; private GuildManager(Guild guild) { this.guild = guild; this.guildEntity = loadGuildFromDb(guild.getId()); - this.rateLimiter = new MessageRateLimiterImpl(); managers.put(guild.getId(), this); reloadBlacklistCache(); @@ -61,7 +57,6 @@ public class GuildManager { this.guild = temp; this.guildEntity = loadGuildFromDb(guild.getId()); - this.rateLimiter = new MessageRateLimiterImpl(); managers.put(guild.getId(), this); reloadBlacklistCache(); @@ -97,10 +92,6 @@ public class GuildManager { return guildEntity.getDebug(); } - public IMessageRateLimiter getRateLimiter() { - return rateLimiter; - } - public Guild getGuild() { return guild; } diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 2165707..3208447 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -10,7 +10,6 @@ import io.sentry.Sentry; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandErrorException; import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.utils.MessageFunction; @@ -27,12 +26,6 @@ public class LogHandler { * @param e The exceptions to log */ public static void log(Exception e) { - if (e instanceof CommandErrorException) { - sendMessageToChannel((CommandErrorException) e); - logInternally((CommandErrorException) e); - return; - } - if (e instanceof CommandExecutionException) { Sentry.captureException(e); logInternally((CommandExecutionException) e); @@ -82,9 +75,4 @@ public class LogHandler { } } } - - private static void sendMessageToChannel(CommandErrorException error) { - CommandContext context = error.getCommandContext(); - context.reply(error.getMessage()); - } } diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 40d3395..cf74a97 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -1,231 +1,51 @@ -package netneutrality.core.context; -/* +package netneutrality.core.context;/* * Copyright (c) anthorob * * https://xtremcommunity.com/ * https://discord.gg/CdFcyQ */ -import io.sentry.Breadcrumb; -import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.events.Event; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandUsage; -import netneutrality.core.GuildManager; -import netneutrality.core.LogHandler; -import netneutrality.exceptions.CommandErrorException; -import netneutrality.exceptions.CommandExecutionException; -import netneutrality.thread.ThreadManager; -import netneutrality.utils.Settings; -import netneutrality.utils.UserFunction; -import java.util.Collection; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; +public interface CommandContext { -public class CommandContext { + AbstractCommand getCommand(); - private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED); + Event getEvent(); - private AbstractCommand command; - private final Message message; - private final Guild guild; - private final TextChannel channel; - private final Member member; - private final User user; - private final JDA jda; + Guild getGuild(); - public CommandContext(Message message, Member member, User user, Guild guild, TextChannel channel, JDA jda) { - this.message = message; - this.member = member; - this.guild = guild; - this.channel = channel; - this.user = user; - this.jda = jda; + MessageChannel getChannel(); - io.sentry.protocol.User sentryUser = new io.sentry.protocol.User(); - sentryUser.setId(member.getId()); - sentryUser.setUsername(member.getEffectiveName()); - Sentry.setUser(sentryUser); - Sentry.addBreadcrumb(Breadcrumb.info("New context for message id " + message.getId())); - } + Member getGuildUser(); - public static CommandContext createContext(GuildMessageReceivedEvent event) { - Message message = event.getMessage(); - Member member = event.getMember(); - User user = event.getAuthor(); - Guild guild = event.getGuild(); - TextChannel channel = event.getChannel(); - JDA jda = event.getJDA(); + User getDiscordUser(); - return new CommandContext(message, member, user, guild, channel, jda); - } + JDA getJDA(); - public String getArgument(int index) { - return getArgs()[index]; - } + void deleteMessage(); - public String[] getArgs() { - String msg = message.getContentDisplay().trim(); - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); - String cmd = msg.split(" ", 2)[0]; - String[] args = msg.replaceFirst("(" + cmd + ")(\\s+)?", "").split("\s"); + void reply(MessageCreateData message); - if (args.length == 1 && args[0].isEmpty()) - args = new String[0]; + void reply(String message); - return args; - } + void reply(MessageEmbed... embeds); - public String getMessageText() { - String msg = message.getContentDisplay().trim(); - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); - String cmd = msg.split(" ", 2)[0]; - - return msg.replaceFirst("(" + cmd + ")(\s)?", ""); - } - - public Message getMessage() { - return message; - } - - public Guild getGuild() { - return guild; - } - - public TextChannel getChannel() { - return channel; - } - - public Member getGuildUser() { - return member; - } - - public User getDiscordUser() { - return user; - } - - public JDA getJDA() { - return jda; - } - - public AbstractCommand getCommand() { - return command; - } - - public GuildManager getGuildManager() { - return GuildManager.getManager(guild); - } - - public void reply(CommandUsage usage) { - reply(new MessageBuilder(usage.toString()).build()); - } - - public void reply(String msg) { - reply(new MessageBuilder(msg).build()); - } - - public void reply(String format, Object... arguments) { + default void reply(String format, Object... arguments) { reply(String.format(format, arguments)); } - public void reply(Message msg) { - if (channel != null && channel.canTalk()) { - channel.sendMessage(msg).queue(); - } + void replyToMessage(String message); + + default void replyToMessage(MessageCreateData message) { + reply(message); } - public void reply(MessageEmbed embed, MessageEmbed... embeds) { - if (channel != null && channel.canTalk()) { - channel.sendMessageEmbeds(embed, embeds).queue(); - } - } - - public void reply(Collection<? extends MessageEmbed> embeds) { - if (channel != null && channel.canTalk()) { - channel.sendMessageEmbeds(embeds).queue(); - } - } - - public void replyToMessage(String msg) { - if (channel != null && channel.canTalk() && message != null) { - replyToMessage(new MessageBuilder(msg).build()); - } - } - - public void replyToMessage(String format, Object... arguments) { + default void replyToMessage(String format, Object... arguments) { replyToMessage(String.format(format, arguments)); } - - public void replyToMessage(Message msg) { - if (channel != null && channel.canTalk() && message != null) { - message.reply(msg).queue(); - } - } - - public void replyPrivate(String msg) { - replyPrivate(new MessageBuilder(msg).build()); - } - - public void replyPrivate(Message msg) { - user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); - } - - public void replyPrivate(MessageEmbed embed, MessageEmbed... embeds) { - user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embed, embeds)).queue(); - } - - public void replyPrivate(Collection<? extends MessageEmbed> embeds) { - user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); - } - - public void deleteMessage() { - if (message != null) { - message.delete().queueAfter(1, TimeUnit.SECONDS); - } - } - - public boolean isMessageFromOwner() { - return member.isOwner(); - } - - public boolean isMessageFromCreator() { - String creatorId = Settings.getInstance().getCreatorId(); - - return creatorId.equals(member.getId()); - } - - public void dispatch(AbstractCommand command) { - this.command = command; - //TODO: Add usage check - - Sentry.configureScope(scope -> { - scope.setContexts("command", command.getCommandName()); - scope.setContexts("isAdmin", UserFunction.isAdmin(member)); - scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); - scope.setTag("channel", channel.getId()); - scope.setTag("message", message.getId()); - scope.setTag("guild", guild.getId()); - }); - - try { - if (command.needAdmin() && !UserFunction.isAdmin(member)) { - reply("You are not powerful enough, scrub"); - return; - } - - if (command.canBeExecutedBy(guild, member)) { - if (command.canBeExecutedFrom(guild, channel)) { - command.execute(this); - } - } - } catch (CommandErrorException | CommandExecutionException e) { - LogHandler.log(e); - } catch (Exception e) { - LogHandler.log(new CommandExecutionException("Error during command execution", this, e)); - } - } } diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java new file mode 100644 index 0000000..294ffcd --- /dev/null +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -0,0 +1,225 @@ +package netneutrality.core.context; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import io.sentry.Breadcrumb; +import io.sentry.Sentry; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; +import netneutrality.command.AbstractCommand; +import netneutrality.core.GuildManager; +import netneutrality.core.LogHandler; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.thread.ThreadManager; +import netneutrality.utils.Settings; +import netneutrality.utils.UserFunction; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +public class MessageCommandContext implements CommandContext { + + private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED); + + private AbstractCommand command; + private final MessageReceivedEvent event; + private final Message message; + private final Guild guild; + private final MessageChannel channel; + private final Member member; + private final User user; + private final JDA jda; + + public MessageCommandContext(MessageReceivedEvent event, Message message, Member member, User user, Guild guild, MessageChannel channel, JDA jda) { + this.event = event; + this.message = message; + this.member = member; + this.guild = guild; + this.channel = channel; + this.user = user; + this.jda = jda; + + io.sentry.protocol.User sentryUser = new io.sentry.protocol.User(); + sentryUser.setId(member.getId()); + sentryUser.setUsername(member.getEffectiveName()); + Sentry.setUser(sentryUser); + Sentry.addBreadcrumb(Breadcrumb.info("New context for message id " + message.getId())); + } + + public static MessageCommandContext createContext(MessageReceivedEvent event) { + Message message = event.getMessage(); + Member member = event.getMember(); + User user = event.getAuthor(); + Guild guild = event.getGuild(); + MessageChannel channel = event.getChannel(); + JDA jda = event.getJDA(); + + return new MessageCommandContext(event, message, member, user, guild, channel, jda); + } + + @Override + public MessageReceivedEvent getEvent() { + return event; + } + + public String getArgument(int index) { + return getArgs()[index]; + } + + public String[] getArgs() { + String msg = message.getContentDisplay().trim(); + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + String cmd = msg.split(" ", 2)[0]; + String[] args = msg.replaceFirst("(" + cmd + ")(\\s+)?", "").split("\s"); + + if (args.length == 1 && args[0].isEmpty()) + args = new String[0]; + + return args; + } + + public String getMessageText() { + String msg = message.getContentDisplay().trim(); + msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + String cmd = msg.split(" ", 2)[0]; + + return msg.replaceFirst("(" + cmd + ")(\s)?", ""); + } + + public Message getMessage() { + return message; + } + + public Guild getGuild() { + return guild; + } + + public MessageChannel getChannel() { + return channel; + } + + public Member getGuildUser() { + return member; + } + + public User getDiscordUser() { + return user; + } + + public JDA getJDA() { + return jda; + } + + public AbstractCommand getCommand() { + return command; + } + + public GuildManager getGuildManager() { + return GuildManager.getManager(guild); + } + + public void reply(String message) { + reply(MessageCreateData.fromContent(message)); + } + + public void reply(String format, Object... arguments) { + reply(String.format(format, arguments)); + } + + public void reply(MessageEmbed... embeds) { + reply(MessageCreateData.fromEmbeds(embeds)); + } + + public void reply(MessageCreateData msg) { + if (channel != null && channel.canTalk()) { + channel.sendMessage(msg).queue(); + } + } + + @Override + public void replyToMessage(String message) { + replyToMessage(MessageCreateData.fromContent(message)); + } + + @Override + public void replyToMessage(String format, Object... arguments) { + replyToMessage(String.format(format, arguments)); + } + + public void replyToMessage(MessageCreateData msg) { + if (channel != null && channel.canTalk() && message != null) { + message.reply(msg).queue(); + } + } + + public void replyPrivate(String message) { + replyPrivate(MessageCreateData.fromContent(message)); + } + + public void replyPrivate(MessageCreateData msg) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + } + + public void replyPrivate(MessageEmbed... embeds) { + replyPrivate(MessageCreateData.fromEmbeds(embeds)); + } + + public void replyPrivate(Collection<? extends MessageEmbed> embeds) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); + } + + @Override + public void deleteMessage() { + if (message != null) { + message.delete().queueAfter(1, TimeUnit.SECONDS); + } + } + + public boolean isMessageFromOwner() { + return member.isOwner(); + } + + public boolean isMessageFromCreator() { + String creatorId = Settings.getInstance().getCreatorId(); + + return creatorId.equals(member.getId()); + } + + public void dispatch(AbstractCommand command) { + this.command = command; + //TODO: Add usage check + + Sentry.configureScope(scope -> { + scope.setContexts("command", command.getCommandName()); + scope.setContexts("isAdmin", UserFunction.isAdmin(member)); + scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); + scope.setTag("channel", channel.getId()); + scope.setTag("message", message.getId()); + scope.setTag("guild", guild.getId()); + }); + + try { + if (command.needAdmin() && !UserFunction.isAdmin(member)) { + reply("You are not powerful enough, scrub"); + return; + } + + if (command.canBeExecutedBy(guild, member)) { + if (command.canBeExecutedFrom(guild, channel)) { + command.execute(this); + } + } + } catch (CommandExecutionException e) { + LogHandler.log(e); + } catch (Exception e) { + LogHandler.log(new CommandExecutionException("Error during command execution", this, e)); + } + } +} diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java new file mode 100644 index 0000000..bfab32e --- /dev/null +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -0,0 +1,203 @@ +package netneutrality.core.context;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import io.sentry.Sentry; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.InteractionHook; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; +import net.dv8tion.jda.api.utils.messages.MessageEditData; +import netneutrality.command.AbstractCommand; +import netneutrality.core.CommandManager; +import netneutrality.core.LogHandler; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.utils.UserFunction; + +import java.util.Collection; + +public class SlashCommandContext implements CommandContext { + + private final SlashCommandInteractionEvent event; + private AbstractCommand command; + private final JDA jda; + private final Guild guild; + private final MessageChannel channel; + private final Member member; + private final User user; + + private SlashCommandContext(JDA jda, SlashCommandInteractionEvent event, Guild guild, MessageChannel channel, Member member, User user) { + this.jda = jda; + this.event = event; + this.guild = guild; + this.channel = channel; + this.member = member; + this.user = user; + } + + public static SlashCommandContext createContext(SlashCommandInteractionEvent event) { + Member member = event.getMember(); + User user = event.getUser(); + Guild guild = event.getGuild(); + MessageChannel channel = event.getChannel(); + JDA jda = event.getJDA(); + + return new SlashCommandContext(jda, event, guild, channel, member, user); + } + + @Override + public SlashCommandInteractionEvent getEvent() { + return event; + } + + @Override + public AbstractCommand getCommand() { + return command; + } + + @Override + public JDA getJDA() { + return jda; + } + + @Override + public Guild getGuild() { + return guild; + } + + @Override + public MessageChannel getChannel() { + return channel; + } + + @Override + public Member getGuildUser() { + return member; + } + + @Override + public User getDiscordUser() { + return user; + } + + @Override + public void deleteMessage() { + // not implemented + } + + public void sendMessageInPrivate(String msg) { + sendMessageInPrivate(new MessageCreateBuilder().setContent(msg).build()); + } + + public void sendMessageInPrivate(MessageCreateData msg) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + } + + public void sendMessageInPrivate(MessageEmbed embed, MessageEmbed... embeds) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embed, embeds)).queue(); + } + + public void sendMessageInPrivate(Collection<? extends MessageEmbed> embeds) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); + } + + public void reply(MessageCreateData message) { + if (event.isAcknowledged()) { + getHook().editOriginal(MessageEditData.fromCreateData(message)).queue(); + //getHook().sendMessage(message).setEphemeral(false).queue(); + return; + } + + event.reply(message).queue(); + } + + public void reply(MessageEmbed... embeds) { + reply(MessageCreateData.fromEmbeds(embeds)); + } + + @Override + public void reply(String message) { + reply(MessageCreateData.fromContent(message)); + } + + public void replyEphemeral(MessageCreateData message) { + if (event.isAcknowledged()) { + getHook().editOriginal(MessageEditData.fromCreateData(message)).queue(); + //getHook().sendMessage(message).setEphemeral(true).queue(); + return; + } + + event.reply(message).setEphemeral(true).queue(); + } + + public void replyEphemeral(String format, Object... arguments) { + replyEphemeral(String.format(format, arguments)); + } + + public void replyEphemeral(String message) { + replyEphemeral(MessageCreateData.fromContent(message)); + } + + @Override + public void replyToMessage(String message) { + replyEphemeral(message); + } + + public InteractionHook getHook() { + if (!event.isAcknowledged()) + throw new RuntimeException("Interaction isn't acknowledged yet"); + + return event.getHook(); + } + + public void ackAndWait(boolean ephemeral) { + if (event.isAcknowledged()) + throw new RuntimeException("Interaction is already acknowledged, please use getHook() instead."); + + event.deferReply(ephemeral).queue(); + } + + public void ackAndWait() { + ackAndWait(false); + } + + public void dispatchToCommand(String commandName) { + if (!CommandManager.isValidCommand(commandName)) { + return; + } + + AbstractCommand command = CommandManager.getCommand(commandName); + this.command = command; + + Sentry.configureScope(scope -> { + scope.setContexts("command", command.getCommandName()); + scope.setContexts("isAdmin", UserFunction.isAdmin(member)); + scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); + scope.setTag("channel", channel.getId()); + scope.setTag("interactionId", event.getInteraction().getId()); + scope.setTag("guild", guild.getId()); + }); + + try { + if (command.needAdmin() && !UserFunction.isAdmin(member)) { + replyEphemeral("You are not powerful enough, scrub"); + return; + } + + if (command.canBeExecutedBy(guild, member)) { + command.execute(this); + } + + } catch (CommandExecutionException exception) { + LogHandler.log(exception); + } catch (Exception exception) { + LogHandler.log(new CommandExecutionException("Error during command execution", this, exception)); + } + + } +} diff --git a/src/main/java/netneutrality/db/GSettings.java b/src/main/java/netneutrality/db/GSettings.java index 8ec59c0..75bb292 100644 --- a/src/main/java/netneutrality/db/GSettings.java +++ b/src/main/java/netneutrality/db/GSettings.java @@ -6,17 +6,11 @@ package netneutrality.db; * https://discord.gg/CdFcyQ */ - -import netneutrality.utils.Settings; - public enum GSettings { //TODO: description - PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")), MUSIC_ROLE("MUSIC_ROLE", ""), MUSIC_CHANNEL("MUSIC_CHANNEL", ""), - MUSIC_VOLUME("MUSIC_VOLUME", "30"), - MUSIC_TOPIC("MUSIC_TOPIC", "0"), - BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); + MUSIC_VOLUME("MUSIC_VOLUME", "30"); private final String name; private final String defaultValue; diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 725316e..b4cf87a 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -6,6 +6,7 @@ package netneutrality.db.controllers; * https://discord.gg/CdFcyQ */ +import net.dv8tion.jda.api.entities.Guild; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; import netneutrality.db.AbstractController; @@ -104,8 +105,8 @@ public class DBBlacklist extends AbstractController { session.close(); } - public ArrayList<OBlacklist> getBlacklistForGuild(CommandContext context) { - GuildManager guildManager = GuildManager.getManager(context.getGuild()); + public ArrayList<OBlacklist> getBlacklistForGuild(Guild guild) { + GuildManager guildManager = GuildManager.getManager(guild); Session session = getSessionFactory().openSession(); OGuild guildEntity = guildManager.getGuildEntity(); diff --git a/src/main/java/netneutrality/exceptions/CommandErrorException.java b/src/main/java/netneutrality/exceptions/CommandErrorException.java deleted file mode 100644 index 0802ea2..0000000 --- a/src/main/java/netneutrality/exceptions/CommandErrorException.java +++ /dev/null @@ -1,27 +0,0 @@ -package netneutrality.exceptions; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.core.context.CommandContext; - -/** - * Used to reply with a message in the text channel where the command was executed - */ -public class CommandErrorException extends CommandException { - - /** - * Used to reply with a message in the text channel where the command was executed - * - * @param message Message to send to the channel - * @param context The command context - */ - public CommandErrorException(String message, CommandContext context, Throwable cause) { - super(message, context, cause); - - } -} diff --git a/src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java b/src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java deleted file mode 100644 index b309f44..0000000 --- a/src/main/java/netneutrality/handler/hooks/message/ReactionHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package netneutrality.handler.hooks.message; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; - -public class ReactionHandler extends ListenerAdapter { - - @Override - public void onGuildMessageReactionAdd(@NotNull GuildMessageReactionAddEvent event) { - Member member = event.getMember(); - } - - @Override - public void onGuildMessageReactionRemove(@NotNull GuildMessageReactionRemoveEvent event) { - super.onGuildMessageReactionRemove(event); - } - - @Override - public void onGuildMessageUpdate(@NotNull GuildMessageUpdateEvent event) { - super.onGuildMessageUpdate(event); - } -} diff --git a/src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java b/src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java deleted file mode 100644 index 4ce8d7b..0000000 --- a/src/main/java/netneutrality/handler/ratelimiter/IMessageRateLimiter.java +++ /dev/null @@ -1,16 +0,0 @@ -package netneutrality.handler.ratelimiter; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; - -public interface IMessageRateLimiter { - - void check(Member member, Message message, TextChannel channel); -} diff --git a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java deleted file mode 100644 index bd0d641..0000000 --- a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package netneutrality.handler.ratelimiter; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; - -import java.time.OffsetDateTime; - -//TODO: to remove? or atleast make it useful -public class MessageRateLimiterImpl implements IMessageRateLimiter { - private final int messagePerSecond = 5; - private static Member lastSender; - private static OffsetDateTime timestamp; - private static final long cooldown = 500000000L; // 1 seconds = 1000000000 nanoseconds - - public MessageRateLimiterImpl() { - - } - - @Override - public void check(Member member, Message message, TextChannel channel) { - - if (lastSender == null || timestamp == null) { - lastSender = member; - timestamp = message.getTimeCreated(); - return; - } - - if (member.getUser().getId().equals(lastSender.getUser().getId())) { - if (message.getTimeCreated().minusNanos(cooldown).isBefore(timestamp)) { - lastSender = member; - timestamp = message.getTimeCreated(); - message.delete().queue(); - return; - } - } - - lastSender = member; - timestamp = message.getTimeCreated(); - } -} diff --git a/src/main/java/netneutrality/hooks/SlashCommandHooks.java b/src/main/java/netneutrality/hooks/SlashCommandHooks.java new file mode 100644 index 0000000..598f733 --- /dev/null +++ b/src/main/java/netneutrality/hooks/SlashCommandHooks.java @@ -0,0 +1,23 @@ +package netneutrality.hooks; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.core.context.SlashCommandContext; +import org.jetbrains.annotations.NotNull; + +public class SlashCommandHooks extends ListenerAdapter { + + @Override + public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + String commandName = event.getName(); + + SlashCommandContext commandContext = SlashCommandContext.createContext(event); + commandContext.dispatchToCommand(commandName); + } +} diff --git a/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java b/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java similarity index 93% rename from src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java rename to src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java index de6a6a7..f556970 100644 --- a/src/main/java/netneutrality/handler/hooks/guilds/ServerJoinHandler.java +++ b/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler.hooks.guilds; +package netneutrality.hooks.guilds; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java b/src/main/java/netneutrality/hooks/message/EditHandler.java similarity index 97% rename from src/main/java/netneutrality/handler/hooks/message/EditHandler.java rename to src/main/java/netneutrality/hooks/message/EditHandler.java index 03cc806..4637c14 100644 --- a/src/main/java/netneutrality/handler/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/hooks/message/EditHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler.hooks.message; +package netneutrality.hooks.message; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java similarity index 65% rename from src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java rename to src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java index 62bb276..9946879 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler.hooks.message; +package netneutrality.hooks.message; /* * Copyright (c) anthorob * @@ -8,39 +8,42 @@ package netneutrality.handler.hooks.message; import io.sentry.Breadcrumb; import io.sentry.Sentry; -import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.command.AbstractCommand; import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; -import netneutrality.core.context.CommandContext; -import netneutrality.db.GSettings; +import netneutrality.core.context.MessageCommandContext; import netneutrality.utils.Settings; import org.jetbrains.annotations.NotNull; public class MessageReceivedHandler extends ListenerAdapter { @Override - public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (event.getAuthor().isBot()) return; if (event.isWebhookMessage()) return; + if (!event.isFromGuild()) + return; + Message message = event.getMessage(); Member member = event.getMember(); Guild guild = event.getGuild(); - TextChannel channel = event.getChannel(); + TextChannel channel = (TextChannel) event.getChannel(); Sentry.addBreadcrumb(Breadcrumb.info("New message from " + member.getEffectiveName())); - CommandContext context = CommandContext.createContext(event); + MessageCommandContext context = MessageCommandContext.createContext(event); - GuildManager.getManager(guild).getRateLimiter().check(member, message, channel); GuildManager.getManager(guild).checkAndLogMessage(message, member, channel); String rawMessage = message.getContentDisplay().trim(); - //String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); - String prefix = GuildManager.getManager(guild).getSetting(GSettings.PREFIX); + String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); if (rawMessage.startsWith(prefix)) { rawMessage = rawMessage.replaceFirst(String.format("^[%s\\s]{1,}", prefix), "").trim(); @@ -54,8 +57,6 @@ public class MessageReceivedHandler extends ListenerAdapter { context.dispatch(command); } - } else { - GuildManager.getManager(guild).checkBlacklist(message, channel); } } } diff --git a/src/main/java/netneutrality/hooks/message/ReactionHandler.java b/src/main/java/netneutrality/hooks/message/ReactionHandler.java new file mode 100644 index 0000000..abcf8b2 --- /dev/null +++ b/src/main/java/netneutrality/hooks/message/ReactionHandler.java @@ -0,0 +1,32 @@ +package netneutrality.hooks.message; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.events.message.MessageUpdateEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +public class ReactionHandler extends ListenerAdapter { + + @Override + public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) { + Member member = event.getMember(); + } + + @Override + public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent event) { + + } + + @Override + public void onMessageUpdate(@NotNull MessageUpdateEvent event) { + + } +} diff --git a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java b/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java similarity index 95% rename from src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java rename to src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java index 7a42370..3bc75c3 100644 --- a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java +++ b/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler.hooks.voice; +package netneutrality.hooks.voice; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index ccb21d3..8a01775 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -13,7 +13,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index de0ea5e..f0f3b8f 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -10,7 +10,6 @@ package netneutrality.music; 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.AudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; @@ -21,6 +20,7 @@ import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.core.GuildManager; import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.db.GSettings; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.loadable.LoadableSong; @@ -30,7 +30,9 @@ import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -43,7 +45,6 @@ public class MusicManager { private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); - private final static Map<String, AudioSourceManager> sources = new HashMap<>(); private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; @@ -75,12 +76,9 @@ public class MusicManager { YoutubeAudioSourceManager youtubeSource = new YoutubeAudioSourceManager(true, Settings.getInstance().get("GG_EMAIL", ""), Settings.getInstance().get("GG_PASS", "")); - SoundCloudAudioSourceManager soundcloudSource = SoundCloudAudioSourceManager.createDefault(); - sources.put("youtube", youtubeSource); - sources.put("soundcloud", soundcloudSource); playerManager.registerSourceManager(youtubeSource); - playerManager.registerSourceManager(soundcloudSource); + playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); } public boolean isNotConnectedTo(VoiceChannel vChannel) { @@ -115,7 +113,7 @@ public class MusicManager { } public synchronized Member getRequesterOfCurrentTrack() { - QueueManager.TrackInfo info = scheduler.getQueueManager().getQueue().peek(); + QueueManager.TrackInfo info = scheduler.getQueueManager().peekHeadOfQueue(); if (info == null) return null; @@ -152,9 +150,8 @@ public class MusicManager { public static void disconnectPlayers() { for (MusicManager mm : managers.values()) { - mm.leave(); + mm.getScheduler().getQueueManager().clearQueue(); mm.player.destroy(); - mm.scheduler.getQueueManager().getQueue().clear(); } } @@ -175,7 +172,7 @@ public class MusicManager { public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); - TextChannel channel = context.getChannel(); + TextChannel channel = (TextChannel) context.getChannel(); if (member.getVoiceState() == null) { logger.error("Guild {}: Voice state is null", guild.getId()); @@ -185,12 +182,12 @@ public class MusicManager { return; } - if (!member.getVoiceState().inVoiceChannel()) { + if (!member.getVoiceState().inAudioChannel()) { context.replyToMessage("You are not in a voice channel"); return; } - VoiceChannel vChannel = member.getVoiceState().getChannel(); + VoiceChannel vChannel = (VoiceChannel) member.getVoiceState().getChannel(); if (needToBeConnected && isNotConnectedTo(vChannel)) { context.replyToMessage("The player is not in your voice channel"); return; @@ -215,23 +212,9 @@ public class MusicManager { player.stopTrack(); } - public synchronized void skip(int nbTrack) { - if (!scheduler.getQueueManager().getQueue().isEmpty()) { - if (nbTrack >= scheduler.getQueueManager().getQueue().size()) { - nbTrack = 1; - } - - logger.debug("Guild {}: skipping tracks, toSkip={}", guild.getId(), nbTrack); - scheduler.getQueueManager().skipAndPlay(nbTrack); - } else { - leave(); - } - } - public synchronized void voteSkip(CommandContext context) { - Queue<QueueManager.TrackInfo> queue = scheduler.getQueueManager().getQueue(); - VoiceChannel voiceChannel = guild.getAudioManager().getConnectedChannel(); - QueueManager.TrackInfo info = queue.peek(); + VoiceChannel voiceChannel = (VoiceChannel) guild.getAudioManager().getConnectedChannel(); + QueueManager.TrackInfo info = scheduler.getQueueManager().peekHeadOfQueue(); if (!isCurrentlyPlaying() || voiceChannel == null) { return; @@ -246,7 +229,7 @@ public class MusicManager { if (connected < 3) { context.reply("Skipping current track since not enough people are connected to the voice channel."); - skip(1); + scheduler.getQueueManager().skip(1); return; } @@ -258,7 +241,7 @@ public class MusicManager { if (info.getSkips().size() > needed) { context.reply("Skipping current track: %s", info.getTrack().getInfo().title); - skip(1); + scheduler.getQueueManager().skip(1); } else { context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); } @@ -269,14 +252,10 @@ public class MusicManager { } public int getQueueSize() { - synchronized (scheduler.getQueueManager().getQueue()) { - return scheduler.getQueueManager().getQueue().size(); - } - + return scheduler.getQueueManager().getQueueSize(); } public TrackScheduler getScheduler() { return scheduler; } - } diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 550449f..b2f4518 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -14,10 +14,11 @@ import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.LinkedBlockingDeque; +import java.util.function.Predicate; public class QueueManager { - static class TrackInfo { + public static class TrackInfo { private final AudioTrack track; private final Member member; @@ -101,9 +102,9 @@ public class QueueManager { this.queue = new LinkedBlockingDeque<>(); } - public Queue<TrackInfo> getQueue() { + public List<TrackInfo> getQueue() { synchronized (queue) { - return queue; + return queue.stream().toList(); } } @@ -115,15 +116,65 @@ public class QueueManager { return guild; } + public int getQueueSize() { + synchronized (queue) { + return queue.size(); + } + } + + public List<TrackInfo> getQueueWithFilter(Predicate<? super TrackInfo> filter) { + synchronized (queue) { + return queue.stream().filter(filter).toList(); + } + } + + public TrackInfo peekHeadOfQueue() { + synchronized (queue) { + return queue.peek(); + } + } + + public TrackInfo pollHeadOfQueue() { + synchronized (queue) { + return queue.poll(); + } + } + + public boolean isEmpty() { + synchronized (queue) { + return queue.isEmpty(); + } + } + public void clearQueue() { - scheduler.getMusicManager().leave(); scheduler.getMusicManager().stopLoading(); + scheduler.getMusicManager().leave(); synchronized (queue) { queue.clear(); } } + public void removeTracksFromUser(Member member) { + synchronized (queue) { + int size = queue.stream().filter(trackInfo -> member.equals(trackInfo.getRequester())).toList().size(); + + if (size > 0) { + if (size == queue.size()) { + clearQueue(); + return; + } + + TrackInfo first = queue.peek(); + queue.removeIf(trackInfo -> member.equals(trackInfo.getRequester())); + + if (first != null && member.equals(first.getRequester())) { + skip(1); + } + } + } + } + public ArrayList<AudioTrack> getAllQueuedTrack() { synchronized (queue) { ArrayList<AudioTrack> tracks = new ArrayList<>(); @@ -156,7 +207,7 @@ public class QueueManager { } } - public void nextTrack(AudioPlayer player) { + public void playNextTrack(AudioPlayer player) { synchronized (queue) { TrackInfo last = queue.poll(); TrackInfo next = queue.peek(); @@ -164,7 +215,7 @@ public class QueueManager { if (next != null) { if (last != null && last.getTrack().equals(next.getTrack())) { logger.debug("Guild {}: duplicate track in queue found, skipping to next. last={}, next={}", guild.getId(), last.getTrack().getIdentifier(), next.getTrack().getIdentifier()); - nextTrack(player); + playNextTrack(player); } else { player.startTrack(next.getTrack(), false); } @@ -175,12 +226,23 @@ public class QueueManager { } - public void skipAndPlay(int nb) { - if (nb == 0) + public void skip(int nbTrack) { + if (nbTrack == 0) return; synchronized (queue) { - for (int i = 0; i < nb; i++) { + + if (queue.isEmpty()) { + scheduler.getMusicManager().leave(); + return; + } + + if (nbTrack > queue.size()) { + nbTrack = 1; + } + + logger.debug("Guild {}: skipping tracks, toSkip={}", guild.getId(), nbTrack); + for (int i = 0; i < nbTrack; i++) { TrackInfo last = queue.poll(); } @@ -190,8 +252,8 @@ public class QueueManager { } else { player.stopTrack(); } - } + } } public void shuffle() { @@ -212,17 +274,17 @@ public class QueueManager { } } - protected boolean removeFromQueue(int index) { + public boolean removeFromQueue(int index) { synchronized (queue) { if (queue.size() > 0 && index <= queue.size()) { logger.debug("Guild {}: removing index {} from queue", guild.getId(), index - 1); if (index == 1) { - skipAndPlay(1); + skip(1); return true; } - ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); + List<TrackInfo> newQueue = new ArrayList<>(queue); newQueue.remove(index - 1); queue.clear(); diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index 6d7f853..b61c956 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -30,7 +30,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { private boolean loadingDisabled = false; private final Guild guild; private final TrackScheduler scheduler; - private final CommandContext context; + private final CommandContext context; public TrackLoadingHandler(CommandContext context, MusicManager manager, String identifier, SourceFinder.AudioSourceType type, boolean silent) { this.identifier = identifier; @@ -66,8 +66,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { scheduler.getQueueManager().queue(audioTrack, context.getGuildUser()); if (!silent) { - scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type)); - // context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type)); + context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, type)); } } @@ -88,8 +87,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { scheduler.getQueueManager().queue(track, context.getGuildUser()); if (!silent) { - scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type)); - // context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type)); + context.reply(MessageFunction.buildAddingTrackMessage(track, type)); } return; @@ -97,8 +95,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { context.deleteMessage(); if (!silent) { - scheduler.sendMessageToChannel(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type)); - // context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type)); + context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, identifier, type)); } for (AudioTrack track : audioPlaylist.getTracks()) { @@ -106,9 +103,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { break; } - synchronized (scheduler.getQueueManager().getQueue()) { - scheduler.getQueueManager().queue(track, context.getGuildUser()); - } + scheduler.getQueueManager().queue(track, context.getGuildUser()); } } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index da3031b..dad5daf 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -99,13 +99,11 @@ public class TrackScheduler extends AudioEventAdapter { // check if mayStartNext if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { - queueManager.nextTrack(player); + queueManager.playNextTrack(player); } if (endReason == AudioTrackEndReason.STOPPED) { - synchronized (queueManager.getQueue()) { - queueManager.getQueue().poll(); - } + queueManager.pollHeadOfQueue(); } // endReason == FINISHED: A track finished or died by an exception (mayStartNext = true). @@ -127,6 +125,6 @@ public class TrackScheduler extends AudioEventAdapter { public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { logger.debug("Guild {}: currently playing track is stuck: {}", guild.getId(), track.getIdentifier()); sendMessageToChannel("Current track is stuck, skipping to next"); - queueManager.nextTrack(player); + queueManager.playNextTrack(player); } } diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index 2a22301..f24a2e6 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -25,12 +25,12 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { @Override public void run() { Guild guild = manager.getGuild(); - VoiceChannel channel = guild.getAudioManager().getConnectedChannel(); + VoiceChannel channel = (VoiceChannel) guild.getAudioManager().getConnectedChannel(); if (channel != null) { List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); - if (members.size() == 0 || manager.getScheduler().getQueueManager().getQueue().isEmpty()) { + if (members.size() == 0 || manager.getScheduler().getQueueManager().isEmpty()) { LoggerFactory.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); manager.leave(); } diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java deleted file mode 100644 index abe112f..0000000 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ /dev/null @@ -1,95 +0,0 @@ -package netneutrality.utils; - -import io.sentry.ISpan; -import io.sentry.ITransaction; -import io.sentry.Sentry; -import io.sentry.SpanStatus; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.thread.ThreadManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.time.OffsetDateTime; -import java.util.List; - -public class ChannelFunction { - - private static final Logger logger = LoggerFactory.getLogger(ChannelFunction.class); - - public static void bulkDeleteMessage(TextChannel channel, int toDelete) { - - if (toDelete >= 2500) return; - - ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { - ITransaction transaction = Sentry.startTransaction(String.format("bulkDeleteMessage(%s, %d)", channel.getId(), toDelete), "task"); - transaction.setData("channel", channel.getId()); - transaction.setData("toDelete", toDelete); - transaction.setTag("operation", "bulk-delete"); - - try { - - int toDeleteFinal = toDelete + 1; - int iteration = toDeleteFinal / 100; - for (int i = 0; i < iteration; i++) { - ISpan innerSpan = transaction.startChild("task", "Processing iteration " + (i + 1) + "/" + iteration); - try { - List<Message> messages = channel.getHistory().retrievePast(100).complete(); - deleteFromList(messages, channel, innerSpan); - toDeleteFinal -= 100; - innerSpan.setStatus(SpanStatus.OK); - } catch (Exception e) { - innerSpan.setThrowable(e); - innerSpan.setStatus(SpanStatus.INTERNAL_ERROR); - throw e; - } finally { - innerSpan.finish(); - } - } - - if (toDeleteFinal > 0) { - ISpan innerSpan = transaction.startChild("task", String.format("Processing final iteration (%d messages)", toDeleteFinal)); - try { - List<Message> messages = channel.getHistory().retrievePast(toDeleteFinal).complete(); - deleteFromList(messages, channel, innerSpan); - innerSpan.setStatus(SpanStatus.OK); - } catch (Exception e) { - innerSpan.setThrowable(e); - innerSpan.setStatus(SpanStatus.INTERNAL_ERROR); - throw e; - } finally { - innerSpan.finish(); - } - - - innerSpan.finish(); - } - - transaction.setStatus(SpanStatus.OK); - } catch (Exception e) { - transaction.setThrowable(e); - transaction.setStatus(SpanStatus.INTERNAL_ERROR); - } finally { - transaction.finish(); - } - }); - } - - private synchronized static void deleteFromList(List<Message> messages, TextChannel channel, ISpan span) { - ISpan innerSpan = span.startChild("delete", "Executing delete of: " + messages.size() + " messages"); - try { - channel.deleteMessages(messages).complete(); - innerSpan.setStatus(SpanStatus.OK); - } catch (IllegalArgumentException e) { - innerSpan.setThrowable(e); - innerSpan.setStatus(SpanStatus.OUT_OF_RANGE); - messages.forEach(m -> { - if (!m.getTimeCreated().isBefore(OffsetDateTime.now().minusWeeks(2))) { - m.delete().queue(); - } - }); - } finally { - innerSpan.finish(); - } - } -} diff --git a/src/main/java/netneutrality/utils/ChannelMessagePurger.java b/src/main/java/netneutrality/utils/ChannelMessagePurger.java new file mode 100644 index 0000000..2cdd5ee --- /dev/null +++ b/src/main/java/netneutrality/utils/ChannelMessagePurger.java @@ -0,0 +1,171 @@ +package netneutrality.utils; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import io.sentry.ISpan; +import io.sentry.ITransaction; +import io.sentry.Sentry; +import io.sentry.SpanStatus; +import net.dv8tion.jda.api.entities.GuildMessageChannel; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageHistory; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import netneutrality.core.context.CommandContext; +import netneutrality.thread.ThreadManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class ChannelMessagePurger { + + private static final Logger logger = LoggerFactory.getLogger(ChannelMessagePurger.class); + private static final Map<GuildMessageChannel, ChannelMessagePurger> instances = new HashMap<>(); + private final GuildMessageChannel channel; + private final Lock lock; + + private ChannelMessagePurger(GuildMessageChannel channel) { + this.channel = channel; + this.lock = new ReentrantLock(); + } + + public static ChannelMessagePurger getPurger(GuildMessageChannel channel) { + return instances.computeIfAbsent(channel, ChannelMessagePurger::new); + } + + public boolean canLockBeAcquired() { + boolean acquired = lock.tryLock(); + if (acquired) + lock.unlock(); + + return acquired; + } + + public void purgeMessages(CommandContext context, int toPurge) { + ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { + if (lock.tryLock()) { + try { + int total = countAllChannelMessages(channel); + int finalToPurge = toPurge; + + if (finalToPurge > total) { + finalToPurge = total; + } + + safePurge(context, finalToPurge); + } finally { + lock.unlock(); + } + } + }); + } + + public void purgeChannel(CommandContext context) { + ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { + if (lock.tryLock()) { + try { + int total = countAllChannelMessages(channel); + context.reply("Number of messages to purge: %d", total); + + safePurge(context, total); + } finally { + lock.unlock(); + } + } + }); + } + + private synchronized int countAllChannelMessages(GuildMessageChannel channel) { + logger.info("Guild {}: counting all messages from channel {}", channel.getGuild().getId(), channel.getId()); + MessageHistory history = channel.getHistory(); + int totalCount = 0; + int iterationCount = 0; + + while (totalCount == iterationCount) { + history.retrievePast(100).complete(); + + iterationCount += 100; + totalCount = history.size(); + } + logger.info("Guild {}: Counted {} messages from channel {}", channel.getGuild().getId(), totalCount, channel.getId()); + + return totalCount; + } + + private synchronized void safePurge(CommandContext context, int toPurge) { + ITransaction transaction = Sentry.startTransaction(String.format("purge messages from guild %s)", channel.getGuild().getId()), "task"); + transaction.setData("channel", channel.getId()); + transaction.setData("toPurge", toPurge); + + if (toPurge == 1) { + toPurge += 1; + } + + int tracker = toPurge; + int iteration = tracker / 100; + boolean olderThan2Weeks = false; + context.replyToMessage("Purging iterations to do: %d", iteration); + + try { + for (int i = 0; i < iteration; i++) { + ISpan innerSpan = transaction.startChild("retrieve-messages", "Processing iteration " + (i + 1) + "/" + iteration); + try { + List<Message> messages = channel.getHistory().retrievePast(100).complete(); + channel.deleteMessages(messages).complete(); + tracker -= 100; + innerSpan.setStatus(SpanStatus.OK); + } catch (IllegalArgumentException ex) { + olderThan2Weeks = true; + } catch (Exception e) { + innerSpan.setThrowable(e); + innerSpan.setStatus(SpanStatus.INTERNAL_ERROR); + } finally { + innerSpan.finish(); + } + } + + if (tracker > 0) { + ISpan innerSpan = transaction.startChild("retrieve-messages", String.format("Processing final iteration (%d messages)", tracker)); + try { + List<Message> messages = channel.getHistory().retrievePast(tracker).complete(); + channel.deleteMessages(messages).complete(); + innerSpan.setStatus(SpanStatus.OK); + } catch (IllegalArgumentException ex) { + olderThan2Weeks = true; + } catch (Exception e) { + innerSpan.setThrowable(e); + innerSpan.setStatus(SpanStatus.INTERNAL_ERROR); + } finally { + innerSpan.finish(); + } + + + innerSpan.finish(); + } + + } catch (Exception e) { + transaction.setThrowable(e); + transaction.setStatus(SpanStatus.INTERNAL_ERROR); + } finally { + transaction.finish(); + MessageCreateBuilder builder = new MessageCreateBuilder() + .addContent("Finished purging ") + .addContent(String.valueOf(toPurge)) + .addContent(" messages."); + + if (olderThan2Weeks) { + builder.addContent("\n").addContent("Messages older than two weeks weren't deleted."); + } + context.reply(builder.build()); + lock.unlock(); + } + } +} diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index a6069ca..8fbca70 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -14,20 +14,22 @@ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; +import netneutrality.core.CommandManager; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandException; -import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; +import netneutrality.music.QueueManager; import netneutrality.music.SourceFinder; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import java.util.*; +import java.util.Set; public class MessageFunction { @@ -35,7 +37,7 @@ public class MessageFunction { public static Member getStartingMention(Message message) { if (isStartingWithMention(message)) { - return message.getMentionedMembers().get(0); + return message.getMentions().getMembers().get(0); } return null; @@ -45,7 +47,7 @@ public class MessageFunction { if (!message.isFromType(ChannelType.TEXT)) return false; - List<Member> mentions = message.getMentionedMembers(); + List<Member> mentions = message.getMentions().getMembers(); for (Member member : mentions) { if (message.getContentDisplay().startsWith("@" + member.getUser().getName())) @@ -55,9 +57,8 @@ public class MessageFunction { return false; } - public static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager, Member user) { + public static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager) { AudioTrack current = manager.getCurrentlyPlaying(); - Member requester = (manager.getRequesterOfCurrentTrack() == null ? user : manager.getRequesterOfCurrentTrack()); EmbedBuilder message = new EmbedBuilder(); message.setAuthor("Link to track", String.format("https://youtu.be/%s", current.getIdentifier())); @@ -66,15 +67,13 @@ public class MessageFunction { message.setColor(Color.BLUE); message.addField("Track title: ", current.getInfo().title, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); - message.setFooter("Requested by " + requester.getEffectiveName(), requester.getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member member, SourceFinder.AudioSourceType type) { + public static MessageEmbed buildAddingTrackMessage(AudioTrack track, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); - String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); String url = track.getIdentifier(); String thumbnail = null; @@ -90,15 +89,13 @@ public class MessageFunction { message.setColor(Color.BLUE); message.addField("Track title: ", String.format("[**`%s`**](%s)", track.getInfo().title, url), false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); - message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member member, String identifier, SourceFinder.AudioSourceType type) { + public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, String identifier, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); - String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); String url = identifier; String thumbnail = null; @@ -114,14 +111,12 @@ public class MessageFunction { message.setColor(Color.BLUE); message.addField("Playlist: ", String.format("[**`%s`**](%s)", playlist.getName(), url), false); message.addField("Number of tracks: ", String.valueOf(playlist.getTracks().size()), false); - message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member member, boolean currentlyPlaying) { - String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); + public static MessageEmbed buildViewQueueMessage(MusicManager manager, boolean currentlyPlaying) { ArrayList<AudioTrack> tracks = manager.getScheduler().getQueueManager().getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); int numberofTracksShown = Math.min(tracks.size(), 10); @@ -143,56 +138,55 @@ public class MessageFunction { if (index == 10) break; } - message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildHelpMessage(AbstractCommand command) { + public static MessageEmbed buildUserTracksMessage(MusicManager manager, Member member) { + List<QueueManager.TrackInfo> tracks = manager.getScheduler() + .getQueueManager() + .getQueueWithFilter(trackInfo -> member.equals(trackInfo.getRequester())); + AudioTrack current = manager.getCurrentlyPlaying(); + int numberofTracksShown = Math.min(tracks.size(), 10); + EmbedBuilder message = new EmbedBuilder(); - message.setTitle(":information_source: Help for command " + command.getCommandName()); + message.setTitle(String.format("Tracks added by %s (showing %d out of %d items):", member.getAsMention(), numberofTracksShown, tracks.size())); message.setColor(Color.BLUE); - message.addField("Command", command.getCommandName(), false); - message.addField("Description", command.getDescription(), false); - message.addField("Aliases", ((command.getAlias() == null || command.getAlias().length == 0) ? "None" : Arrays.toString(command.getAlias()).replaceAll("[\\[\\]]", "")), false); - message.addField("Usage", (command.getUsage() == null ? "No arguments defined" : command.getUsage().toString()), false); + + int index = 0; + for (QueueManager.TrackInfo track : tracks) { + AudioTrackInfo info = track.getTrack().getInfo(); + + if (current != null && current.getInfo().title.equals(info.title)) { + message.addField("Track #" + ++index + " (Currently playing)", info.title, false); + } else { + message.addField("Track #" + ++index, info.title, false); + } + + if (index == 10) break; + } + message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static ArrayList<MessageEmbed> buildHelpMessage(HashMap<String, AbstractCommand> commands, boolean admin) { - - SortedSet<String> keys = new TreeSet<>(commands.keySet()); + public static ArrayList<MessageEmbed> buildHelpMessage(Member member) { HashMap<CommandType, EmbedBuilder> help = new HashMap<>(); - for (String commandName : keys) { - AbstractCommand command = commands.get(commandName); + for (AbstractCommand command : CommandManager.commands.values()) { if (command.getType() == null) continue; String description = "No description yet"; - StringBuilder availAlias = new StringBuilder(); if (command.isEnabled() && command.getType() != CommandType.UNLISTED) { - if (command.getType() == CommandType.ADMINISTRATION && !admin) + if (command.getType() == CommandType.ADMINISTRATION && !UserFunction.isAdmin(member)) continue; if (command.getDescription() != null) description = command.getDescription(); - if (command.getAlias() != null && command.getAlias().length > 0) { - availAlias.append("("); - for (String str : command.getAlias()) { - availAlias.append(str).append(","); - } - - if (!availAlias.isEmpty()) { - availAlias.deleteCharAt(availAlias.lastIndexOf(",")); - availAlias.append(")"); - } - } - EmbedBuilder message; if (help.containsKey(command.getType())) { message = help.get(command.getType()); @@ -205,9 +199,8 @@ public class MessageFunction { message.setColor(Color.BLUE); } - message.addField(String.format("%s %s", command.getCommandName(), availAlias), description, false); + message.addField(String.format("%s", command.getCommandName()), description, false); } - } ArrayList<MessageEmbed> messages = new ArrayList<>(); diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index a4caf74..dbee39b 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -16,10 +16,11 @@ public class MusicUtils { public static boolean checkIfConnected(MusicManager manager, CommandContext context) { if (context.getGuildUser().getVoiceState() == null) { + context.reply("Voice state is null, this should not happen"); throw new CommandExecutionException("Voice state is null, this should not happen", context, null); } - if (!context.getGuildUser().getVoiceState().inVoiceChannel()) { + if (!context.getGuildUser().getVoiceState().inAudioChannel()) { context.reply("You are not in a voice channel"); return false; } @@ -29,7 +30,7 @@ public class MusicUtils { return false; } - VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); + VoiceChannel vChannel = (VoiceChannel) context.getGuildUser().getVoiceState().getChannel(); if (manager.isNotConnectedTo(vChannel)) { context.reply("The bot isn't in your voice channel"); return false; From 90455b90c3cc6986b5247d99994a8e4cb31c9ff5 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 1 Oct 2022 11:41:07 -0400 Subject: [PATCH 099/155] Fixed a thread stuck scenario while trying to load unknown sources Fixed /skip command not executing because of a negation in the if statement Improved skip command by using the duplicate track detection --- .../command/music/SkipCommand.java | 2 +- .../netneutrality/music/MusicManager.java | 2 +- .../netneutrality/music/QueueManager.java | 35 ++++++------------- .../java/netneutrality/music/TrackLoader.java | 14 +++++--- .../music/TrackLoadingHandler.java | 32 ++++++++--------- .../netneutrality/music/TrackScheduler.java | 6 ++-- .../netneutrality/thread/ThreadManager.java | 19 +++++++--- 7 files changed, 57 insertions(+), 53 deletions(-) diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index ac22c57..1a9b679 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -74,7 +74,7 @@ public class SkipCommand extends AbstractMusicCommand { int skips = context.getEvent().getOption("skip", 0, OptionMapping::getAsInt); context.ackAndWait(); - if (!MusicUtils.checkIfConnected(manager, context)) { + if (MusicUtils.checkIfConnected(manager, context)) { if (skips > 0) { context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : "")); manager.getScheduler().getQueueManager().skip(skips); diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index f0f3b8f..b9e25b8 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -42,7 +42,7 @@ public class MusicManager { private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); private final static Map<String, MusicManager> managers = new ConcurrentHashMap<>(); - private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); + private final static ScheduledExecutorService executor = ThreadManager.getMusicExecutor(); private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); private final Guild guild; diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index b2f4518..016ee5a 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -46,16 +46,6 @@ public class QueueManager { } } - public void toggleSkip(Member member) { - if (hasSkip(member)) { - logger.debug("VoteSkip: user={}, skip already exist, before={}, after={}", member.getId(), skips.size(), skips.size() - 1); - skips.remove(member.getId()); - } else { - logger.debug("VoteSkip: user={}, skip doesn't exist, before={}, after={}", member.getId(), skips.size(), skips.size() + 1); - skips.add(member.getId()); - } - } - public boolean hasSkip(Member member) { return skips.contains(member.getId()); } @@ -134,9 +124,9 @@ public class QueueManager { } } - public TrackInfo pollHeadOfQueue() { + public void removeHeadOfQueue() { synchronized (queue) { - return queue.poll(); + queue.poll(); } } @@ -207,7 +197,7 @@ public class QueueManager { } } - public void playNextTrack(AudioPlayer player) { + public void startNextTrack() { synchronized (queue) { TrackInfo last = queue.poll(); TrackInfo next = queue.peek(); @@ -215,7 +205,7 @@ public class QueueManager { if (next != null) { if (last != null && last.getTrack().equals(next.getTrack())) { logger.debug("Guild {}: duplicate track in queue found, skipping to next. last={}, next={}", guild.getId(), last.getTrack().getIdentifier(), next.getTrack().getIdentifier()); - playNextTrack(player); + startNextTrack(); } else { player.startTrack(next.getTrack(), false); } @@ -223,7 +213,10 @@ public class QueueManager { player.stopTrack(); } } + } + public void skip() { + skip(1); } public void skip(int nbTrack) { @@ -241,18 +234,12 @@ public class QueueManager { nbTrack = 1; } - logger.debug("Guild {}: skipping tracks, toSkip={}", guild.getId(), nbTrack); - for (int i = 0; i < nbTrack; i++) { - TrackInfo last = queue.poll(); - } - - TrackInfo current = queue.peek(); - if (current != null) { - player.startTrack(current.getTrack(), false); - } else { - player.stopTrack(); + logger.debug("Guild {}: skipping {} tracks", guild.getId(), nbTrack); + for (int i = 1; i < nbTrack; i++) { + queue.poll(); } + startNextTrack(); } } diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/netneutrality/music/TrackLoader.java index 462f0f2..fff9fef 100644 --- a/src/main/java/netneutrality/music/TrackLoader.java +++ b/src/main/java/netneutrality/music/TrackLoader.java @@ -13,11 +13,14 @@ import netneutrality.music.loadable.CachedSource; import netneutrality.music.loadable.LoadableMusicSource; import netneutrality.music.loadable.LoadableSong; import netneutrality.thread.ThreadManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; public class TrackLoader implements Runnable { + private final Logger logger = LoggerFactory.getLogger(TrackLoader.class); private final CommandContext context; private final MusicManager musicManager; private final AudioPlayerManager audioPlayerManager; @@ -40,10 +43,10 @@ public class TrackLoader implements Runnable { public void loadAllSongs(List<LoadableSong> songs) { this.songs = songs; if (songs.size() > 1) { - silent = true; + this.silent = true; } - ThreadManager.getExecutor("Track loader").submit(this); + ThreadManager.getMusicExecutor().submit(this); } public void loadAllSongs(CachedSource cachedSource) { @@ -81,7 +84,7 @@ public class TrackLoader implements Runnable { totalNumberOfTracks++; - System.out.println("notify, loaded: " + numberOfTracksLoaded + ", total: " + totalNumberOfTracks); + logger.debug("callback notify; total={}, loaded={}", totalNumberOfTracks, numberOfTracksLoaded); sync.notify(); } @@ -90,6 +93,8 @@ public class TrackLoader implements Runnable { audioPlayerManager.loadItemOrdered(this, identifier, loadingHandler); } else { + totalNumberOfTracks++; + if (songs.size() == 1) { context.replyToMessage("No source found to play the given url"); } @@ -99,7 +104,7 @@ public class TrackLoader implements Runnable { try { synchronized (sync) { while (!(songs.size() == totalNumberOfTracks)) { - System.out.println("wait"); + logger.debug("waiting for load; size={}, total={}, loaded={}", songs.size(), totalNumberOfTracks, numberOfTracksLoaded); sync.wait(); } @@ -109,6 +114,7 @@ public class TrackLoader implements Runnable { } } } catch (InterruptedException exception) { + stopLoading(); LogHandler.log(exception); } diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index b61c956..52b467f 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -71,7 +71,7 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { } @Override - public void playlistLoaded(AudioPlaylist audioPlaylist) { + public void playlistLoaded(AudioPlaylist playlist) { if (loadConsumer != null) { loadConsumer.accept(true); } @@ -81,29 +81,29 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { } logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - if (!audioPlaylist.getTracks().isEmpty()) { - if (audioPlaylist.isSearchResult()) { - AudioTrack track = audioPlaylist.getTracks().get(0); + if (!playlist.getTracks().isEmpty()) { + if (playlist.isSearchResult()) { + + AudioTrack track = playlist.getTracks().get(0); scheduler.getQueueManager().queue(track, context.getGuildUser()); if (!silent) { context.reply(MessageFunction.buildAddingTrackMessage(track, type)); } - return; - } - - context.deleteMessage(); - if (!silent) { - context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, identifier, type)); - } - - for (AudioTrack track : audioPlaylist.getTracks()) { - if (loadingDisabled) { - break; + } else { + context.deleteMessage(); + if (!silent) { + context.reply(MessageFunction.buildAddingPlaylistMessage(playlist, identifier, type)); } - scheduler.getQueueManager().queue(track, context.getGuildUser()); + for (AudioTrack track : playlist.getTracks()) { + if (loadingDisabled) { + break; + } + + scheduler.getQueueManager().queue(track, context.getGuildUser()); + } } } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index dad5daf..0b9c387 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -99,11 +99,11 @@ public class TrackScheduler extends AudioEventAdapter { // check if mayStartNext if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { - queueManager.playNextTrack(player); + queueManager.startNextTrack(); } if (endReason == AudioTrackEndReason.STOPPED) { - queueManager.pollHeadOfQueue(); + queueManager.removeHeadOfQueue(); } // endReason == FINISHED: A track finished or died by an exception (mayStartNext = true). @@ -125,6 +125,6 @@ public class TrackScheduler extends AudioEventAdapter { public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { logger.debug("Guild {}: currently playing track is stuck: {}", guild.getId(), track.getIdentifier()); sendMessageToChannel("Current track is stuck, skipping to next"); - queueManager.playNextTrack(player); + queueManager.startNextTrack(); } } diff --git a/src/main/java/netneutrality/thread/ThreadManager.java b/src/main/java/netneutrality/thread/ThreadManager.java index 791bb54..335c44b 100644 --- a/src/main/java/netneutrality/thread/ThreadManager.java +++ b/src/main/java/netneutrality/thread/ThreadManager.java @@ -7,10 +7,7 @@ package netneutrality.thread; */ import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; public class ThreadManager { @@ -20,6 +17,20 @@ public class ThreadManager { private static final Map<String, ExecutorService> executors = new ConcurrentHashMap<>(); + public static ScheduledExecutorService getMusicExecutor() { + return (ScheduledExecutorService) executors.computeIfAbsent( + "music-executor", + s -> Executors.newScheduledThreadPool( + Runtime.getRuntime().availableProcessors(), + new BaseThreadFactory("music-executor") + ) + ); + } + + public static ExecutorService getExecutor() { + return executors.computeIfAbsent("general-executor", s -> Executors.newCachedThreadPool(new BaseThreadFactory("general-executor"))); + } + public static ExecutorService getExecutor(String name) { return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); } From d3683cc638f0eb30406a3131d38aff9ce6061a3c Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 6 Feb 2023 17:17:23 -0500 Subject: [PATCH 100/155] Update to latest alpha and make clone of track when playing next --- pom.xml | 2 +- .../java/netneutrality/NetNeutrality.java | 5 ++--- .../command/AbstractCommand.java | 2 +- .../command/AbstractMusicCommand.java | 6 +++++- .../java/netneutrality/command/ICommand.java | 2 +- .../command/admin/PurgeCommand.java | 2 +- .../command/bot/ConfigureCommand.java | 2 +- .../command/music/JoinCommand.java | 2 +- .../java/netneutrality/core/BotState.java | 11 ++-------- .../java/netneutrality/core/GuildManager.java | 21 ++++++++++--------- .../java/netneutrality/core/LogHandler.java | 2 +- .../core/context/CommandContext.java | 6 +++++- .../core/context/MessageCommandContext.java | 3 ++- .../core/context/SlashCommandContext.java | 6 +++++- .../db/controllers/DBMessage.java | 2 +- .../hooks/message/EditHandler.java | 2 +- .../hooks/message/MessageReceivedHandler.java | 2 +- .../netneutrality/music/MusicManager.java | 11 ++-------- .../netneutrality/music/QueueManager.java | 10 +++------ .../java/netneutrality/music/TrackLoader.java | 10 ++++++--- .../netneutrality/music/TrackScheduler.java | 2 +- .../MusicPlayerAutoDisconnectThread.java | 2 +- .../utils/ChannelMessagePurger.java | 6 +++--- .../netneutrality/utils/MessageFunction.java | 20 +++++++++++++++++- .../java/netneutrality/utils/MusicUtils.java | 2 +- .../netneutrality/utils/UserFunction.java | 7 ------- 26 files changed, 79 insertions(+), 69 deletions(-) diff --git a/pom.xml b/pom.xml index 4dd727e..65c50b4 100644 --- a/pom.xml +++ b/pom.xml @@ -108,7 +108,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-alpha.18</version> + <version>5.0.0-alpha.22</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 95acf1e..330f31d 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -5,6 +5,7 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.exceptions.InvalidTokenException; import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.core.CommandManager; import netneutrality.core.LogHandler; @@ -24,8 +25,6 @@ import org.apache.logging.log4j.core.config.Configurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.security.auth.login.LoginException; - public class NetNeutrality { private static JDA jda; @@ -68,7 +67,7 @@ public class NetNeutrality { .setActivity(Activity.watching("me load...")) .build(); jda.awaitReady(); - } catch (LoginException | IllegalArgumentException | InterruptedException e) { + } catch (InvalidTokenException | IllegalArgumentException | InterruptedException e) { Sentry.captureException(e); LogHandler.log(e); diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 68575d2..0541a40 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -2,7 +2,7 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import netneutrality.core.context.MessageCommandContext; diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 61ec61a..da44b66 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -6,7 +6,11 @@ package netneutrality.command; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.GuildManager; import netneutrality.db.GSettings; import netneutrality.utils.UserFunction; diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index bb8b86c..3cd2156 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -8,7 +8,7 @@ package netneutrality.command; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.core.context.MessageCommandContext; diff --git a/src/main/java/netneutrality/command/admin/PurgeCommand.java b/src/main/java/netneutrality/command/admin/PurgeCommand.java index a4ddd6d..2d43587 100644 --- a/src/main/java/netneutrality/command/admin/PurgeCommand.java +++ b/src/main/java/netneutrality/command/admin/PurgeCommand.java @@ -6,7 +6,7 @@ package netneutrality.command.admin; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.GuildMessageChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 42b1cc8..95a9939 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -7,7 +7,7 @@ package netneutrality.command.bot; */ import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionMapping; diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 10d044a..8a3d7c0 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -7,7 +7,7 @@ package netneutrality.command.music; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; import netneutrality.core.context.MessageCommandContext; diff --git a/src/main/java/netneutrality/core/BotState.java b/src/main/java/netneutrality/core/BotState.java index dd06023..705aa89 100644 --- a/src/main/java/netneutrality/core/BotState.java +++ b/src/main/java/netneutrality/core/BotState.java @@ -1,11 +1,4 @@ -package netneutrality.core;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - - +package netneutrality.core; /* * Copyright (c) anthorob * @@ -13,7 +6,7 @@ package netneutrality.core;/* * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.music.MusicManager; import netneutrality.music.TrackScheduler; import org.json.JSONArray; diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 32708b4..b96ce65 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -9,7 +9,7 @@ package netneutrality.core; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.NetNeutrality; import netneutrality.db.DBController; import netneutrality.db.GSettings; @@ -84,14 +84,6 @@ public class GuildManager { return managers; } - public boolean isLoggingEnabled() { - return guildEntity.getLogging(); - } - - public boolean isDebugEnabled() { - return guildEntity.getDebug(); - } - public Guild getGuild() { return guild; } @@ -108,6 +100,15 @@ public class GuildManager { return settingsCache; } + // Methods + public boolean isLoggingEnabled() { + return guildEntity.getLogging(); + } + + public boolean isDebugEnabled() { + return guildEntity.getDebug(); + } + public String getSetting(GSettings setting) { String value = settingsCache.get(setting.getName()); @@ -196,7 +197,7 @@ public class GuildManager { public void checkAndLogMessage(Message message, Member member, TextChannel channel) { if (isLoggingEnabled()) { - ThreadManager.getExecutor("log-messages").submit(() -> DBController.get(DBMessage.class).log(this, channel, member, message)); + ThreadManager.getExecutor().submit(() -> DBController.get(DBMessage.class).log(this, channel, member, message)); } } diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 3208447..990e4ca 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -8,7 +8,7 @@ package netneutrality.core; import io.sentry.Sentry; import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index cf74a97..6ff37df 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -6,7 +6,11 @@ package netneutrality.core.context;/* */ import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.Event; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import netneutrality.command.AbstractCommand; diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java index 294ffcd..70f4b2e 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -10,6 +10,7 @@ import io.sentry.Breadcrumb; import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import netneutrality.command.AbstractCommand; @@ -26,7 +27,7 @@ import java.util.concurrent.TimeUnit; public class MessageCommandContext implements CommandContext { - private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED); + private static final ExecutorService commandExecutor = ThreadManager.getExecutor(); private AbstractCommand command; private final MessageReceivedEvent event; diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java index bfab32e..f444eaf 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -7,7 +7,11 @@ package netneutrality.core.context;/* import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.InteractionHook; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 84d2641..5b399cf 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -9,7 +9,7 @@ package netneutrality.db.controllers; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.core.GuildManager; import netneutrality.db.AbstractController; import netneutrality.db.entities.OLogMessage; diff --git a/src/main/java/netneutrality/hooks/message/EditHandler.java b/src/main/java/netneutrality/hooks/message/EditHandler.java index 4637c14..befd9c1 100644 --- a/src/main/java/netneutrality/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/hooks/message/EditHandler.java @@ -7,7 +7,7 @@ package netneutrality.hooks.message; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.core.GuildManager; diff --git a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java index 9946879..31cd7e5 100644 --- a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java @@ -11,7 +11,7 @@ import io.sentry.Sentry; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.command.AbstractCommand; diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index b9e25b8..3613295 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -15,12 +15,11 @@ import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import netneutrality.core.GuildManager; import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; -import netneutrality.core.context.SlashCommandContext; import netneutrality.db.GSettings; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.loadable.LoadableSong; @@ -155,12 +154,6 @@ public class MusicManager { } } - public boolean restoreQueue(List<String> track) { - //TODO: todo - - return false; - } - public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { logger.debug("Guild {}: request to play {} by user {}", guild.getId(), url, context.getGuildUser().getId()); diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 016ee5a..0901f4f 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -1,4 +1,5 @@ -package netneutrality.music;/* +package netneutrality.music; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -203,12 +204,7 @@ public class QueueManager { TrackInfo next = queue.peek(); if (next != null) { - if (last != null && last.getTrack().equals(next.getTrack())) { - logger.debug("Guild {}: duplicate track in queue found, skipping to next. last={}, next={}", guild.getId(), last.getTrack().getIdentifier(), next.getTrack().getIdentifier()); - startNextTrack(); - } else { - player.startTrack(next.getTrack(), false); - } + player.startTrack(next.getTrack().makeClone(), false); } else { player.stopTrack(); } diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/netneutrality/music/TrackLoader.java index fff9fef..204a2df 100644 --- a/src/main/java/netneutrality/music/TrackLoader.java +++ b/src/main/java/netneutrality/music/TrackLoader.java @@ -16,6 +16,7 @@ import netneutrality.thread.ThreadManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.List; public class TrackLoader implements Runnable { @@ -65,8 +66,11 @@ public class TrackLoader implements Runnable { @Override public void run() { + List<LoadableSong> copy = new ArrayList<>(songs); + for (LoadableSong song : songs) { if (loadingDisabled) { + copy.remove(song); break; } @@ -93,7 +97,7 @@ public class TrackLoader implements Runnable { audioPlayerManager.loadItemOrdered(this, identifier, loadingHandler); } else { - totalNumberOfTracks++; + copy.remove(song); if (songs.size() == 1) { context.replyToMessage("No source found to play the given url"); @@ -103,13 +107,13 @@ public class TrackLoader implements Runnable { try { synchronized (sync) { - while (!(songs.size() == totalNumberOfTracks)) { + while (!(copy.size() == totalNumberOfTracks)) { logger.debug("waiting for load; size={}, total={}, loaded={}", songs.size(), totalNumberOfTracks, numberOfTracksLoaded); sync.wait(); } //TODO: logic - if (songs.size() > 1 && source != null && !loadingDisabled) { + if (copy.size() > 1 && source != null && !loadingDisabled) { context.replyToMessage("Loaded %d of %d tracks from online source", numberOfTracksLoaded, totalNumberOfTracks); } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 0b9c387..c738c4b 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -13,7 +13,7 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.core.LogHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index f24a2e6..4c65371 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -7,7 +7,7 @@ package netneutrality.thread;/* import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import netneutrality.NetNeutrality; import netneutrality.music.MusicManager; import org.slf4j.LoggerFactory; diff --git a/src/main/java/netneutrality/utils/ChannelMessagePurger.java b/src/main/java/netneutrality/utils/ChannelMessagePurger.java index 2cdd5ee..40aab16 100644 --- a/src/main/java/netneutrality/utils/ChannelMessagePurger.java +++ b/src/main/java/netneutrality/utils/ChannelMessagePurger.java @@ -10,9 +10,9 @@ import io.sentry.ISpan; import io.sentry.ITransaction; import io.sentry.Sentry; import io.sentry.SpanStatus; -import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageHistory; +import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import netneutrality.core.context.CommandContext; import netneutrality.thread.ThreadManager; @@ -50,7 +50,7 @@ public class ChannelMessagePurger { } public void purgeMessages(CommandContext context, int toPurge) { - ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { + ThreadManager.getExecutor().submit(() -> { if (lock.tryLock()) { try { int total = countAllChannelMessages(channel); @@ -69,7 +69,7 @@ public class ChannelMessagePurger { } public void purgeChannel(CommandContext context) { - ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { + ThreadManager.getExecutor().submit(() -> { if (lock.tryLock()) { try { int total = countAllChannelMessages(channel); diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 8fbca70..cd90d77 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -11,7 +11,11 @@ import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; import netneutrality.core.CommandManager; @@ -94,6 +98,20 @@ public class MessageFunction { return message.build(); } + public static MessageEmbed buildSearchResultsMessage(List<AudioTrack> tracks) { + EmbedBuilder message = new EmbedBuilder(); + + message.setTitle("Select the track to add to the queue"); + message.setColor(Color.BLUE); + + int i = 0; + for (AudioTrack track : tracks) { + message.addField(++i + ": ", String.format("**`%s`**", track.getInfo().title), false); + } + + return message.build(); + } + public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, String identifier, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); String url = identifier; diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index dbee39b..3f5fa2a 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -7,7 +7,7 @@ package netneutrality.utils; */ import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/netneutrality/utils/UserFunction.java index 8eee156..cb33152 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/netneutrality/utils/UserFunction.java @@ -7,13 +7,6 @@ import net.dv8tion.jda.api.entities.Role; public class UserFunction { public static boolean isAdmin(Member user) { - - // This check will only be present during the development of the bot - String creatorId = Settings.getInstance().getCreatorId(); - if (creatorId != null && user.getId().equals(creatorId)) { - return true; - } - boolean isAdmin = false; for(Role role : user.getRoles()) { if (role.getPermissions().contains(Permission.MANAGE_SERVER) || role.getPermissions().contains(Permission.ADMINISTRATOR)) From a214244016d54f646592e37b9060fe10e65eee8c Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 6 Feb 2023 17:30:40 -0500 Subject: [PATCH 101/155] Updates dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 65c50b4..8a00de0 100644 --- a/pom.xml +++ b/pom.xml @@ -108,7 +108,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-alpha.22</version> + <version>5.0.0-beta.2</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> @@ -118,7 +118,7 @@ <dependency> <groupId>com.github.walkyst</groupId> <artifactId>lavaplayer-fork</artifactId> - <version>1.3.98.4</version> + <version>1.3.99.2</version> </dependency> <dependency> From c71b246dc0f660c2dce24ec1a0d6b8d0d8f006dd Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 6 Feb 2023 17:42:14 -0500 Subject: [PATCH 102/155] Fix build errors --- .../command/admin/BlacklistCommand.java | 2 +- .../command/bot/ConfigureCommand.java | 2 +- .../command/music/QueueCommand.java | 2 +- .../hooks/voice/VoiceEventHandler.java | 18 +++--------------- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/java/netneutrality/command/admin/BlacklistCommand.java b/src/main/java/netneutrality/command/admin/BlacklistCommand.java index 6762834..cf8fff1 100644 --- a/src/main/java/netneutrality/command/admin/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/admin/BlacklistCommand.java @@ -77,7 +77,7 @@ public class BlacklistCommand extends AbstractCommand { @Override public void execute(SlashCommandContext context) { - String sub = context.getEvent().getCommandPath().split("/")[1]; + String sub = context.getEvent().getFullCommandName().split(" ")[1]; DBBlacklist controller = DBController.get(DBBlacklist.class); String word = context.getEvent().getOption("word", "", OptionMapping::getAsString); context.ackAndWait(true); diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 95a9939..db8940c 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -209,7 +209,7 @@ public class ConfigureCommand extends AbstractCommand { @Override public void execute(SlashCommandContext context) { - String sub = context.getEvent().getCommandPath().split("/")[1]; + String sub = context.getEvent().getFullCommandName().split(" ")[1]; GuildManager guildManager = GuildManager.getManager(context.getGuild()); context.ackAndWait(true); diff --git a/src/main/java/netneutrality/command/music/QueueCommand.java b/src/main/java/netneutrality/command/music/QueueCommand.java index 5bc534c..53728ef 100644 --- a/src/main/java/netneutrality/command/music/QueueCommand.java +++ b/src/main/java/netneutrality/command/music/QueueCommand.java @@ -107,7 +107,7 @@ public class QueueCommand extends AbstractMusicCommand { public void execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); - String sub = context.getEvent().getCommandPath().split("/")[1]; + String sub = context.getEvent().getFullCommandName().split(" ")[1]; if (!MusicUtils.checkIfConnected(manager, context)) { return; diff --git a/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java b/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java index 3bc75c3..0ef6fe4 100644 --- a/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java +++ b/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java @@ -6,26 +6,14 @@ package netneutrality.hooks.voice; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent; -import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; -import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; public class VoiceEventHandler extends ListenerAdapter { @Override - public void onGuildVoiceJoin(@NotNull GuildVoiceJoinEvent event) { - super.onGuildVoiceJoin(event); - } - - @Override - public void onGuildVoiceMove(@NotNull GuildVoiceMoveEvent event) { - super.onGuildVoiceMove(event); - } - - @Override - public void onGuildVoiceLeave(@NotNull GuildVoiceLeaveEvent event) { - super.onGuildVoiceLeave(event); + public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { + super.onGuildVoiceUpdate(event); } } From 744abf204e4c903b092bb7536d38367fe7b59f4f Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 23 Mar 2023 20:30:28 -0400 Subject: [PATCH 103/155] bug fix for voice connection --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a00de0..9db0808 100644 --- a/pom.xml +++ b/pom.xml @@ -108,7 +108,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.2</version> + <version>5.0.0-beta.6</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> From b2d1daf9c36e16e594a4f55b3483ad6ec7706a06 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 23 Mar 2023 20:38:32 -0400 Subject: [PATCH 104/155] Remove admin check for slash commands --- src/main/java/netneutrality/command/music/LeaveCommand.java | 5 ----- .../java/netneutrality/core/context/SlashCommandContext.java | 5 ----- 2 files changed, 10 deletions(-) diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index f62e07d..d23e940 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -16,11 +16,6 @@ import netneutrality.utils.MusicUtils; public class LeaveCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } - @Override public boolean isEnabled() { return true; diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java index f444eaf..a86a4e7 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -188,11 +188,6 @@ public class SlashCommandContext implements CommandContext { }); try { - if (command.needAdmin() && !UserFunction.isAdmin(member)) { - replyEphemeral("You are not powerful enough, scrub"); - return; - } - if (command.canBeExecutedBy(guild, member)) { command.execute(this); } From b4fe1c7b7393c7fe87d5c94243e7d147064bb265 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Wed, 24 May 2023 13:23:04 -0400 Subject: [PATCH 105/155] Add support for Youtube Music links --- src/main/java/netneutrality/music/SourceFinder.java | 10 ++++++++-- src/main/java/netneutrality/utils/MessageFunction.java | 10 +++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index e18eb07..b78073d 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -14,6 +14,7 @@ public class SourceFinder { public enum AudioSourceType { Youtube, + YTMusic, Soundcloud, Bandcamp, Vimeo, @@ -22,17 +23,22 @@ public class SourceFinder { } - private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); + private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-zA-Z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); + private static final Pattern youtubeMusicPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?music\\.(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-zA-Z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); private static Matcher twitchMatcher; public static AudioSourceType getSource(String url) { Matcher youtubeMatcher = youtubePattern.matcher(url); + Matcher youtubeMusicMatcher = youtubeMusicPattern.matcher(url); Matcher soundcloudMatcher = soundcloudPattern.matcher(url); if (youtubeMatcher.find()) return AudioSourceType.Youtube; + if (youtubeMusicMatcher.find()) + return AudioSourceType.YTMusic; + if (soundcloudMatcher.find()) return AudioSourceType.Soundcloud; @@ -46,7 +52,7 @@ public class SourceFinder { String identifier; identifier = switch (getSource(url)) { - case Youtube, Soundcloud -> url; + case Youtube, YTMusic, Soundcloud -> url; case YTSearch -> "ytsearch:" + url; default -> null; }; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index cd90d77..c3be185 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -83,7 +83,7 @@ public class MessageFunction { if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { url = String.format("https://youtu.be/%s", track.getIdentifier()); - thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier()); + thumbnail = String.format("https://i3.ytimg.com/vi/%s/hqdefault.jpg", track.getIdentifier()); } if (thumbnail != null) { @@ -118,8 +118,12 @@ public class MessageFunction { String thumbnail = null; if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { - url = String.format("https://youtu.be/%s", playlist.getSelectedTrack().getIdentifier()); - thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier()); + url = String.format("https://youtu.be/%s", playlist.getTracks().get(0).getIdentifier()); + thumbnail = String.format("https://i3.ytimg.com/vi/%s/hqdefault.jpg", playlist.getTracks().get(0).getIdentifier()); + } + + if (type == SourceFinder.AudioSourceType.YTMusic) { + thumbnail = String.format("https://i3.ytimg.com/vi/%s/hqdefault.jpg", playlist.getTracks().get(0).getIdentifier()); } if (thumbnail != null) { From 55ad8657078ea72bc0ed186f03a0590f7e799b4b Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Wed, 24 May 2023 16:15:33 -0400 Subject: [PATCH 106/155] Fix permission errors in Dockerfile and update docker-compose.yml --- Dockerfile | 2 ++ docker-compose.yml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 86d2c03..21f8be2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,8 @@ COPY src ./src COPY bot.properties.example bot.properties ./ COPY startup.sh ./ +RUN ["chmod", "+x", "./mvnw"] RUN ./mvnw install +RUN ["chmod", "+x", "./startup.sh"] CMD ["./startup.sh"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 15a9e7b..9cbe57e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: db: image: mariadb:10.7 container_name: db - restart: always + restart: unless-stopped volumes: - netneutrality-db:/var/lib/mysql - ./sql:/docker-entrypoint-initdb.d @@ -21,7 +21,7 @@ services: bot: container_name: bot build: ./ - restart: always + restart: unless-stopped depends_on: - db environment: From 38bd0cd4e29d8cd5c7f434f42f86080202775dff Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Thu, 17 Aug 2023 15:10:44 -0400 Subject: [PATCH 107/155] burn the corporations --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 9db0808..de3daad 100644 --- a/pom.xml +++ b/pom.xml @@ -102,13 +102,13 @@ <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>3.4.2</version> + <version>3.6.0</version> </dependency> <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.6</version> + <version>5.0.0-beta.12</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> @@ -118,7 +118,7 @@ <dependency> <groupId>com.github.walkyst</groupId> <artifactId>lavaplayer-fork</artifactId> - <version>1.3.99.2</version> + <version>1.4.3</version> </dependency> <dependency> @@ -140,7 +140,7 @@ <dependency> <groupId>io.sentry</groupId> <artifactId>sentry</artifactId> - <version>6.4.0</version> + <version>6.16.0</version> </dependency> <dependency> <groupId>p6spy</groupId> @@ -152,7 +152,7 @@ <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> - <version>20220320</version> + <version>20230227</version> </dependency> <dependency> @@ -164,17 +164,17 @@ <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>8.0.30</version> + <version>8.0.33</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> - <version>2.18.0</version> + <version>2.20.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> - <version>2.18.0</version> + <version>2.20.0</version> </dependency> <dependency> From 93437ab8aaa3a1afd1e5da2a7f626667d4bf7725 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Wed, 20 Dec 2023 20:54:00 -0500 Subject: [PATCH 108/155] Various things and fixes --- pom.xml | 2 +- .../command/AbstractMusicCommand.java | 6 +- .../java/netneutrality/command/ICommand.java | 1 + .../command/bot/ConfigureCommand.java | 32 +++---- .../java/netneutrality/core/BotState.java | 4 +- .../core/GuildConfigManager.java | 96 +++++++++++++++++++ .../java/netneutrality/core/GuildManager.java | 87 ++--------------- .../java/netneutrality/core/LogHandler.java | 11 +++ .../core/context/CommandContext.java | 2 + .../core/context/MessageCommandContext.java | 8 +- .../core/context/SlashCommandContext.java | 2 - .../db/controllers/DBBlacklist.java | 40 +++++--- .../db/controllers/DBMessage.java | 5 +- .../exceptions/CommandException.java | 2 +- .../hooks/message/EditHandler.java | 3 +- .../hooks/message/MessageReceivedHandler.java | 21 +--- .../http/server/ActionHandler.java | 8 +- .../netneutrality/music/MusicManager.java | 10 +- .../java/netneutrality/music/TrackLoader.java | 1 + .../netneutrality/music/TrackScheduler.java | 7 +- .../MusicPlayerAutoDisconnectThread.java | 27 ++++-- .../java/netneutrality/utils/JpaUtils.java | 15 +-- .../netneutrality/utils/MessageFunction.java | 29 +----- 23 files changed, 222 insertions(+), 197 deletions(-) create mode 100644 src/main/java/netneutrality/core/GuildConfigManager.java diff --git a/pom.xml b/pom.xml index de3daad..ae0bfa9 100644 --- a/pom.xml +++ b/pom.xml @@ -108,7 +108,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.12</version> + <version>5.0.0-beta.18</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index da44b66..25bb332 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -34,7 +34,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getGuildConfigManager().getSetting(GSettings.MUSIC_ROLE); if (roleDb != null && !roleDb.isEmpty()) { if (UserFunction.isAdmin(member)) { @@ -44,7 +44,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { Role neededRole = guild.getRoleById(roleDb); if (neededRole == null) { // Role doesn't exist on guild anymore, remove from db - GuildManager.getManager(guild).setSettingValue(GSettings.MUSIC_ROLE, null); + GuildManager.getManager(guild).getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, null); return true; } @@ -59,7 +59,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { if (channel.getType() != ChannelType.TEXT) return false; - String channelDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_CHANNEL); + String channelDb = GuildManager.getManager(guild).getGuildConfigManager().getSetting(GSettings.MUSIC_CHANNEL); if (channelDb != null && !channelDb.isEmpty()) { return channelDb.equals(channel.getId()); diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 3cd2156..bc3f73a 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -38,6 +38,7 @@ public interface ICommand { boolean canBeExecutedFrom(Guild guild, MessageChannel channel); + @Deprecated void execute(MessageCommandContext context); void execute(SlashCommandContext context); diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index db8940c..861bd69 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -89,7 +89,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-role")) { if (args.length == 1) { - String roleDb = guildManager.getSetting(GSettings.MUSIC_ROLE); + String roleDb = guildManager.getGuildConfigManager().getSetting(GSettings.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -101,8 +101,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GSettings.MUSIC_ROLE).isEmpty()) { - guildManager.setSettingValue(GSettings.MUSIC_ROLE, null); + if (!guildManager.getGuildConfigManager().getSetting(GSettings.MUSIC_ROLE).isEmpty()) { + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, null); } context.reply("Successful reset of the role"); @@ -112,7 +112,7 @@ public class ConfigureCommand extends AbstractCommand { if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GSettings.MUSIC_ROLE, role.getId()); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, role.getId()); context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } @@ -122,7 +122,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-channel")) { if (args.length == 1) { - String channelDb = guildManager.getSetting(GSettings.MUSIC_CHANNEL); + String channelDb = guildManager.getGuildConfigManager().getSetting(GSettings.MUSIC_CHANNEL); TextChannel channel = null; if (!channelDb.isEmpty()) { channel = context.getGuild().getTextChannelById(channelDb); @@ -134,8 +134,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GSettings.MUSIC_CHANNEL).isEmpty()) { - guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, null); + if (!guildManager.getGuildConfigManager().getSetting(GSettings.MUSIC_CHANNEL).isEmpty()) { + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_CHANNEL, null); } context.reply("Successful reset of the channel"); @@ -145,7 +145,7 @@ public class ConfigureCommand extends AbstractCommand { if (channels.size() == 1) { TextChannel channel = channels.get(0); if (channel.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); context.reply("Successfully set %s as the channel required to execute music command", channel.getAsMention()); } } @@ -155,7 +155,7 @@ public class ConfigureCommand extends AbstractCommand { // Default volume for music player if (context.getArgument(0).equals("music-volume")) { if (args.length == 1) { - int volume = Integer.parseInt(guildManager.getSetting(GSettings.MUSIC_VOLUME)); + int volume = Integer.parseInt(guildManager.getGuildConfigManager().getSetting(GSettings.MUSIC_VOLUME)); context.reply("Default volume for music player: %d", volume); context.reply("Set using 'conf music-volume <value between 0 and 100>'"); @@ -166,7 +166,7 @@ public class ConfigureCommand extends AbstractCommand { int volume = Integer.parseInt(args[1]); if (volume > 0 && volume <= 100) { - guildManager.setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); context.reply("Default volume for music player is now %d", volume); @@ -218,13 +218,13 @@ public class ConfigureCommand extends AbstractCommand { assert role != null; if (role.getPosition() == -1) { - guildManager.setSettingValue(GSettings.MUSIC_ROLE, null); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, null); context.replyEphemeral("Everyone can now use music commands"); return; } if (role.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GSettings.MUSIC_ROLE, role.getId()); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, role.getId()); context.replyEphemeral("Successfully set %s as the role needed for music command", role.getAsMention()); return; } @@ -234,14 +234,14 @@ public class ConfigureCommand extends AbstractCommand { GuildChannelUnion channel = context.getEvent().getOption("channel", OptionMapping::getAsChannel); if (channel == null) { - guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, null); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_CHANNEL, null); context.replyEphemeral("No channel restrictions for music commands"); return; } if (channel instanceof TextChannel) { if (channel.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); context.replyEphemeral("Successfully set %s as the channel required to execute music command", channel.getAsMention()); return; } @@ -251,7 +251,7 @@ public class ConfigureCommand extends AbstractCommand { if ("music-volume".equals(sub)) { int volume = context.getEvent().getOption("volume", 30, OptionMapping::getAsInt); - guildManager.setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); + guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); context.replyEphemeral("Default volume for music player is now %d", volume); @@ -267,7 +267,7 @@ public class ConfigureCommand extends AbstractCommand { } if ("show-all".equals(sub)) { - Map<String, String> settings = guildManager.getSettings(); + Map<String, String> settings = guildManager.getGuildConfigManager().getSettings(); MessageCreateBuilder builder = new MessageCreateBuilder(); for (GSettings o : GSettings.values()) { diff --git a/src/main/java/netneutrality/core/BotState.java b/src/main/java/netneutrality/core/BotState.java index 705aa89..dd402f7 100644 --- a/src/main/java/netneutrality/core/BotState.java +++ b/src/main/java/netneutrality/core/BotState.java @@ -6,7 +6,7 @@ package netneutrality.core; * https://discord.gg/CdFcyQ */ -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.music.MusicManager; import netneutrality.music.TrackScheduler; import org.json.JSONArray; @@ -35,7 +35,7 @@ public class BotState { JSONObject music = new JSONObject(); guild.put("id", manager.getGuild().getId()); - TextChannel currentChannel = trackScheduler.getTextChannel(); + MessageChannel currentChannel = trackScheduler.getTextChannel(); if (currentChannel == null) { music.put("current_channel", "null"); } else { diff --git a/src/main/java/netneutrality/core/GuildConfigManager.java b/src/main/java/netneutrality/core/GuildConfigManager.java new file mode 100644 index 0000000..cb36d2f --- /dev/null +++ b/src/main/java/netneutrality/core/GuildConfigManager.java @@ -0,0 +1,96 @@ +package netneutrality.core;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.Guild; +import netneutrality.db.GSettings; +import netneutrality.db.entities.OGuild; +import netneutrality.db.entities.OGuildSetting; +import netneutrality.utils.JpaUtils; +import org.hibernate.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class GuildConfigManager { + + private static final Logger logger = LoggerFactory.getLogger(GuildConfigManager.class); + private final Guild guild; + private final OGuild guildEntity; + + private final Map<String, String> settingsCache = new HashMap<>(); + + public GuildConfigManager(Guild guild, OGuild guildEntity) { + this.guild = guild; + this.guildEntity = guildEntity; + + reloadSettingsCache(); + } + + public Map<String, String> getSettings() { + return settingsCache; + } + + public String getSetting(GSettings setting) { + String value = settingsCache.get(setting.getName()); + + if (value == null) { + value = setting.getDefaultValue(); + } + + return value; + } + + + public void setSettingValue(GSettings setting, String value) { + Session session = SessionManager.getSessionFactory().openSession(); + JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); + + OGuildSetting oGuildSetting = guildEntity.getSettingByName(setting.getName()); + + session.beginTransaction(); + if (value == null || setting.getDefaultValue().equals(value)) { + if (oGuildSetting != null) { + session.delete(oGuildSetting); + } + } else { + if (oGuildSetting == null) { + oGuildSetting = new OGuildSetting(); + oGuildSetting.setGuild(guildEntity); + oGuildSetting.setName(setting.getName()); + oGuildSetting.setValue(value); + + session.save(oGuildSetting); + } else { + oGuildSetting.setValue(value); + + session.update(oGuildSetting); + } + } + + session.getTransaction().commit(); + session.close(); + + reloadSettingsCache(); + } + + public void reloadSettingsCache() { + logger.debug("Reloading settings cache for guild: " + guild.getId()); + settingsCache.clear(); + + JpaUtils.getWithSession(guildEntity, session -> { + Set<OGuildSetting> settingSet = guildEntity.getGuildSettings(); + + for (OGuildSetting setting : settingSet) { + settingsCache.put(setting.getName(), setting.getValue()); + } + }); + } + +} diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index b96ce65..d195aad 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -9,14 +9,12 @@ package netneutrality.core; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.NetNeutrality; import netneutrality.db.DBController; -import netneutrality.db.GSettings; import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OBlacklist; import netneutrality.db.entities.OGuild; -import netneutrality.db.entities.OGuildSetting; import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; @@ -25,7 +23,6 @@ import org.hibernate.SessionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -36,18 +33,18 @@ public class GuildManager { private static final Logger logger = LoggerFactory.getLogger(GuildManager.class); private static final Map<String, GuildManager> managers = new ConcurrentHashMap<>(); private static final SessionFactory sessionFactory = SessionManager.getSessionFactory(); - private final Map<String, String> settingsCache = new HashMap<>(); private final Set<String> blacklistCache = new HashSet<>(); + private final GuildConfigManager guildConfigManager; private final Guild guild; private OGuild guildEntity; private GuildManager(Guild guild) { this.guild = guild; this.guildEntity = loadGuildFromDb(guild.getId()); + this.guildConfigManager = new GuildConfigManager(guild, this.guildEntity); managers.put(guild.getId(), this); reloadBlacklistCache(); - reloadSettingsCache(); } private GuildManager(String guildId) { @@ -57,10 +54,10 @@ public class GuildManager { this.guild = temp; this.guildEntity = loadGuildFromDb(guild.getId()); + this.guildConfigManager = new GuildConfigManager(guild, this.guildEntity); managers.put(guild.getId(), this); reloadBlacklistCache(); - reloadSettingsCache(); } public static GuildManager getManager(Guild guild) { @@ -96,8 +93,8 @@ public class GuildManager { return blacklistCache; } - public Map<String, String> getSettings() { - return settingsCache; + public GuildConfigManager getGuildConfigManager() { + return guildConfigManager; } // Methods @@ -109,47 +106,6 @@ public class GuildManager { return guildEntity.getDebug(); } - public String getSetting(GSettings setting) { - String value = settingsCache.get(setting.getName()); - - if (value == null) { - value = setting.getDefaultValue(); - } - - return value; - } - - public void setSettingValue(GSettings setting, String value) { - Session session = sessionFactory.openSession(); - JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); - - OGuildSetting oGuildSetting = guildEntity.getSettingByName(setting.getName()); - - session.beginTransaction(); - if (value == null || setting.getDefaultValue().equals(value)) { - if (oGuildSetting != null) { - session.delete(oGuildSetting); - } - } else { - if (oGuildSetting == null) { - oGuildSetting = new OGuildSetting(); - oGuildSetting.setGuild(guildEntity); - oGuildSetting.setName(setting.getName()); - oGuildSetting.setValue(value); - - session.save(oGuildSetting); - } else { - oGuildSetting.setValue(value); - - session.update(oGuildSetting); - } - } - - session.getTransaction().commit(); - reloadSettingsCache(false); - session.close(); - } - public void setDebug(boolean toggle) { if (toggle == isDebugEnabled()) return; @@ -157,30 +113,11 @@ public class GuildManager { JpaUtils.updateWithTransaction(guildEntity, () -> guildEntity.setDebug(toggle)); } - public boolean reloadSettingsCache(boolean close) { - logger.debug("Reloading settings cache for guild: " + guild.getId()); - settingsCache.clear(); - - JpaUtils.getWithSession(guildEntity, close, session -> { - Set<OGuildSetting> settingSet = guildEntity.getGuildSettings(); - - for (OGuildSetting setting : settingSet) { - settingsCache.put(setting.getName(), setting.getValue()); - } - }); - - return true; - } - - public boolean reloadSettingsCache() { - return reloadSettingsCache(true); - } - - public void reloadBlacklistCache(boolean close) { + public void reloadBlacklistCache() { logger.debug("Reloading blacklist cache for guild: " + guild.getId()); blacklistCache.clear(); - JpaUtils.getWithSession(guildEntity, close, session -> { + JpaUtils.getWithSession(guildEntity, session -> { Set<OBlacklist> oBlacklistSet = guildEntity.getBlacklists(); for (OBlacklist bl : oBlacklistSet) { @@ -191,17 +128,13 @@ public class GuildManager { }); } - public void reloadBlacklistCache() { - reloadBlacklistCache(true); - } - - public void checkAndLogMessage(Message message, Member member, TextChannel channel) { + public void checkAndLogMessage(Message message, Member member, MessageChannel channel) { if (isLoggingEnabled()) { ThreadManager.getExecutor().submit(() -> DBController.get(DBMessage.class).log(this, channel, member, message)); } } - public void checkBlacklist(Message message, TextChannel channel) { + public void checkBlacklist(Message message, MessageChannel channel) { MessageFunction.testMessageAgainstBlacklist(message, channel, blacklistCache); } diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 990e4ca..ba11ac9 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -10,6 +10,7 @@ import io.sentry.Sentry; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import netneutrality.core.context.CommandContext; +import netneutrality.core.context.SlashCommandContext; import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.utils.MessageFunction; @@ -30,6 +31,8 @@ public class LogHandler { Sentry.captureException(e); logInternally((CommandExecutionException) e); tryLogToDebugChannel((CommandExecutionException) e); + tryGracefulSlashContextError((CommandExecutionException) e); + return; } @@ -75,4 +78,12 @@ public class LogHandler { } } } + + private static void tryGracefulSlashContextError(CommandExecutionException error) { + CommandContext context = error.getCommandContext(); + + if (context instanceof SlashCommandContext slashCommandContext) { + slashCommandContext.replyEphemeral("Error during command execution"); + } + } } diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 6ff37df..4e2db05 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -52,4 +52,6 @@ public interface CommandContext { default void replyToMessage(String format, Object... arguments) { replyToMessage(String.format(format, arguments)); } + + void dispatchToCommand(String commandName); } diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java index 70f4b2e..32eb42c 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -14,6 +14,7 @@ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import netneutrality.command.AbstractCommand; +import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; import netneutrality.core.LogHandler; import netneutrality.exceptions.CommandExecutionException; @@ -193,7 +194,12 @@ public class MessageCommandContext implements CommandContext { return creatorId.equals(member.getId()); } - public void dispatch(AbstractCommand command) { + public void dispatchToCommand(String commandName) { + if (!CommandManager.isValidCommand(commandName)) { + return; + } + + AbstractCommand command = CommandManager.getCommand(commandName); this.command = command; //TODO: Add usage check diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java index a86a4e7..775301f 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -21,7 +21,6 @@ import netneutrality.command.AbstractCommand; import netneutrality.core.CommandManager; import netneutrality.core.LogHandler; import netneutrality.exceptions.CommandExecutionException; -import netneutrality.utils.UserFunction; import java.util.Collection; @@ -180,7 +179,6 @@ public class SlashCommandContext implements CommandContext { Sentry.configureScope(scope -> { scope.setContexts("command", command.getCommandName()); - scope.setContexts("isAdmin", UserFunction.isAdmin(member)); scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); scope.setTag("channel", channel.getId()); scope.setTag("interactionId", event.getInteraction().getId()); diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index b4cf87a..31f8c68 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -22,11 +22,13 @@ public class DBBlacklist extends AbstractController { public void add(String word, CommandContext context) { GuildManager guildManager = GuildManager.getManager(context.getGuild()); - Session session = getSessionFactory().openSession(); + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); if (bl == null) { + Session session = getSessionFactory().openSession(); + session.beginTransaction(); bl = new OBlacklist(); bl.setGuild(guildManager.getGuildEntity()); @@ -36,73 +38,81 @@ public class DBBlacklist extends AbstractController { session.save(bl); session.getTransaction().commit(); - guildManager.reloadBlacklistCache(false); + session.close(); + + guildManager.reloadBlacklistCache(); context.reply(String.format("Added the word [%s] to the blacklist.", word)); } else { context.reply("Word is already blacklisted"); } - session.close(); + } public void delete(String word, CommandContext context) { GuildManager guildManager = GuildManager.getManager(context.getGuild()); - Session session = getSessionFactory().openSession(); - OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); + if (bl != null) { + Session session = getSessionFactory().openSession(); session.beginTransaction(); session.delete(bl); session.getTransaction().commit(); - guildManager.reloadBlacklistCache(false); + session.close(); + + guildManager.reloadBlacklistCache(); context.reply("Removed the word [%s] from the blacklist.", word); } else { context.reply("Can't delete word because it doesn't exist"); } - - session.close(); } public void enable(String word, CommandContext context) { GuildManager guildManager = GuildManager.getManager(context.getGuild()); - Session session = getSessionFactory().openSession(); + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); if (bl != null && !bl.getEnabled()) { + Session session = getSessionFactory().openSession(); session.beginTransaction(); + bl.setEnabled(true); session.update(bl); session.getTransaction().commit(); - guildManager.reloadBlacklistCache(false); + session.close(); + + guildManager.reloadBlacklistCache(); context.reply("Enabled the word [%s] for the blacklist.", word); } else { context.reply("Either word doesn't exist or is already enabled"); } - session.close(); + } public void disable(String word, CommandContext context) { GuildManager guildManager = GuildManager.getManager(context.getGuild()); - Session session = getSessionFactory().openSession(); + OBlacklist bl = getWordFromDb(word, context.getGuild().getId()); if (bl != null && bl.getEnabled()) { + Session session = getSessionFactory().openSession(); session.beginTransaction(); + bl.setEnabled(false); session.update(bl); session.getTransaction().commit(); - guildManager.reloadBlacklistCache(false); + session.close(); + + guildManager.reloadBlacklistCache(); context.reply("Disabled the word [%s] for the blacklist.", word); } else { context.reply("Either word doesn't exist or is already disabled"); } - - session.close(); } public ArrayList<OBlacklist> getBlacklistForGuild(Guild guild) { diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 5b399cf..0476f7e 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -1,5 +1,4 @@ package netneutrality.db.controllers; - /* * Copyright (c) anthorob * @@ -9,7 +8,7 @@ package netneutrality.db.controllers; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.GuildManager; import netneutrality.db.AbstractController; import netneutrality.db.entities.OLogMessage; @@ -24,7 +23,7 @@ public class DBMessage extends AbstractController { private final static Logger logger = LoggerFactory.getLogger(DBMessage.class); - public void log(GuildManager guildManager, TextChannel channel, Member author, Message message) { + public void log(GuildManager guildManager, MessageChannel channel, Member author, Message message) { Session session = getSessionFactory().openSession(); session.beginTransaction(); diff --git a/src/main/java/netneutrality/exceptions/CommandException.java b/src/main/java/netneutrality/exceptions/CommandException.java index e058aad..55524ff 100644 --- a/src/main/java/netneutrality/exceptions/CommandException.java +++ b/src/main/java/netneutrality/exceptions/CommandException.java @@ -15,7 +15,7 @@ public abstract class CommandException extends RuntimeException { private final CommandContext context; public CommandException(String message, CommandContext context, Throwable cause) { - super(message== null ? DEFAULT_MESSAGE : message, cause); + super(message == null ? DEFAULT_MESSAGE : message, cause); this.context = context; } diff --git a/src/main/java/netneutrality/hooks/message/EditHandler.java b/src/main/java/netneutrality/hooks/message/EditHandler.java index befd9c1..5ee3bd3 100644 --- a/src/main/java/netneutrality/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/hooks/message/EditHandler.java @@ -15,6 +15,7 @@ import netneutrality.core.SessionManager; import netneutrality.db.DBController; import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OGuild; +import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; import org.hibernate.Session; @@ -34,7 +35,7 @@ public class EditHandler extends ListenerAdapter { if (guildEntity.getLogChannel() != null && !guildEntity.getLogChannel().isEmpty()) { Session session = SessionManager.getSessionFactory().openSession(); - session.load(guildEntity, guildEntity.getGuildId()); + JpaUtils.tryLoad(session, guildEntity, guildEntity.getGuildId()); int size = guildEntity.getLoggings() .stream() diff --git a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java index 31cd7e5..f9ec8c3 100644 --- a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java @@ -8,14 +8,9 @@ package netneutrality.hooks.message; import io.sentry.Breadcrumb; import io.sentry.Sentry; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.command.AbstractCommand; -import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; import netneutrality.core.context.MessageCommandContext; import netneutrality.utils.Settings; @@ -32,15 +27,11 @@ public class MessageReceivedHandler extends ListenerAdapter { return; Message message = event.getMessage(); - Member member = event.getMember(); - Guild guild = event.getGuild(); - TextChannel channel = (TextChannel) event.getChannel(); - - Sentry.addBreadcrumb(Breadcrumb.info("New message from " + member.getEffectiveName())); MessageCommandContext context = MessageCommandContext.createContext(event); + Sentry.addBreadcrumb(Breadcrumb.info("New message from " + context.getGuildUser().getEffectiveName())); - GuildManager.getManager(guild).checkAndLogMessage(message, member, channel); + GuildManager.getManager(context.getGuild()).checkAndLogMessage(message, context.getGuildUser(), context.getChannel()); String rawMessage = message.getContentDisplay().trim(); String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); @@ -50,13 +41,7 @@ public class MessageReceivedHandler extends ListenerAdapter { // rawMessage = rawMessage.substring(prefix.length()).trim(); String commandString = rawMessage.split(" ", 2)[0]; - - if (CommandManager.isValidCommand(commandString)) { - AbstractCommand command = CommandManager.getCommand(commandString); - - context.dispatch(command); - } - + context.dispatchToCommand(commandString); } } } diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 4cdb784..903a27c 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -49,7 +49,7 @@ public class ActionHandler extends AbstractHandler { Guild guild = NetNeutrality.getJDA().getGuildById(guildId); if (guild != null) { GuildManager manager = GuildManager.getManager(guild); - Map<String, String> settings = manager.getSettings(); + Map<String, String> settings = manager.getGuildConfigManager().getSettings(); JSONObject setting = new JSONObject(settings); json.put("status", "ok"); @@ -68,11 +68,11 @@ public class ActionHandler extends AbstractHandler { String guildId = args[args.length - 1]; Guild guild = NetNeutrality.getJDA().getGuildById(guildId); - boolean ok; + boolean ok = true; //TODO: add bool if (guild == null) - ok = GuildManager.getManager(guildId).reloadSettingsCache(); + GuildManager.getManager(guildId).getGuildConfigManager().reloadSettingsCache(); else - ok = GuildManager.getManager(guild).reloadSettingsCache(); + GuildManager.getManager(guild).getGuildConfigManager().reloadSettingsCache(); json.put("status", String.valueOf(ok)); diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 3613295..c5df1a3 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -17,6 +17,7 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.GuildManager; import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; @@ -55,7 +56,7 @@ public class MusicManager { this.guild = guild; this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(this); - this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GSettings.MUSIC_VOLUME)); + this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getGuildConfigManager().getSetting(GSettings.MUSIC_VOLUME)); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); @@ -92,11 +93,10 @@ public class MusicManager { player.setVolume(baseVolume); if (autoDisconnectThread == null) - autoDisconnectThread = executor.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 120, 120, TimeUnit.SECONDS); + autoDisconnectThread = executor.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 240, 240, TimeUnit.SECONDS); } else { throw new RuntimeException("Error connecting to voice channel"); } - } public boolean isConnected() { @@ -165,11 +165,11 @@ public class MusicManager { public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); - TextChannel channel = (TextChannel) context.getChannel(); + MessageChannel channel = context.getChannel(); if (member.getVoiceState() == null) { logger.error("Guild {}: Voice state is null", guild.getId()); - context.replyToMessage("Voice state is null, something has gone wrong."); + context.replyToMessage("Voice state is null, something has gone terribly wrong."); LogHandler.log(new CommandExecutionException("Voice state is null", context, null)); return; diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/netneutrality/music/TrackLoader.java index 204a2df..d648662 100644 --- a/src/main/java/netneutrality/music/TrackLoader.java +++ b/src/main/java/netneutrality/music/TrackLoader.java @@ -119,6 +119,7 @@ public class TrackLoader implements Runnable { } } catch (InterruptedException exception) { stopLoading(); + context.replyToMessage("Loading of tracks was interrupted due to an exception"); LogHandler.log(exception); } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index c738c4b..1b471d9 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -14,6 +14,7 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.LogHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +25,7 @@ public class TrackScheduler extends AudioEventAdapter { private final QueueManager queueManager; private final MusicManager manager; private final AudioPlayer player; - private TextChannel currentChannel; + private MessageChannel currentChannel; private final Guild guild; public TrackScheduler(MusicManager manager) { @@ -50,11 +51,11 @@ public class TrackScheduler extends AudioEventAdapter { return guild; } - public TextChannel getTextChannel() { + public MessageChannel getTextChannel() { return currentChannel; } - public synchronized void attachTextChannel(TextChannel channel) { + public synchronized void attachTextChannel(MessageChannel channel) { this.currentChannel = channel; } diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index 4c65371..8b8a0b1 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -1,4 +1,5 @@ -package netneutrality.thread;/* +package netneutrality.thread; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -18,6 +19,7 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { final MusicManager manager; + //TODO: move to scheduler public MusicPlayerAutoDisconnectThread(MusicManager musicManager) { manager = musicManager; } @@ -27,13 +29,26 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { Guild guild = manager.getGuild(); VoiceChannel channel = (VoiceChannel) guild.getAudioManager().getConnectedChannel(); - if (channel != null) { - List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); + try { + if (channel != null) { + if (conditionsMetToDisconnect(channel)) { + // Sleep 30 seconds then check again (prevents disconnecting right after a track ends) + Thread.sleep(30000); - if (members.size() == 0 || manager.getScheduler().getQueueManager().isEmpty()) { - LoggerFactory.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); - manager.leave(); + if (conditionsMetToDisconnect(channel)) { + LoggerFactory.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); + manager.leave(); + } + } } + } catch (InterruptedException e) { + throw new RuntimeException(e); } } + + private boolean conditionsMetToDisconnect(VoiceChannel channel) { + List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); + + return members.size() == 0 || manager.getScheduler().getQueueManager().isEmpty(); + } } diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/netneutrality/utils/JpaUtils.java index 29d004b..4625e84 100644 --- a/src/main/java/netneutrality/utils/JpaUtils.java +++ b/src/main/java/netneutrality/utils/JpaUtils.java @@ -70,28 +70,17 @@ public class JpaUtils { getWithSession(oGuild, oGuild.getGuildId(), consumer); } - public static void getWithSession(OGuild oGuild, boolean close, Consumer<Session> consumer) { - getWithSession(oGuild, oGuild.getGuildId(), close, consumer); - } - - public static void getWithSession(Object persistantEntity, Serializable id, Consumer<Session> consumer) { - getWithSession(persistantEntity, id, true, consumer); - } - - /** * @param persistantEntity The entity to load * @param id The identifier for the entity * @param close If the session should be closed after consumer is executed * @param consumer The comsumer, which exposes the session */ - public static void getWithSession(Object persistantEntity, Serializable id, boolean close, Consumer<Session> consumer) { + public static void getWithSession(Object persistantEntity, Serializable id, Consumer<Session> consumer) { Session session = SessionManager.getSessionFactory().openSession(); tryLoad(session, persistantEntity, id); consumer.accept(session); - - if (close) - session.close(); + session.close(); } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index c3be185..77c4a50 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -14,8 +14,7 @@ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.ChannelType; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; import netneutrality.core.CommandManager; @@ -39,28 +38,6 @@ public class MessageFunction { private final static Logger logger = LoggerFactory.getLogger(MessageFunction.class); - public static Member getStartingMention(Message message) { - if (isStartingWithMention(message)) { - return message.getMentions().getMembers().get(0); - } - - return null; - } - - public static boolean isStartingWithMention(Message message) { - if (!message.isFromType(ChannelType.TEXT)) - return false; - - List<Member> mentions = message.getMentions().getMembers(); - - for (Member member : mentions) { - if (message.getContentDisplay().startsWith("@" + member.getUser().getName())) - return true; - } - - return false; - } - public static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager) { AudioTrack current = manager.getCurrentlyPlaying(); @@ -81,7 +58,7 @@ public class MessageFunction { String url = track.getIdentifier(); String thumbnail = null; - if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { + if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch || type == SourceFinder.AudioSourceType.YTMusic) { url = String.format("https://youtu.be/%s", track.getIdentifier()); thumbnail = String.format("https://i3.ytimg.com/vi/%s/hqdefault.jpg", track.getIdentifier()); } @@ -275,7 +252,7 @@ public class MessageFunction { return editEmbed.build(); } - public static void testMessageAgainstBlacklist(Message message, TextChannel channel, Set<String> cache) { + public static void testMessageAgainstBlacklist(Message message, MessageChannel channel, Set<String> cache) { boolean found = false; for (String word : cache) { if (message.getContentRaw().toLowerCase().contains(word)) { From 73fd55fe0c443ad7f4a22fcc1a39c33c8eb779ae Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 9 Mar 2024 22:09:54 -0500 Subject: [PATCH 109/155] Update Hibernate to 6.x --- pom.xml | 4 ++-- src/main/java/netneutrality/core/SessionManager.java | 2 +- src/main/java/netneutrality/db/entities/OBlacklist.java | 2 +- src/main/java/netneutrality/db/entities/OGuild.java | 2 +- src/main/java/netneutrality/db/entities/OGuildSetting.java | 2 +- src/main/java/netneutrality/db/entities/OLogMessage.java | 2 +- src/main/java/netneutrality/db/entities/OLogging.java | 2 +- src/main/java/netneutrality/db/entities/OLoggingId.java | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index ae0bfa9..f1e551d 100644 --- a/pom.xml +++ b/pom.xml @@ -130,12 +130,12 @@ <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> - <version>5.6.5.Final</version> + <version>6.1.7.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-hikaricp</artifactId> - <version>5.6.5.Final</version> + <version>6.1.7.Final</version> </dependency> <dependency> <groupId>io.sentry</groupId> diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index 249f459..f338703 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -29,7 +29,7 @@ public class SessionManager { if (sessionFactory == null) { try { StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder().configure(); - Map<String, String> settings = new HashMap<>(); + Map<String, Object> settings = new HashMap<>(); String dbName = Settings.getInstance().get("MYSQL_DATABASE", "netneutrality"); String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); diff --git a/src/main/java/netneutrality/db/entities/OBlacklist.java b/src/main/java/netneutrality/db/entities/OBlacklist.java index 36c4715..d8f0228 100644 --- a/src/main/java/netneutrality/db/entities/OBlacklist.java +++ b/src/main/java/netneutrality/db/entities/OBlacklist.java @@ -7,7 +7,7 @@ package netneutrality.db.entities; * https://discord.gg/CdFcyQ */ -import javax.persistence.*; +import jakarta.persistence.*; @Entity @Table(name = "blacklist") diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java index c7d4659..1be8b89 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -7,7 +7,7 @@ package netneutrality.db.entities; * https://discord.gg/CdFcyQ */ -import javax.persistence.*; +import jakarta.persistence.*; import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java index b2704ca..5116aae 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -7,7 +7,7 @@ package netneutrality.db.entities; * https://discord.gg/CdFcyQ */ -import javax.persistence.*; +import jakarta.persistence.*; @Entity @Table(name = "guild_settings") diff --git a/src/main/java/netneutrality/db/entities/OLogMessage.java b/src/main/java/netneutrality/db/entities/OLogMessage.java index cc5ccee..dc0da9f 100644 --- a/src/main/java/netneutrality/db/entities/OLogMessage.java +++ b/src/main/java/netneutrality/db/entities/OLogMessage.java @@ -7,7 +7,7 @@ package netneutrality.db.entities; * https://discord.gg/CdFcyQ */ -import javax.persistence.*; +import jakarta.persistence.*; import java.time.Instant; @Entity diff --git a/src/main/java/netneutrality/db/entities/OLogging.java b/src/main/java/netneutrality/db/entities/OLogging.java index ed1b470..a690912 100644 --- a/src/main/java/netneutrality/db/entities/OLogging.java +++ b/src/main/java/netneutrality/db/entities/OLogging.java @@ -7,7 +7,7 @@ package netneutrality.db.entities; * https://discord.gg/CdFcyQ */ -import javax.persistence.*; +import jakarta.persistence.*; @Entity @Table(name = "logging") diff --git a/src/main/java/netneutrality/db/entities/OLoggingId.java b/src/main/java/netneutrality/db/entities/OLoggingId.java index d3eafa2..f32f9bb 100644 --- a/src/main/java/netneutrality/db/entities/OLoggingId.java +++ b/src/main/java/netneutrality/db/entities/OLoggingId.java @@ -9,8 +9,8 @@ package netneutrality.db.entities; import org.hibernate.Hibernate; -import javax.persistence.Column; -import javax.persistence.Embeddable; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; import java.io.Serial; import java.io.Serializable; import java.util.Objects; From 3eb38ba4fc938480b2316f81d18e9374f951c548 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Sat, 9 Mar 2024 22:12:24 -0500 Subject: [PATCH 110/155] Use newer fork of lavaplayer --- pom.xml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index f1e551d..a7afa73 100644 --- a/pom.xml +++ b/pom.xml @@ -114,11 +114,16 @@ <!-- <groupId>com.sedmelluq</groupId>--> <!-- <artifactId>lavaplayer</artifactId>--> <!-- <version>1.3.78</version>--> +<!-- </dependency>--> +<!-- <dependency>--> +<!-- <groupId>com.github.walkyst</groupId>--> +<!-- <artifactId>lavaplayer-fork</artifactId>--> +<!-- <version>1.4.3</version>--> <!-- </dependency>--> <dependency> - <groupId>com.github.walkyst</groupId> - <artifactId>lavaplayer-fork</artifactId> - <version>1.4.3</version> + <groupId>dev.arbjerg</groupId> + <artifactId>lavaplayer</artifactId> + <version>2.1.0</version> </dependency> <dependency> From 92daaad37c30283e6bbb528f5c5230242cd546e7 Mon Sep 17 00:00:00 2001 From: anthorob <anthorob@xtremmail.com> Date: Mon, 11 Mar 2024 01:05:54 -0400 Subject: [PATCH 111/155] Update lavaplayer to fix 400 status code --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a7afa73..80dc657 100644 --- a/pom.xml +++ b/pom.xml @@ -108,7 +108,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.18</version> + <version>5.0.0-beta.20</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.sedmelluq</groupId>--> @@ -123,7 +123,7 @@ <dependency> <groupId>dev.arbjerg</groupId> <artifactId>lavaplayer</artifactId> - <version>2.1.0</version> + <version>2.1.1</version> </dependency> <dependency> From 23108fb2d98cf57376826bd5a0a1a6070d50aaf0 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Fri, 29 Mar 2024 01:29:04 -0400 Subject: [PATCH 112/155] Update dependencies and maven wrapper --- .mvn/wrapper/MavenWrapperDownloader.java | 117 ------------ .mvn/wrapper/maven-wrapper.properties | 8 +- mvnw | 218 +++++++++++------------ mvnw.cmd | 31 +++- pom.xml | 35 ++-- 5 files changed, 145 insertions(+), 264 deletions(-) delete mode 100644 .mvn/wrapper/MavenWrapperDownloader.java diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097..0000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index e83fa69..346d645 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -5,14 +5,14 @@ # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/mvnw b/mvnw index 5643201..8d937f4 100644 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.2.0 # # Required ENV vars: # ------------------ @@ -27,7 +27,6 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -54,7 +53,7 @@ fi cygwin=false; darwin=false; mingw=false -case "`uname`" in +case "$(uname)" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true @@ -62,9 +61,9 @@ case "`uname`" in # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME else - export JAVA_HOME="/Library/Java/Home" + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME fi fi ;; @@ -72,68 +71,38 @@ esac if [ -z "$JAVA_HOME" ] ; then if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + JAVA_HOME=$(java-config --jre-home) fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") fi # For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" fi if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" else - javaExecutable="`readlink -f \"$javaExecutable\"`" + javaExecutable="$(readlink -f "\"$javaExecutable\"")" fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') JAVA_HOME="$javaHome" export JAVA_HOME fi @@ -149,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`\\unset -f command; \\command -v java`" + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" fi fi @@ -163,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" @@ -184,96 +150,99 @@ find_maven_basedir() { fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + wdir=$(cd "$wdir/.." || exit 1; pwd) fi # end of workaround done - echo "${basedir}" + printf '%s' "$(cd "$basedir" || exit 1; pwd)" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") if [ -z "$BASE_DIR" ]; then exit 1; fi +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. ########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi + log "Couldn't find $wrapperJarPath, downloading it ..." + if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") fi if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" fi - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" # For Cygwin, switch paths to Windows format before running javac if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" fi fi fi @@ -282,35 +251,58 @@ fi # End of extension ########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi fi + MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") fi # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +# shellcheck disable=SC2086 # safe args exec "$JAVACMD" \ $MAVEN_OPTS \ $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 8a15b7f..c4586b5 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -18,13 +18,12 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script +@REM Apache Maven Wrapper startup batch script, version 3.2.0 @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @@ -120,10 +119,10 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B ) @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central @@ -134,11 +133,11 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% + echo Downloading from: %WRAPPER_URL% ) powershell -Command "&{"^ @@ -146,7 +145,7 @@ if exist %WRAPPER_JAR% ( "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ "}" if "%MVNW_VERBOSE%" == "true" ( echo Finished downloading %WRAPPER_JAR% @@ -154,6 +153,24 @@ if exist %WRAPPER_JAR% ( ) @REM End of extension +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + @REM Provide a "standardized" way to retrieve the CLI args that will @REM work with both Windows and non-Windows executions. set MAVEN_CMD_LINE_ARGS=%* diff --git a/pom.xml b/pom.xml index 80dc657..9a003bf 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ <repositories> <repository> <id>central</id> - <url>https://repo.maven.apache.org/maven2</url> + <url>https://repo1.maven.org/maven2/</url> </repository> <repository> @@ -102,24 +102,14 @@ <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>3.6.0</version> + <version>3.7.1</version> </dependency> <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.20</version> + <version>5.0.0-beta.21</version> </dependency> -<!-- <dependency>--> -<!-- <groupId>com.sedmelluq</groupId>--> -<!-- <artifactId>lavaplayer</artifactId>--> -<!-- <version>1.3.78</version>--> -<!-- </dependency>--> -<!-- <dependency>--> -<!-- <groupId>com.github.walkyst</groupId>--> -<!-- <artifactId>lavaplayer-fork</artifactId>--> -<!-- <version>1.4.3</version>--> -<!-- </dependency>--> <dependency> <groupId>dev.arbjerg</groupId> <artifactId>lavaplayer</artifactId> @@ -129,7 +119,7 @@ <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> - <version>4.10.0</version> + <version>4.12.0</version> </dependency> <dependency> @@ -145,7 +135,7 @@ <dependency> <groupId>io.sentry</groupId> <artifactId>sentry</artifactId> - <version>6.16.0</version> + <version>7.6.0</version> </dependency> <dependency> <groupId>p6spy</groupId> @@ -153,11 +143,10 @@ <version>3.9.1</version> </dependency> - <!-- https://mvnrepository.com/artifact/org.json/json --> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> - <version>20230227</version> + <version>20240303</version> </dependency> <dependency> @@ -167,19 +156,19 @@ </dependency> <dependency> - <groupId>mysql</groupId> - <artifactId>mysql-connector-java</artifactId> - <version>8.0.33</version> + <groupId>com.mysql</groupId> + <artifactId>mysql-connector-j</artifactId> + <version>8.3.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> - <version>2.20.0</version> + <version>2.23.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> - <artifactId>log4j-slf4j-impl</artifactId> - <version>2.20.0</version> + <artifactId>log4j-slf4j2-impl</artifactId> + <version>2.23.1</version> </dependency> <dependency> From e6be74ad5393aa2b112af917ed153b0eb9e19c03 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 30 Mar 2024 15:14:40 -0400 Subject: [PATCH 113/155] Add more useful logs in reply and use snapshot of lavalink to temporarily fix player issues --- pom.xml | 10 ++++-- .../java/netneutrality/core/LogHandler.java | 31 +++++++++---------- .../core/context/CommandContext.java | 4 +++ .../core/context/SlashCommandContext.java | 4 +++ .../music/TrackLoadingHandler.java | 21 ++++++------- .../netneutrality/music/TrackScheduler.java | 3 +- .../netneutrality/utils/MessageFunction.java | 12 +++++++ .../java/netneutrality/utils/MusicUtils.java | 1 - 8 files changed, 53 insertions(+), 33 deletions(-) diff --git a/pom.xml b/pom.xml index 9a003bf..28098f4 100644 --- a/pom.xml +++ b/pom.xml @@ -96,6 +96,12 @@ <url>https://jitpack.io</url> </repository> + <repository> + <id>arbjergDev-snapshots</id> + <name>Lavalink Repository</name> + <url>https://maven.lavalink.dev/snapshots</url> + </repository> + </repositories> <dependencies> @@ -113,7 +119,7 @@ <dependency> <groupId>dev.arbjerg</groupId> <artifactId>lavaplayer</artifactId> - <version>2.1.1</version> + <version>0eaeee195f0315b2617587aa3537fa202df07ddc-SNAPSHOT</version> </dependency> <dependency> @@ -167,7 +173,7 @@ </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> - <artifactId>log4j-slf4j2-impl</artifactId> + <artifactId>log4j-slf4j-impl</artifactId> <version>2.23.1</version> </dependency> diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index ba11ac9..47363cb 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -27,16 +27,18 @@ public class LogHandler { * @param e The exceptions to log */ public static void log(Exception e) { - if (e instanceof CommandExecutionException) { - Sentry.captureException(e); - logInternally((CommandExecutionException) e); - tryLogToDebugChannel((CommandExecutionException) e); - tryGracefulSlashContextError((CommandExecutionException) e); + Sentry.captureException(e); + + if (e instanceof CommandExecutionException exception) { + CommandContext context = exception.getCommandContext(); + + logInternally(exception, context); + tryLogToDebugChannel(exception, context); + tryGracefulSlashContextError(exception, context); return; } - Sentry.captureException(e); logger.error(e.getMessage(), e); } @@ -59,14 +61,11 @@ public class LogHandler { } } - private static void logInternally(CommandException error) { - CommandContext context = error.getCommandContext(); - logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage(), error); + private static void logInternally(CommandException exception, CommandContext context) { + logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), exception.getMessage(), exception); } - private static void tryLogToDebugChannel(CommandException error) { - CommandContext context = error.getCommandContext(); - + private static void tryLogToDebugChannel(CommandException exception, CommandContext context) { if (context.getGuild() != null) { if (GuildManager.getManager(context.getGuild()).isDebugEnabled()) { context.getGuild() @@ -74,16 +73,14 @@ public class LogHandler { .stream() .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) .filter(TextChannel::canTalk) - .forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, error)).queue()); + .forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, exception)).queue()); } } } - private static void tryGracefulSlashContextError(CommandExecutionException error) { - CommandContext context = error.getCommandContext(); - + private static void tryGracefulSlashContextError(CommandException exception, CommandContext context) { if (context instanceof SlashCommandContext slashCommandContext) { - slashCommandContext.replyEphemeral("Error during command execution"); + slashCommandContext.reply(MessageFunction.buildSentryErrorMessage(exception.getMessage())); } } } diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 4e2db05..ff2d737 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -53,5 +53,9 @@ public interface CommandContext { replyToMessage(String.format(format, arguments)); } + default void replyToMessage(MessageEmbed... embeds) { + replyToMessage(MessageCreateData.fromEmbeds(embeds)); + } + void dispatchToCommand(String commandName); } diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java index 775301f..9684e3c 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -138,6 +138,10 @@ public class SlashCommandContext implements CommandContext { event.reply(message).setEphemeral(true).queue(); } + public void replyEphemeral(MessageEmbed... embeds) { + replyEphemeral(MessageCreateData.fromEmbeds(embeds)); + } + public void replyEphemeral(String format, Object... arguments) { replyEphemeral(String.format(format, arguments)); } diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index 52b467f..ccd5151 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -56,9 +56,8 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { loadConsumer.accept(true); } - if (loadingDisabled) { + if (loadingDisabled) return; - } context.deleteMessage(); @@ -76,9 +75,9 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { loadConsumer.accept(true); } - if (loadingDisabled) { + if (loadingDisabled) return; - } + logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); if (!playlist.getTracks().isEmpty()) { @@ -110,24 +109,22 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { @Override public void noMatches() { - logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); + if (loadConsumer != null) + loadConsumer.accept(false); if (!silent) context.replyToMessage("No matches found"); - - if (loadConsumer != null) - loadConsumer.accept(false); } @Override public void loadFailed(FriendlyException e) { + if (loadConsumer != null) + loadConsumer.accept(false); + logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); LogHandler.log(e); if (!silent) - context.replyToMessage("Failed to load track: " + e.getMessage()); - - if (loadConsumer != null) - loadConsumer.accept(false); + context.replyToMessage(MessageFunction.buildSentryErrorMessage("Failed to load track: " + e.getMessage())); } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 1b471d9..5e7bc1d 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -16,6 +16,7 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.LogHandler; +import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -119,7 +120,7 @@ public class TrackScheduler extends AudioEventAdapter { public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { logger.debug("Guild {}: exception while playing track [{}]: {}", guild.getId(), track.getIdentifier(), exception.getMessage()); LogHandler.log(exception); - sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage()); + sendMessageToChannel(MessageFunction.buildSentryErrorMessage(String.format("Error while playing track [%s]: %s", track.getInfo().title, exception.getMessage()))); } @Override diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 77c4a50..1b8f941 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -10,6 +10,7 @@ package netneutrality.utils; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import io.sentry.Sentry; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; @@ -208,6 +209,17 @@ public class MessageFunction { return messages; } + public static MessageEmbed buildSentryErrorMessage(String error) { + EmbedBuilder message = new EmbedBuilder(); + message.setColor(Color.RED); + message.setTitle(":warning: Error during execution :warning:"); + message.addField("Error message:", error, false); + message.addField("Error ID:", Sentry.getLastEventId().toString(), false); + message.setTimestamp(OffsetDateTime.now()); + + return message.build(); + } + public static MessageEmbed buildDebugMessage(CommandContext context, CommandException error) { EmbedBuilder message = new EmbedBuilder(); message.setColor(Color.RED); diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index 3f5fa2a..71a1046 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -16,7 +16,6 @@ public class MusicUtils { public static boolean checkIfConnected(MusicManager manager, CommandContext context) { if (context.getGuildUser().getVoiceState() == null) { - context.reply("Voice state is null, this should not happen"); throw new CommandExecutionException("Voice state is null, this should not happen", context, null); } From eded9bee00135bf4daa7ca79008a97b6fbe6f8f5 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 30 Mar 2024 15:23:12 -0400 Subject: [PATCH 114/155] chmod +x of mvnw --- mvnw | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 mvnw diff --git a/mvnw b/mvnw old mode 100644 new mode 100755 From f79ab8984a13de9fd178e97275d10cf6cc329fe4 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Thu, 9 May 2024 15:32:43 -0400 Subject: [PATCH 115/155] Add Udio music source --- .../netneutrality/music/MusicManager.java | 3 + .../netneutrality/music/SourceFinder.java | 10 +- .../music/source/UdioAudioSourceManager.java | 159 ++++++++++++++++++ .../music/source/UdioAudioTrack.java | 90 ++++++++++ 4 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 src/main/java/netneutrality/music/source/UdioAudioSourceManager.java create mode 100644 src/main/java/netneutrality/music/source/UdioAudioTrack.java diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index c5df1a3..cde9d79 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -11,6 +11,7 @@ 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.soundcloud.SoundCloudAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; @@ -24,6 +25,7 @@ import netneutrality.core.context.CommandContext; import netneutrality.db.GSettings; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.loadable.LoadableSong; +import netneutrality.music.source.UdioAudioSourceManager; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; @@ -79,6 +81,7 @@ public class MusicManager { playerManager.registerSourceManager(youtubeSource); playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); + playerManager.registerSourceManager(new UdioAudioSourceManager()); } public boolean isNotConnectedTo(VoiceChannel vChannel) { diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index b78073d..eb64383 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -19,6 +19,7 @@ public class SourceFinder { Bandcamp, Vimeo, YTSearch, + Udio, Nothing } @@ -26,12 +27,14 @@ public class SourceFinder { private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-zA-Z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern youtubeMusicPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?music\\.(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-zA-Z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); - private static Matcher twitchMatcher; + private static final Pattern udioPattern = Pattern.compile("^https://www.udio.com/songs/[0-9A-Za-z]+$", Pattern.CASE_INSENSITIVE); + public static AudioSourceType getSource(String url) { Matcher youtubeMatcher = youtubePattern.matcher(url); Matcher youtubeMusicMatcher = youtubeMusicPattern.matcher(url); Matcher soundcloudMatcher = soundcloudPattern.matcher(url); + Matcher udioMatcher = udioPattern.matcher(url); if (youtubeMatcher.find()) return AudioSourceType.Youtube; @@ -42,6 +45,9 @@ public class SourceFinder { if (soundcloudMatcher.find()) return AudioSourceType.Soundcloud; + if (udioMatcher.find()) + return AudioSourceType.Udio; + if (!(url.startsWith("http://") || url.startsWith("https://"))) return AudioSourceType.YTSearch; @@ -52,7 +58,7 @@ public class SourceFinder { String identifier; identifier = switch (getSource(url)) { - case Youtube, YTMusic, Soundcloud -> url; + case Youtube, YTMusic, Soundcloud, Udio -> url; case YTSearch -> "ytsearch:" + url; default -> null; }; diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java new file mode 100644 index 0000000..2c191cb --- /dev/null +++ b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java @@ -0,0 +1,159 @@ +package netneutrality.music.source;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager; +import com.sedmelluq.discord.lavaplayer.tools.DataFormatTools; +import com.sedmelluq.discord.lavaplayer.tools.ExceptionTools; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser; +import com.sedmelluq.discord.lavaplayer.tools.io.HttpClientTools; +import com.sedmelluq.discord.lavaplayer.tools.io.HttpConfigurable; +import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface; +import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager; +import com.sedmelluq.discord.lavaplayer.track.AudioItem; +import com.sedmelluq.discord.lavaplayer.track.AudioReference; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpStatus; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Pattern; + +import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity.SUSPICIOUS; + +public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigurable { + + private static final String TRACK_URL_REGEX = "^https://www.udio.com/songs/[0-9A-Za-z]+$"; + private static final Pattern trackUrlPattern = Pattern.compile(TRACK_URL_REGEX); + + private final HttpInterfaceManager httpInterfaceManager; + + public UdioAudioSourceManager() { + httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager(); + } + + public HttpInterface getHttpInterface() { + return httpInterfaceManager.getInterface(); + } + + @Override + public String getSourceName() { + return "udio"; + } + + @Override + public AudioItem loadItem(AudioPlayerManager manager, AudioReference reference) { + // start = "og:audio:url\",\"content\":\" + // end = \"}], + + if (!trackUrlPattern.matcher(reference.identifier).matches()) { + return null; + } + + try (HttpInterface httpInterface = httpInterfaceManager.getInterface()) { + return loadFromTrackPage(httpInterface, reference.identifier); + } catch (IOException e) { + throw new FriendlyException("Loading Udio track information failed.", SUSPICIOUS, e); + } + + } + + private AudioItem loadFromTrackPage(HttpInterface httpInterface, String trackUrl) throws IOException { + + try (CloseableHttpResponse response = httpInterface.execute(new HttpGet(trackUrl))) { + int statusCode = response.getStatusLine().getStatusCode(); + + if (statusCode == HttpStatus.SC_NOT_FOUND) { + return AudioReference.NO_TRACK; + } else if (!HttpClientTools.isSuccessWithContent(statusCode)) { + throw new FriendlyException("Server responded with an error.", SUSPICIOUS, + new IllegalStateException("Response code is " + statusCode)); + } + + return loadTrackFromPageContent(trackUrl, IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8)); + } + } + + private AudioTrack loadTrackFromPageContent(String trackUrl, String content) throws IOException { + JsonBrowser config = loadConfigJsonFromPageContent(content); + + if (config == null) { + throw new FriendlyException("Track information not found on the page.", SUSPICIOUS, null); + } + + JsonBrowser trackInfo; + try { + trackInfo = config.index(3).get("children").index(3).get("children").index(3).get("track"); + } catch (NullPointerException e) { + throw new FriendlyException("Track information not found on the page.", SUSPICIOUS, null); + } + + return new UdioAudioTrack(new AudioTrackInfo( + trackInfo.get("title").text(), + trackInfo.get("artist").text(), + (long) (trackInfo.get("duration").as(Double.class) * 1000.0), + trackUrl, + false, + trackUrl + ), this); + } + + JsonBrowser loadConfigJsonFromPageContent(String content) throws IOException { + String configText = DataFormatTools.extractBetween(content, "self.__next_f.push([1,\"8:", "\\n"); + System.out.println(configText); + + if (configText != null) { + configText = configText.replace("\\", ""); + System.out.println(configText); + + return JsonBrowser.parse(configText); + } + + return null; + } + + @Override + public boolean isTrackEncodable(AudioTrack track) { + return true; + } + + @Override + public void encodeTrack(AudioTrack track, DataOutput output) throws IOException { + + } + + @Override + public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException { + return new UdioAudioTrack(trackInfo, this); + } + + @Override + public void shutdown() { + ExceptionTools.closeWithWarnings(httpInterfaceManager); + } + + @Override + public void configureRequests(Function<RequestConfig, RequestConfig> configurator) { + httpInterfaceManager.configureRequests(configurator); + } + + @Override + public void configureBuilder(Consumer<HttpClientBuilder> configurator) { + httpInterfaceManager.configureBuilder(configurator); + } +} diff --git a/src/main/java/netneutrality/music/source/UdioAudioTrack.java b/src/main/java/netneutrality/music/source/UdioAudioTrack.java new file mode 100644 index 0000000..e44f97f --- /dev/null +++ b/src/main/java/netneutrality/music/source/UdioAudioTrack.java @@ -0,0 +1,90 @@ +package netneutrality.music.source;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import com.sedmelluq.discord.lavaplayer.container.mp3.Mp3AudioTrack; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser; +import com.sedmelluq.discord.lavaplayer.tools.io.HttpClientTools; +import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface; +import com.sedmelluq.discord.lavaplayer.tools.io.PersistentHttpStream; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import com.sedmelluq.discord.lavaplayer.track.DelegatedAudioTrack; +import com.sedmelluq.discord.lavaplayer.track.playback.LocalAudioTrackExecutor; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; + +import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity.SUSPICIOUS; + +public class UdioAudioTrack extends DelegatedAudioTrack { + + private static final Logger log = LoggerFactory.getLogger(UdioAudioTrack.class); + + private final UdioAudioSourceManager sourceManager; + + /** + * @param trackInfo Track info + * @param sourceManager Source manager which was used to find this track + */ + public UdioAudioTrack(AudioTrackInfo trackInfo, UdioAudioSourceManager sourceManager) { + super(trackInfo); + + this.sourceManager = sourceManager; + } + + @Override + public void process(LocalAudioTrackExecutor localExecutor) throws Exception { + + + try (HttpInterface httpInterface = sourceManager.getHttpInterface()) { + String playbackUrl = loadPlaybackUrl(httpInterface); + + log.debug("Starting Udio track from URL: {}", playbackUrl); + + try (PersistentHttpStream stream = new PersistentHttpStream(httpInterface, new URI(playbackUrl), null)) { + processDelegate(new Mp3AudioTrack(trackInfo, stream), localExecutor); + } + } + } + + private String loadPlaybackUrl(HttpInterface httpInterface) throws IOException { + JsonBrowser config = loadPlayerConfig(httpInterface); + + if (config == null) { + throw new FriendlyException("Track information not present on the page.", SUSPICIOUS, null); + } + + JsonBrowser trackInfo; + try { + trackInfo = config.index(3).get("children").index(3).get("children").index(3).get("track"); + } catch (NullPointerException e) { + throw new FriendlyException("Track information not found on the page.", SUSPICIOUS, null); + } + + return trackInfo.get("song_path").text(); + } + + private JsonBrowser loadPlayerConfig(HttpInterface httpInterface) throws IOException { + try (CloseableHttpResponse response = httpInterface.execute(new HttpGet(trackInfo.identifier))) { + int statusCode = response.getStatusLine().getStatusCode(); + + if (!HttpClientTools.isSuccessWithContent(statusCode)) { + throw new FriendlyException("Server responded with an error.", SUSPICIOUS, + new IllegalStateException("Response code for player config is " + statusCode)); + } + + return sourceManager.loadConfigJsonFromPageContent(IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8)); + } + } +} From fa93bf6af4b12e4ab77b1c375fcffb36b0c88a9c Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Thu, 9 May 2024 15:34:41 -0400 Subject: [PATCH 116/155] Update docker build process --- Dockerfile | 25 +++++++++++++++---------- docker-compose.yml | 2 +- startup.sh | 16 ++++++++-------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 21f8be2..aed3bb3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,27 @@ -FROM openjdk:17-jdk-slim +FROM eclipse-temurin:17-jdk-alpine as build -RUN apt-get -y update -RUN apt-get -y install netcat -RUN apt-get -y install curl +COPY .mvn/ .mvn +COPY mvnw pom.xml ./ +COPY src ./src +COPY bot.properties.example bot.properties ./ + +RUN ["chmod", "+x", "./mvnw"] +RUN ./mvnw install + + +FROM eclipse-temurin:17-jre-alpine + +RUN apk add netcat-openbsd +RUN apk add curl WORKDIR /app ARG API_PORT=9000 EXPOSE ${API_PORT} -COPY .mvn/ .mvn -COPY mvnw pom.xml ./ -COPY src ./src COPY bot.properties.example bot.properties ./ COPY startup.sh ./ - -RUN ["chmod", "+x", "./mvnw"] -RUN ./mvnw install +COPY --from=build /target/netneutrality-jar-with-dependencies.jar ./ RUN ["chmod", "+x", "./startup.sh"] CMD ["./startup.sh"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9cbe57e..4a4bdd3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.3' services: db: - image: mariadb:10.7 + image: mariadb:lts container_name: db restart: unless-stopped volumes: diff --git a/startup.sh b/startup.sh index ae06536..916905d 100644 --- a/startup.sh +++ b/startup.sh @@ -1,10 +1,10 @@ -#!/bin/bash +#!/bin/sh -function prop { +prop() { grep "${1}" bot.properties | cut -d'=' -f2 } -function _term() { +_term() { echo "Caught SIGTERM/SIGINT signal, graceful shutdown of bot.." if [ -z "$pid" ]; then echo "Bot isn't running, exiting." @@ -16,10 +16,10 @@ function _term() { fi } -trap _term SIGTERM -trap _term SIGINT +trap _term TERM +trap _term INT -if [ ! -f /bin/nc ]; then +if [ ! -f /usr/bin/nc ]; then echo "nc not found. Exiting." exit 1 fi @@ -40,9 +40,9 @@ echo "Waiting 10 seconds for database to start.." sleep 10 echo "Checking if MySQL / MariaDB is started.." -if /bin/nc -z "$MYSQL_HOST" "$MYSQL_PORT"; then +if /usr/bin/nc -z "$MYSQL_HOST" "$MYSQL_PORT"; then echo "Database OK. Starting bot.."; - /usr/local/openjdk-17/bin/java -jar target/netneutrality-jar-with-dependencies.jar & + /opt/java/openjdk/bin/java -jar /app/netneutrality-jar-with-dependencies.jar & pid=$! wait "$pid" From fe70bba68951d9b4213730545bb8e7b02f6e353c Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Thu, 9 May 2024 16:17:35 -0400 Subject: [PATCH 117/155] Add MP3 direct link to allowed sources --- src/main/java/netneutrality/music/SourceFinder.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index eb64383..fc9e835 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -20,6 +20,7 @@ public class SourceFinder { Vimeo, YTSearch, Udio, + DirectLinkMp3, Nothing } @@ -28,6 +29,7 @@ public class SourceFinder { private static final Pattern youtubeMusicPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?music\\.(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-zA-Z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); private static final Pattern udioPattern = Pattern.compile("^https://www.udio.com/songs/[0-9A-Za-z]+$", Pattern.CASE_INSENSITIVE); + private static final Pattern mp3Pattern = Pattern.compile("^https?://(?:.*)(?:.mp3)$", Pattern.CASE_INSENSITIVE); public static AudioSourceType getSource(String url) { @@ -35,6 +37,7 @@ public class SourceFinder { Matcher youtubeMusicMatcher = youtubeMusicPattern.matcher(url); Matcher soundcloudMatcher = soundcloudPattern.matcher(url); Matcher udioMatcher = udioPattern.matcher(url); + Matcher mp3Matcher = mp3Pattern.matcher(url); if (youtubeMatcher.find()) return AudioSourceType.Youtube; @@ -48,6 +51,9 @@ public class SourceFinder { if (udioMatcher.find()) return AudioSourceType.Udio; + if (mp3Matcher.find()) + return AudioSourceType.DirectLinkMp3; + if (!(url.startsWith("http://") || url.startsWith("https://"))) return AudioSourceType.YTSearch; @@ -58,7 +64,7 @@ public class SourceFinder { String identifier; identifier = switch (getSource(url)) { - case Youtube, YTMusic, Soundcloud, Udio -> url; + case Youtube, YTMusic, Soundcloud, Udio, DirectLinkMp3 -> url; case YTSearch -> "ytsearch:" + url; default -> null; }; From 20d362978c09b2ab9a81a0dba684ecab7bac2840 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Thu, 9 May 2024 16:24:31 -0400 Subject: [PATCH 118/155] Add MP3 direct link (fix) --- src/main/java/netneutrality/music/MusicManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index cde9d79..2d6629b 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -10,6 +10,7 @@ package netneutrality.music; 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.http.HttpAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; @@ -82,6 +83,7 @@ public class MusicManager { playerManager.registerSourceManager(youtubeSource); playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); playerManager.registerSourceManager(new UdioAudioSourceManager()); + playerManager.registerSourceManager(new HttpAudioSourceManager()); } public boolean isNotConnectedTo(VoiceChannel vChannel) { From 8742ecc09685e7465c55d6fc17d59bd6b8ec334b Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Fri, 10 May 2024 06:53:15 -0400 Subject: [PATCH 119/155] Udio: Fix track loading when lyrics are present in the JSON --- .../netneutrality/music/SourceFinder.java | 1 - .../music/source/UdioAudioSourceManager.java | 46 +++++++++++-------- .../music/source/UdioAudioTrack.java | 15 ++---- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index fc9e835..a8fef91 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -31,7 +31,6 @@ public class SourceFinder { private static final Pattern udioPattern = Pattern.compile("^https://www.udio.com/songs/[0-9A-Za-z]+$", Pattern.CASE_INSENSITIVE); private static final Pattern mp3Pattern = Pattern.compile("^https?://(?:.*)(?:.mp3)$", Pattern.CASE_INSENSITIVE); - public static AudioSourceType getSource(String url) { Matcher youtubeMatcher = youtubePattern.matcher(url); Matcher youtubeMusicMatcher = youtubeMusicPattern.matcher(url); diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java index 2c191cb..9a07188 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java @@ -5,6 +5,8 @@ package netneutrality.music.source;/* * https://discord.gg/CdFcyQ */ +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.io.JsonEOFException; import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager; import com.sedmelluq.discord.lavaplayer.tools.DataFormatTools; @@ -25,6 +27,8 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.DataInput; import java.io.DataOutput; @@ -38,6 +42,9 @@ import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity. public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigurable { + private static final Logger log = LoggerFactory.getLogger(UdioAudioSourceManager.class); + + private static final String TRACK_URL_REGEX = "^https://www.udio.com/songs/[0-9A-Za-z]+$"; private static final Pattern trackUrlPattern = Pattern.compile(TRACK_URL_REGEX); @@ -58,9 +65,6 @@ public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigura @Override public AudioItem loadItem(AudioPlayerManager manager, AudioReference reference) { - // start = "og:audio:url\",\"content\":\" - // end = \"}], - if (!trackUrlPattern.matcher(reference.identifier).matches()) { return null; } @@ -90,17 +94,10 @@ public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigura } private AudioTrack loadTrackFromPageContent(String trackUrl, String content) throws IOException { - JsonBrowser config = loadConfigJsonFromPageContent(content); + JsonBrowser trackInfo = loadTrackInfoFromPageContent(content); - if (config == null) { - throw new FriendlyException("Track information not found on the page.", SUSPICIOUS, null); - } - - JsonBrowser trackInfo; - try { - trackInfo = config.index(3).get("children").index(3).get("children").index(3).get("track"); - } catch (NullPointerException e) { - throw new FriendlyException("Track information not found on the page.", SUSPICIOUS, null); + if (trackInfo == null) { + throw new FriendlyException("Udio: Failed to extract track information from web page.", SUSPICIOUS, null); } return new UdioAudioTrack(new AudioTrackInfo( @@ -113,15 +110,24 @@ public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigura ), this); } - JsonBrowser loadConfigJsonFromPageContent(String content) throws IOException { - String configText = DataFormatTools.extractBetween(content, "self.__next_f.push([1,\"8:", "\\n"); - System.out.println(configText); + JsonBrowser loadTrackInfoFromPageContent(String content) throws IOException { + // start = self.__next_f.push([1,"8: + // end = \n"]) - if (configText != null) { - configText = configText.replace("\\", ""); - System.out.println(configText); + String json = DataFormatTools.extractBetween(content, "self.__next_f.push([1,\"8:", "\\n\"])"); + + if (json != null) { + json = json.replace("\\", ""); + + try { + JsonBrowser parsedJson = JsonBrowser.parse(json); + return parsedJson.index(3).get("children").index(3).get("children").index(3).get("track"); + } catch (JsonParseException e) { + log.debug("Udio HTML: {}", content); + + return null; + } - return JsonBrowser.parse(configText); } return null; diff --git a/src/main/java/netneutrality/music/source/UdioAudioTrack.java b/src/main/java/netneutrality/music/source/UdioAudioTrack.java index e44f97f..d62d3be 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioTrack.java +++ b/src/main/java/netneutrality/music/source/UdioAudioTrack.java @@ -59,17 +59,10 @@ public class UdioAudioTrack extends DelegatedAudioTrack { } private String loadPlaybackUrl(HttpInterface httpInterface) throws IOException { - JsonBrowser config = loadPlayerConfig(httpInterface); + JsonBrowser trackInfo = loadPlayerConfig(httpInterface); - if (config == null) { - throw new FriendlyException("Track information not present on the page.", SUSPICIOUS, null); - } - - JsonBrowser trackInfo; - try { - trackInfo = config.index(3).get("children").index(3).get("children").index(3).get("track"); - } catch (NullPointerException e) { - throw new FriendlyException("Track information not found on the page.", SUSPICIOUS, null); + if (trackInfo == null) { + throw new FriendlyException("Udio: Failed to extract track information from web page.", SUSPICIOUS, null); } return trackInfo.get("song_path").text(); @@ -84,7 +77,7 @@ public class UdioAudioTrack extends DelegatedAudioTrack { new IllegalStateException("Response code for player config is " + statusCode)); } - return sourceManager.loadConfigJsonFromPageContent(IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8)); + return sourceManager.loadTrackInfoFromPageContent(IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8)); } } } From d9481f4d8532a4823755180b34cbafa0889c101f Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 11 May 2024 11:20:52 -0400 Subject: [PATCH 120/155] Fix queue shuffling where a track was removed on each shuffle --- src/main/java/netneutrality/music/QueueManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 0901f4f..34901fd 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -246,7 +246,6 @@ public class QueueManager { TrackInfo current = queue.poll(); ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); - newQueue.remove(0); Collections.shuffle(newQueue); From d61d15f36d0670cbd18bd324845b02737ecdd069 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 14 May 2024 03:45:09 -0400 Subject: [PATCH 121/155] Remove unused files and add bot version at runtime --- bot.properties.example | 1 + .../java/netneutrality/NetNeutrality.java | 13 +- .../db/entities/OSellyOrder.java | 114 ------------------ src/main/java/netneutrality/http/Selly.java | 82 ------------- .../java/netneutrality/http/WebModule.java | 9 +- .../netneutrality/thread/ThreadManager.java | 5 +- .../java/netneutrality/utils/Settings.java | 8 +- src/main/resources/spy.properties | 4 - 8 files changed, 27 insertions(+), 209 deletions(-) delete mode 100644 src/main/java/netneutrality/db/entities/OSellyOrder.java delete mode 100644 src/main/java/netneutrality/http/Selly.java delete mode 100644 src/main/resources/spy.properties diff --git a/bot.properties.example b/bot.properties.example index 66a5f53..29a40f3 100644 --- a/bot.properties.example +++ b/bot.properties.example @@ -1,4 +1,5 @@ BOT_ENV=dev +BOT_VERSION=1.0.0 BOT_TOKEN= BOT_PREFIX= BOT_OWNER= diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 330f31d..37caa25 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -1,5 +1,11 @@ package netneutrality; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; @@ -30,6 +36,8 @@ public class NetNeutrality { private static JDA jda; public final static Logger logger = LoggerFactory.getLogger(NetNeutrality.class); + public static final String VERSION = "2.0.0"; + public static void main(String[] args) { String sentryDsn = Settings.getInstance().get("SENTRY_DSN"); String env = Settings.getInstance().get("BOT_ENV", "dev"); @@ -37,9 +45,8 @@ public class NetNeutrality { options.setDsn(sentryDsn); options.setEnvironment(env); options.setTracesSampleRate(1.0); - //options.setDebug(env.equals("dev")); options.setDebug(false); - options.setRelease("netneutrality@2.0.0"); + options.setRelease(String.format("netneutrality@%s", VERSION)); }); if ("dev".equals(env)) { @@ -68,8 +75,6 @@ public class NetNeutrality { .build(); jda.awaitReady(); } catch (InvalidTokenException | IllegalArgumentException | InterruptedException e) { - Sentry.captureException(e); - LogHandler.log(e); System.exit(1); } diff --git a/src/main/java/netneutrality/db/entities/OSellyOrder.java b/src/main/java/netneutrality/db/entities/OSellyOrder.java deleted file mode 100644 index 9c15182..0000000 --- a/src/main/java/netneutrality/db/entities/OSellyOrder.java +++ /dev/null @@ -1,114 +0,0 @@ -package netneutrality.db.entities; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -public class OSellyOrder { - - private final String id; - private final String productId; - private final String email; - private final String ip; - private final float value; - private final String currency; - private final String gateway; - private final int risk; - private final int status; - private final int cryptoValue; - private final String cryptoAddress; - private final float usdValue; - private final String createdAt; - - public OSellyOrder(String id, String productId, String email, String ip, float value, String currency, String gateway, int risk, int status, int cryptoValue, String cryptoAddress, float usdValue, String createdAt) { - this.id = id; - this.productId = productId; - this.email = email; - this.ip = ip; - this.value = value; - this.currency = currency; - this.gateway = gateway; - this.risk = risk; - this.status = status; - this.cryptoValue = cryptoValue; - this.cryptoAddress = cryptoAddress; - this.usdValue = usdValue; - this.createdAt = createdAt; - } - - //TODO: Construct from JSONObject - - public String getId() { - return id; - } - - public String getProductId() { - return productId; - } - - public String getEmail() { - return email; - } - - public String getIp() { - return ip; - } - - public float getValue() { - return value; - } - - public String getCurrency() { - return currency; - } - - public String getGateway() { - return gateway; - } - - public int getRisk() { - return risk; - } - - public int getStatus() { - return status; - } - - public int getCryptoValue() { - return cryptoValue; - } - - public String getCryptoAddress() { - return cryptoAddress; - } - - public float getUsdValue() { - return usdValue; - } - - public String getCreatedAt() { - return createdAt; - } - - @Override - public String toString() { - return "MSellyOrder{" + - "id='" + id + '\'' + - ", product_id='" + productId + '\'' + - ", email='" + email + '\'' + - ", ip='" + ip + '\'' + - ", value='" + value + '\'' + - ", currency='" + currency + '\'' + - ", gateway='" + gateway + '\'' + - ", risk='" + risk + '\'' + - ", status='" + status + '\'' + - ", cryptoValue='" + cryptoValue + '\'' + - ", cryptoAddress='" + cryptoAddress + '\'' + - ", usdValue='" + usdValue + '\'' + - ", createdAt='" + createdAt + '\'' + - '}'; - } -} diff --git a/src/main/java/netneutrality/http/Selly.java b/src/main/java/netneutrality/http/Selly.java deleted file mode 100644 index 5bad45c..0000000 --- a/src/main/java/netneutrality/http/Selly.java +++ /dev/null @@ -1,82 +0,0 @@ -package netneutrality.http; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import netneutrality.db.entities.OSellyOrder; -import org.json.JSONArray; -import org.json.JSONObject; - -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -public class Selly { - - private final byte[] encodedAuth; - - public Selly(String email, String apiKey) { - String concat = email + ":" + apiKey; - encodedAuth = Base64.getEncoder().encode(concat.getBytes()); - } - - public Map<String, OSellyOrder> getOrders() { - WebModule sellyApi = new WebModule("https://selly.gg/api/v2/orders"); - Map<String, String> headers = new HashMap<>(); - Map<String, OSellyOrder> orders = new HashMap<>(); - headers.put("Authorization", "Basic " + new String(encodedAuth)); - JSONArray response = null; - try { - sellyApi.request(headers); - response = sellyApi.getAsArray(); - } catch (IOException e) { - e.printStackTrace(); - } - - - for (int i = 0; i < response.length(); i++) { - JSONObject order = response.getJSONObject(i); - orders.put(order.getString("id"), new OSellyOrder(order.getString("id"), order.getString("product_id"), order.getString("email"), order.getString("ip_address"), - Float.parseFloat(order.getString("value")), order.getString("currency"), order.getString("gateway"), order.getInt("risk_level"), order.getInt("status"), - order.getInt("crypto_value"), order.getString("crypto_address"), Float.parseFloat(order.getString("usd_value")), order.getString("created_at"))); - } - - - return orders; - } - - public JSONObject getOrderById(String id) { - WebModule order = new WebModule("https://selly.gg/api/v2/orders/" + id); - Map<String, String> headers = new HashMap<>(); - headers.put("Authorization", "Basic " + new String(encodedAuth)); - JSONObject response = null; - try { - order.request(headers); - response = order.getAsObject(); - } catch (IOException e) { - e.printStackTrace(); - } - - return response; - } - - public JSONArray getProducts() { - WebModule orders = new WebModule("https://selly.gg/api/v2/products"); - Map<String, String> headers = new HashMap<>(); - headers.put("Authorization", "Basic " + new String(encodedAuth)); - JSONArray response = null; - - try { - orders.request(headers); - response = orders.getAsArray(); - } catch (IOException e) { - e.printStackTrace(); - } - - return response; - } -} diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index 376037b..ce17a78 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -1,7 +1,14 @@ package netneutrality.http; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + import io.sentry.Breadcrumb; import io.sentry.Sentry; +import netneutrality.NetNeutrality; import netneutrality.core.LogHandler; import okhttp3.*; import org.json.JSONArray; @@ -19,7 +26,7 @@ public class WebModule { private final OkHttpClient client = new OkHttpClient(); private Response response; //private final String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 OPR/82.0.4227.43"; - private static final String userAgent = "NetNeutrality/1.0 (Discord bot, anthorob@xtremmail.com)"; + private static final String userAgent = String.format("Net Neutrality/%s (Discord bot, tony@bobert.me)", NetNeutrality.VERSION); public WebModule(String url) { diff --git a/src/main/java/netneutrality/thread/ThreadManager.java b/src/main/java/netneutrality/thread/ThreadManager.java index 335c44b..7854b0f 100644 --- a/src/main/java/netneutrality/thread/ThreadManager.java +++ b/src/main/java/netneutrality/thread/ThreadManager.java @@ -2,8 +2,7 @@ package netneutrality.thread; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import java.util.Map; @@ -53,7 +52,7 @@ public class ThreadManager { try { for (ExecutorService ex : executors.values()) { ex.shutdown(); - ex.awaitTermination(2, TimeUnit.SECONDS); + ex.awaitTermination(1, TimeUnit.SECONDS); } } catch (InterruptedException e) { diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index f0c515e..10f9bf9 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -1,5 +1,11 @@ package netneutrality.utils; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + import org.apache.commons.io.FileUtils; import java.io.File; @@ -34,7 +40,7 @@ public class Settings { loadEnvironmentVariables(); } catch (IOException e) { - System.err.println("Can't find config file: bot.properties"); + System.err.println("Can't find config file or config file is empty: bot.properties"); System.exit(1); } finally { try { diff --git a/src/main/resources/spy.properties b/src/main/resources/spy.properties deleted file mode 100644 index fa4d6da..0000000 --- a/src/main/resources/spy.properties +++ /dev/null @@ -1,4 +0,0 @@ -driverlist=com.mysql.cj.jdbc.Driver -dateformat=yyyy-MM-dd hh:mm:ss a -appender=com.p6spy.engine.spy.appender.StdoutLogger -logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat \ No newline at end of file From 77ef79d28e90fec17516f973d3c7e8224f58e122 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 14 May 2024 04:01:20 -0400 Subject: [PATCH 122/155] Update dependencies and logging implementation --- pom.xml | 37 ++++++++++++------- .../java/netneutrality/NetNeutrality.java | 6 +-- .../command/AbstractCommand.java | 7 ++++ .../java/netneutrality/command/ICommand.java | 3 +- .../netneutrality/core/CommandManager.java | 6 +-- .../core/GuildConfigManager.java | 6 +-- .../java/netneutrality/core/GuildManager.java | 6 +-- .../java/netneutrality/core/LogHandler.java | 6 +-- .../netneutrality/core/SessionManager.java | 6 +-- .../java/netneutrality/db/DBController.java | 6 +-- .../db/controllers/DBMessage.java | 6 +-- .../http/server/ActionHandler.java | 4 +- .../netneutrality/http/server/WebApi.java | 6 +-- .../music/AudioPlayerSendHandler.java | 3 +- .../netneutrality/music/MusicManager.java | 9 ++--- .../netneutrality/music/QueueManager.java | 11 +++--- .../netneutrality/music/SourceFinder.java | 3 +- .../java/netneutrality/music/TrackLoader.java | 9 ++--- .../music/TrackLoadingHandler.java | 9 ++--- .../netneutrality/music/TrackScheduler.java | 9 ++--- .../music/loadable/LoadableSourceManager.java | 6 +-- .../music/source/UdioAudioSourceManager.java | 29 ++++----------- .../music/source/UdioAudioTrack.java | 13 +++---- .../MusicPlayerAutoDisconnectThread.java | 4 +- .../utils/ChannelMessagePurger.java | 6 +-- .../netneutrality/utils/MessageFunction.java | 6 +-- 26 files changed, 107 insertions(+), 115 deletions(-) diff --git a/pom.xml b/pom.xml index 28098f4..a844e85 100644 --- a/pom.xml +++ b/pom.xml @@ -102,6 +102,13 @@ <url>https://maven.lavalink.dev/snapshots</url> </repository> + <repository> + <id>arbjergDev-releases</id> + <name>Lavalink Repository</name> + <url>https://maven.lavalink.dev/releases</url> + </repository> + + </repositories> <dependencies> @@ -114,13 +121,19 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.21</version> + <version>5.0.0-beta.24</version> </dependency> <dependency> <groupId>dev.arbjerg</groupId> <artifactId>lavaplayer</artifactId> <version>0eaeee195f0315b2617587aa3537fa202df07ddc-SNAPSHOT</version> </dependency> + <dependency> + <groupId>dev.lavalink.youtube</groupId> + <artifactId>common</artifactId> + <version>1.2.0</version> + </dependency> + <dependency> <groupId>com.squareup.okhttp3</groupId> @@ -138,16 +151,12 @@ <artifactId>hibernate-hikaricp</artifactId> <version>6.1.7.Final</version> </dependency> + <dependency> <groupId>io.sentry</groupId> <artifactId>sentry</artifactId> <version>7.6.0</version> </dependency> - <dependency> - <groupId>p6spy</groupId> - <artifactId>p6spy</artifactId> - <version>3.9.1</version> - </dependency> <dependency> <groupId>org.json</groupId> @@ -166,6 +175,12 @@ <artifactId>mysql-connector-j</artifactId> <version>8.3.0</version> </dependency> + + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <version>2.23.1</version> + </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> @@ -173,10 +188,11 @@ </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> - <artifactId>log4j-slf4j-impl</artifactId> + <artifactId>log4j-slf4j2-impl</artifactId> <version>2.23.1</version> </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> @@ -194,13 +210,6 @@ <version>4.13.2</version> </dependency> - <dependency> - <groupId>org.openjdk.nashorn</groupId> - <artifactId>nashorn-core</artifactId> - <version>15.4</version> - </dependency> - - </dependencies> </project> \ No newline at end of file diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 37caa25..209a9e4 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -28,13 +28,13 @@ import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class NetNeutrality { private static JDA jda; - public final static Logger logger = LoggerFactory.getLogger(NetNeutrality.class); + public final static Logger logger = LogManager.getLogger(NetNeutrality.class); public static final String VERSION = "2.0.0"; diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 0541a40..158970d 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -1,5 +1,11 @@ package netneutrality.command; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -28,6 +34,7 @@ public abstract class AbstractCommand implements ICommand { return true; } + @Deprecated @Override public void execute(MessageCommandContext context) { // Prefer slash commands diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index bc3f73a..19b3a2d 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -2,8 +2,7 @@ package netneutrality.command; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/netneutrality/core/CommandManager.java b/src/main/java/netneutrality/core/CommandManager.java index 5cb70f4..2e9e316 100644 --- a/src/main/java/netneutrality/core/CommandManager.java +++ b/src/main/java/netneutrality/core/CommandManager.java @@ -13,9 +13,9 @@ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; import netneutrality.NetNeutrality; import netneutrality.command.AbstractCommand; +import org.apache.logging.log4j.LogManager; import org.reflections.Reflections; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.Logger; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; @@ -26,7 +26,7 @@ import java.util.Set; public class CommandManager { - private final static Logger logger = LoggerFactory.getLogger(CommandManager.class); + private final static Logger logger = LogManager.getLogger(CommandManager.class); public static final HashMap<String, AbstractCommand> commands = new HashMap<>(); public static void init() { diff --git a/src/main/java/netneutrality/core/GuildConfigManager.java b/src/main/java/netneutrality/core/GuildConfigManager.java index cb36d2f..78c37ed 100644 --- a/src/main/java/netneutrality/core/GuildConfigManager.java +++ b/src/main/java/netneutrality/core/GuildConfigManager.java @@ -11,8 +11,8 @@ import netneutrality.db.entities.OGuild; import netneutrality.db.entities.OGuildSetting; import netneutrality.utils.JpaUtils; import org.hibernate.Session; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.Map; @@ -20,7 +20,7 @@ import java.util.Set; public class GuildConfigManager { - private static final Logger logger = LoggerFactory.getLogger(GuildConfigManager.class); + private static final Logger logger = LogManager.getLogger(GuildConfigManager.class); private final Guild guild; private final OGuild guildEntity; diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index d195aad..166ed81 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -18,10 +18,10 @@ import netneutrality.db.entities.OGuild; import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; +import org.apache.logging.log4j.LogManager; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.Logger; import java.util.HashSet; import java.util.Map; @@ -30,7 +30,7 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { - private static final Logger logger = LoggerFactory.getLogger(GuildManager.class); + private static final Logger logger = LogManager.getLogger(GuildManager.class); private static final Map<String, GuildManager> managers = new ConcurrentHashMap<>(); private static final SessionFactory sessionFactory = SessionManager.getSessionFactory(); private final Set<String> blacklistCache = new HashSet<>(); diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 47363cb..10620f4 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -14,12 +14,12 @@ import netneutrality.core.context.SlashCommandContext; import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.utils.MessageFunction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class LogHandler { - private final static Logger logger = LoggerFactory.getLogger(LogHandler.class); + private final static Logger logger = LogManager.getLogger(LogHandler.class); /** * Log an exception accordingly diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index f338703..5b4d84f 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -8,20 +8,20 @@ package netneutrality.core; import io.sentry.Sentry; import netneutrality.utils.Settings; +import org.apache.logging.log4j.LogManager; import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Environment; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.Map; public class SessionManager { - private final static Logger logger = LoggerFactory.getLogger(SessionManager.class); + private final static Logger logger = LogManager.getLogger(SessionManager.class); private static StandardServiceRegistry registry; private static SessionFactory sessionFactory; diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 051db3e..a12fcbc 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -8,14 +8,14 @@ package netneutrality.db; */ import netneutrality.core.SessionManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.lang.reflect.InvocationTargetException; public class DBController { - private final static Logger logger = LoggerFactory.getLogger(DBController.class); + private final static Logger logger = LogManager.getLogger(DBController.class); public static <T> T get(Class<T> returnType) { if (returnType == null) diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 0476f7e..9183bd9 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -12,16 +12,16 @@ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.GuildManager; import netneutrality.db.AbstractController; import netneutrality.db.entities.OLogMessage; +import org.apache.logging.log4j.LogManager; import org.hibernate.Session; import org.hibernate.query.Query; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.Logger; import java.util.List; public class DBMessage extends AbstractController { - private final static Logger logger = LoggerFactory.getLogger(DBMessage.class); + private final static Logger logger = LogManager.getLogger(DBMessage.class); public void log(GuildManager guildManager, MessageChannel channel, Member author, Message message) { Session session = getSessionFactory().openSession(); diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 903a27c..7634b08 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -10,8 +10,8 @@ import net.dv8tion.jda.api.entities.Guild; import netneutrality.NetNeutrality; import netneutrality.core.GuildManager; import netneutrality.http.WebModule; +import org.apache.logging.log4j.LogManager; import org.json.JSONObject; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Map; @@ -24,7 +24,7 @@ public class ActionHandler extends AbstractHandler { String path = exchange.getRequestURI().getRawPath(); if (path.equals("/actions/shutdown")) { - LoggerFactory.getLogger(NetNeutrality.class).info("Request to shutdown received"); + LogManager.getLogger(NetNeutrality.class).info("Request to shutdown received"); NetNeutrality.shutdown(); sendStringResponse(exchange, "Shutting down.."); diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 8a01775..de2a307 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -9,8 +9,8 @@ package netneutrality.http.server; import com.sun.net.httpserver.HttpServer; import netneutrality.thread.BaseThreadFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.IOException; import java.net.InetSocketAddress; @@ -19,7 +19,7 @@ import java.util.concurrent.Executors; public class WebApi { - private final static Logger logger = LoggerFactory.getLogger(WebApi.class); + private final static Logger logger = LogManager.getLogger(WebApi.class); private HttpServer server; diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index b36e4d5..2b4f108 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -2,8 +2,7 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 2d6629b..89b2cf0 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -3,8 +3,7 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; @@ -30,8 +29,8 @@ import netneutrality.music.source.UdioAudioSourceManager; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.List; @@ -43,7 +42,7 @@ import java.util.concurrent.TimeUnit; public class MusicManager { - private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); + private final static Logger logger = LogManager.getLogger(MusicManager.class); private final static Map<String, MusicManager> managers = new ConcurrentHashMap<>(); private final static ScheduledExecutorService executor = ThreadManager.getMusicExecutor(); diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 34901fd..d6bab24 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -2,16 +2,15 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.*; import java.util.concurrent.LinkedBlockingDeque; @@ -24,7 +23,7 @@ public class QueueManager { private final AudioTrack track; private final Member member; private final Set<String> skips; - private final Logger logger = LoggerFactory.getLogger(QueueManager.class); + private final Logger logger = LogManager.getLogger(QueueManager.class); public TrackInfo(AudioTrack track, Member member) { this.track = track; @@ -78,7 +77,7 @@ public class QueueManager { } } - private final Logger logger = LoggerFactory.getLogger(QueueManager.class); + private final Logger logger = LogManager.getLogger(QueueManager.class); private final TrackScheduler scheduler; private final AudioPlayer player; diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index a8fef91..41e1b66 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -3,8 +3,7 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import java.util.regex.Matcher; diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/netneutrality/music/TrackLoader.java index d648662..4aea43d 100644 --- a/src/main/java/netneutrality/music/TrackLoader.java +++ b/src/main/java/netneutrality/music/TrackLoader.java @@ -2,8 +2,7 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; @@ -13,15 +12,15 @@ import netneutrality.music.loadable.CachedSource; import netneutrality.music.loadable.LoadableMusicSource; import netneutrality.music.loadable.LoadableSong; import netneutrality.thread.ThreadManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.List; public class TrackLoader implements Runnable { - private final Logger logger = LoggerFactory.getLogger(TrackLoader.class); + private final Logger logger = LogManager.getLogger(TrackLoader.class); private final CommandContext context; private final MusicManager musicManager; private final AudioPlayerManager audioPlayerManager; diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index ccd5151..f655008 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -2,8 +2,7 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ @@ -15,13 +14,13 @@ import net.dv8tion.jda.api.entities.Guild; import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.utils.MessageFunction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.function.Consumer; public class TrackLoadingHandler implements AudioLoadResultHandler { - private final Logger logger = LoggerFactory.getLogger(TrackLoadingHandler.class); + private final Logger logger = LogManager.getLogger(TrackLoadingHandler.class); private final String identifier; private final SourceFinder.AudioSourceType type; diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 5e7bc1d..d21d8a6 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -2,8 +2,7 @@ package netneutrality.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; @@ -17,11 +16,11 @@ import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.LogHandler; import netneutrality.utils.MessageFunction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class TrackScheduler extends AudioEventAdapter { - private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class); + private final static Logger logger = LogManager.getLogger(TrackScheduler.class); private final QueueManager queueManager; private final MusicManager manager; diff --git a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java index ff2c46e..0d3102a 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java +++ b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java @@ -7,9 +7,9 @@ package netneutrality.music.loadable; */ import netneutrality.http.WebModule; +import org.apache.logging.log4j.LogManager; import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.Logger; import java.time.OffsetDateTime; import java.util.Collections; @@ -19,7 +19,7 @@ import java.util.Map; public class LoadableSourceManager { - private final Logger logger = LoggerFactory.getLogger(LoadableSourceManager.class); + private final Logger logger = LogManager.getLogger(LoadableSourceManager.class); private static final Map<String, CachedSource> cache = new HashMap<>(); public CachedSource get(LoadableMusicSource source) { diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java index 9a07188..836c275 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java @@ -1,12 +1,11 @@ -package netneutrality.music.source;/* +package netneutrality.music.source; +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.io.JsonEOFException; import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager; import com.sedmelluq.discord.lavaplayer.tools.DataFormatTools; @@ -14,7 +13,6 @@ import com.sedmelluq.discord.lavaplayer.tools.ExceptionTools; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser; import com.sedmelluq.discord.lavaplayer.tools.io.HttpClientTools; -import com.sedmelluq.discord.lavaplayer.tools.io.HttpConfigurable; import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface; import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager; import com.sedmelluq.discord.lavaplayer.track.AudioItem; @@ -23,26 +21,22 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import org.apache.commons.io.IOUtils; import org.apache.http.HttpStatus; -import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.HttpClientBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.function.Consumer; -import java.util.function.Function; import java.util.regex.Pattern; import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity.SUSPICIOUS; -public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigurable { +public class UdioAudioSourceManager implements AudioSourceManager { - private static final Logger log = LoggerFactory.getLogger(UdioAudioSourceManager.class); + private static final Logger log = LogManager.getLogger(UdioAudioSourceManager.class); private static final String TRACK_URL_REGEX = "^https://www.udio.com/songs/[0-9A-Za-z]+$"; @@ -153,13 +147,4 @@ public class UdioAudioSourceManager implements AudioSourceManager, HttpConfigura ExceptionTools.closeWithWarnings(httpInterfaceManager); } - @Override - public void configureRequests(Function<RequestConfig, RequestConfig> configurator) { - httpInterfaceManager.configureRequests(configurator); - } - - @Override - public void configureBuilder(Consumer<HttpClientBuilder> configurator) { - httpInterfaceManager.configureBuilder(configurator); - } } diff --git a/src/main/java/netneutrality/music/source/UdioAudioTrack.java b/src/main/java/netneutrality/music/source/UdioAudioTrack.java index d62d3be..8829a08 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioTrack.java +++ b/src/main/java/netneutrality/music/source/UdioAudioTrack.java @@ -1,11 +1,10 @@ -package netneutrality.music.source;/* +package netneutrality.music.source; +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ - import com.sedmelluq.discord.lavaplayer.container.mp3.Mp3AudioTrack; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser; @@ -18,8 +17,8 @@ import com.sedmelluq.discord.lavaplayer.track.playback.LocalAudioTrackExecutor; import org.apache.commons.io.IOUtils; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.IOException; import java.net.URI; @@ -29,7 +28,7 @@ import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity. public class UdioAudioTrack extends DelegatedAudioTrack { - private static final Logger log = LoggerFactory.getLogger(UdioAudioTrack.class); + private static final Logger log = LogManager.getLogger(UdioAudioTrack.class); private final UdioAudioSourceManager sourceManager; diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index 8b8a0b1..938745a 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -11,7 +11,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import netneutrality.NetNeutrality; import netneutrality.music.MusicManager; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; import java.util.List; @@ -36,7 +36,7 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { Thread.sleep(30000); if (conditionsMetToDisconnect(channel)) { - LoggerFactory.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); + LogManager.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); manager.leave(); } } diff --git a/src/main/java/netneutrality/utils/ChannelMessagePurger.java b/src/main/java/netneutrality/utils/ChannelMessagePurger.java index 40aab16..9ff2c31 100644 --- a/src/main/java/netneutrality/utils/ChannelMessagePurger.java +++ b/src/main/java/netneutrality/utils/ChannelMessagePurger.java @@ -16,8 +16,8 @@ import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import netneutrality.core.context.CommandContext; import netneutrality.thread.ThreadManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.List; @@ -27,7 +27,7 @@ import java.util.concurrent.locks.ReentrantLock; public class ChannelMessagePurger { - private static final Logger logger = LoggerFactory.getLogger(ChannelMessagePurger.class); + private static final Logger logger = LogManager.getLogger(ChannelMessagePurger.class); private static final Map<GuildMessageChannel, ChannelMessagePurger> instances = new HashMap<>(); private final GuildMessageChannel channel; private final Lock lock; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 1b8f941..39c31dc 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -25,8 +25,8 @@ import netneutrality.music.MusicManager; import netneutrality.music.QueueManager; import netneutrality.music.SourceFinder; import org.apache.commons.lang3.time.DurationFormatUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.awt.*; import java.time.OffsetDateTime; @@ -37,7 +37,7 @@ import java.util.Set; public class MessageFunction { - private final static Logger logger = LoggerFactory.getLogger(MessageFunction.class); + private final static Logger logger = LogManager.getLogger(MessageFunction.class); public static MessageEmbed buildCurrentlyPlayingMessage(MusicManager manager) { AudioTrack current = manager.getCurrentlyPlaying(); From dd0aa19fcfb1bf5b7ae4b14dcff071df1913d3e0 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 14 May 2024 04:14:31 -0400 Subject: [PATCH 123/155] Add unit test for UdioAudioSourceManager --- .../source/UdioAudioSourceManagerTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java diff --git a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java new file mode 100644 index 0000000..238d43b --- /dev/null +++ b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java @@ -0,0 +1,31 @@ +package netneutrality.music.source; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import com.sedmelluq.discord.lavaplayer.track.AudioItem; +import com.sedmelluq.discord.lavaplayer.track.AudioReference; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class UdioAudioSourceManagerTest { + + @Test + public void loadItem() { + AudioReference reference = new AudioReference("https://www.udio.com/songs/eNmZxqpMt9MRrjFUgYDgyi", null); + + UdioAudioSourceManager udioAudioSourceManager = new UdioAudioSourceManager(); + AudioItem loaded = udioAudioSourceManager.loadItem(null, reference); + + assertNotNull(loaded); + + UdioAudioTrack audioTrack = (UdioAudioTrack) loaded; + AudioTrackInfo info = audioTrack.getInfo(); + + assertNotNull(info); + } +} From 0070e3f5bb58bde2fd693b718394146aca42f296 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 14 May 2024 04:21:18 -0400 Subject: [PATCH 124/155] Use new youtube audio source --- src/main/java/netneutrality/music/MusicManager.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index 89b2cf0..b6c07ce 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -11,12 +11,10 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; -import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; -import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import dev.lavalink.youtube.YoutubeAudioSourceManager; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.GuildManager; @@ -28,7 +26,6 @@ import netneutrality.music.loadable.LoadableSong; import netneutrality.music.source.UdioAudioSourceManager; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; -import netneutrality.utils.Settings; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -75,11 +72,7 @@ public class MusicManager { } public static void initPlayerManager() { - YoutubeAudioSourceManager youtubeSource = new YoutubeAudioSourceManager(true, - Settings.getInstance().get("GG_EMAIL", ""), - Settings.getInstance().get("GG_PASS", "")); - - playerManager.registerSourceManager(youtubeSource); + playerManager.registerSourceManager(new YoutubeAudioSourceManager()); playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); playerManager.registerSourceManager(new UdioAudioSourceManager()); playerManager.registerSourceManager(new HttpAudioSourceManager()); From 70a4cad11ace0d67604261aa5284df9ff43692bd Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 14 May 2024 08:08:18 -0400 Subject: [PATCH 125/155] Clean up the imports, add Readme and change license to Apache --- .gitignore | 1 - LICENSE | 875 ++++-------------- README.md | 12 + docker-compose.yml | 1 + .../java/netneutrality/NetNeutrality.java | 2 +- .../command/AbstractMusicCommand.java | 3 +- .../netneutrality/command/CommandType.java | 3 +- .../command/admin/BlacklistCommand.java | 3 +- .../command/admin/PurgeCommand.java | 3 +- .../command/basic/HelpCommand.java | 3 +- .../command/basic/PingCommand.java | 3 +- .../command/bot/ConfigureCommand.java | 3 +- .../command/crypto/CryptoPriceCommand.java | 3 +- .../command/music/BitconnectCommand.java | 3 +- .../command/music/ClearQueueCommand.java | 3 +- .../music/CurrentlyPlayingCommand.java | 3 +- .../command/music/JoinCommand.java | 3 +- .../command/music/LeaveCommand.java | 3 +- .../command/music/PlayCommand.java | 3 +- .../command/music/QueueCommand.java | 3 +- .../command/music/ShuffleCommand.java | 7 +- .../command/music/SkipCommand.java | 3 +- .../command/music/StopCommand.java | 3 +- .../command/music/ViewQueueCommand.java | 3 +- .../command/music/VolumeCommand.java | 3 +- .../command/music/VoteSkipCommand.java | 3 +- .../java/netneutrality/core/BotState.java | 3 +- .../netneutrality/core/CommandManager.java | 5 +- .../core/GuildConfigManager.java | 9 +- .../java/netneutrality/core/GuildManager.java | 5 +- .../java/netneutrality/core/LogHandler.java | 3 +- .../netneutrality/core/SessionManager.java | 5 +- .../core/context/CommandContext.java | 7 +- .../core/context/MessageCommandContext.java | 3 +- .../core/context/SlashCommandContext.java | 7 +- .../netneutrality/db/AbstractController.java | 3 +- .../java/netneutrality/db/DBController.java | 3 +- src/main/java/netneutrality/db/GSettings.java | 3 +- .../db/controllers/DBBlacklist.java | 3 +- .../db/controllers/DBMessage.java | 5 +- .../netneutrality/db/entities/OBlacklist.java | 3 +- .../netneutrality/db/entities/OGuild.java | 4 +- .../db/entities/OGuildSetting.java | 3 +- .../db/entities/OLogMessage.java | 4 +- .../netneutrality/db/entities/OLogging.java | 3 +- .../netneutrality/db/entities/OLoggingId.java | 7 +- .../exceptions/CommandException.java | 3 +- .../exceptions/CommandExecutionException.java | 3 +- .../exceptions/ExecutorException.java | 3 +- .../hooks/SlashCommandHooks.java | 3 +- .../hooks/guilds/ServerJoinHandler.java | 3 +- .../hooks/message/EditHandler.java | 3 +- .../hooks/message/MessageReceivedHandler.java | 3 +- .../hooks/message/ReactionHandler.java | 3 +- .../hooks/voice/VoiceEventHandler.java | 3 +- .../http/server/AbstractHandler.java | 8 +- .../http/server/ActionHandler.java | 7 +- .../http/server/GuildHandler.java | 3 +- .../http/server/RootHandler.java | 3 +- .../netneutrality/http/server/WebApi.java | 3 +- .../netneutrality/music/TrackScheduler.java | 1 - .../music/loadable/AppleMostPlayed.java | 3 +- .../music/loadable/CachedSource.java | 3 +- .../music/loadable/LoadableMusicSource.java | 9 +- .../music/loadable/LoadableSong.java | 3 +- .../music/loadable/LoadableSourceManager.java | 5 +- .../thread/BaseThreadFactory.java | 7 +- .../MusicPlayerAutoDisconnectThread.java | 3 +- .../netneutrality/thread/ShutdownThread.java | 7 +- .../utils/ChannelMessagePurger.java | 3 +- .../java/netneutrality/utils/JpaUtils.java | 7 +- .../netneutrality/utils/MessageFunction.java | 3 +- .../java/netneutrality/utils/MiscUtils.java | 3 +- .../java/netneutrality/utils/MusicUtils.java | 3 +- .../netneutrality/utils/UserFunction.java | 6 + .../music/LoadableSourceTest.java | 19 +- .../source/UdioAudioSourceManagerTest.java | 2 +- .../netneutrality/utils/SettingsTest.java | 6 +- startup.sh | 3 - 79 files changed, 335 insertions(+), 858 deletions(-) create mode 100644 README.md diff --git a/.gitignore b/.gitignore index a27df78..1a12202 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ *.ctxt # Config file -bot.config bot.properties # Mobile Tools for Java (J2ME) diff --git a/LICENSE b/LICENSE index b7687ab..261eeb9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,201 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - netneutrality - Copyright (C) 2018 Anthony - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - netneutrality Copyright (C) 2018 Anthony - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..41c062b --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Net Neutrality Discord bot + +This is the source code for my custom discord bot. This is a personal project, so I offer no support on how to build it. + +The configuration is contained in the file "bot.properties". There is an example file for all the variables, they can also be overwritten by environment variables. + +The preferred method for running the bot is by using Docker Compose like this: + +```bash +docker compose build +docker compose up -d +``` diff --git a/docker-compose.yml b/docker-compose.yml index 4a4bdd3..3db4bf2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,7 @@ services: MYSQL_PASSWORD: 'password' MYSQL_DATABASE: 'netneutrality' MYSQL_ROOT_PASSWORD: 'password' + MARIADB_AUTO_UPGRADE: '1' ports: - "3306" networks: diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 209a9e4..3f5aa07 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -27,9 +27,9 @@ import netneutrality.thread.ShutdownThread; import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; public class NetNeutrality { diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 25bb332..36d95b1 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -2,8 +2,7 @@ package netneutrality.command; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/netneutrality/command/CommandType.java b/src/main/java/netneutrality/command/CommandType.java index 31c2cfe..84ecc69 100644 --- a/src/main/java/netneutrality/command/CommandType.java +++ b/src/main/java/netneutrality/command/CommandType.java @@ -2,8 +2,7 @@ package netneutrality.command; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ public enum CommandType { diff --git a/src/main/java/netneutrality/command/admin/BlacklistCommand.java b/src/main/java/netneutrality/command/admin/BlacklistCommand.java index cf8fff1..86be8b1 100644 --- a/src/main/java/netneutrality/command/admin/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/admin/BlacklistCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.admin; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; diff --git a/src/main/java/netneutrality/command/admin/PurgeCommand.java b/src/main/java/netneutrality/command/admin/PurgeCommand.java index 2d43587..72942aa 100644 --- a/src/main/java/netneutrality/command/admin/PurgeCommand.java +++ b/src/main/java/netneutrality/command/admin/PurgeCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.admin; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 8ec34f4..0ec10e7 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.basic; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.MessageEmbed; diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index 8a943a9..f832727 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.basic; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 861bd69..61bcafa 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.bot; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Role; diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index ffa0098..63a2e2b 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.crypto; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.OptionMapping; diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index b2e0269..6844b1b 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/ClearQueueCommand.java b/src/main/java/netneutrality/command/music/ClearQueueCommand.java index 54a1b96..0daf844 100644 --- a/src/main/java/netneutrality/command/music/ClearQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ClearQueueCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index 68f4738..a852a4f 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 8a3d7c0..627b3ec 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index d23e940..8b948ce 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 0ef8ec5..f414c8c 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.OptionMapping; diff --git a/src/main/java/netneutrality/command/music/QueueCommand.java b/src/main/java/netneutrality/command/music/QueueCommand.java index 53728ef..5615a82 100644 --- a/src/main/java/netneutrality/command/music/QueueCommand.java +++ b/src/main/java/netneutrality/command/music/QueueCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Member; diff --git a/src/main/java/netneutrality/command/music/ShuffleCommand.java b/src/main/java/netneutrality/command/music/ShuffleCommand.java index 57e3a2a..a5ee873 100644 --- a/src/main/java/netneutrality/command/music/ShuffleCommand.java +++ b/src/main/java/netneutrality/command/music/ShuffleCommand.java @@ -1,8 +1,9 @@ -package netneutrality.command.music;/* +package netneutrality.command.music; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 1a9b679..e52642c 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.OptionMapping; diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 4d869e2..3a87054 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 429930a..58a568f 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 29bd9d2..0943481 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -3,8 +3,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.OptionMapping; diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index a27c612..ef29123 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -2,8 +2,7 @@ package netneutrality.command.music; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; diff --git a/src/main/java/netneutrality/core/BotState.java b/src/main/java/netneutrality/core/BotState.java index dd402f7..f2023c1 100644 --- a/src/main/java/netneutrality/core/BotState.java +++ b/src/main/java/netneutrality/core/BotState.java @@ -2,8 +2,7 @@ package netneutrality.core; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; diff --git a/src/main/java/netneutrality/core/CommandManager.java b/src/main/java/netneutrality/core/CommandManager.java index 2e9e316..f3f599b 100644 --- a/src/main/java/netneutrality/core/CommandManager.java +++ b/src/main/java/netneutrality/core/CommandManager.java @@ -3,8 +3,7 @@ package netneutrality.core; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.interactions.commands.build.CommandData; @@ -14,8 +13,8 @@ import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; import netneutrality.NetNeutrality; import netneutrality.command.AbstractCommand; import org.apache.logging.log4j.LogManager; -import org.reflections.Reflections; import org.apache.logging.log4j.Logger; +import org.reflections.Reflections; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; diff --git a/src/main/java/netneutrality/core/GuildConfigManager.java b/src/main/java/netneutrality/core/GuildConfigManager.java index 78c37ed..4d23ff3 100644 --- a/src/main/java/netneutrality/core/GuildConfigManager.java +++ b/src/main/java/netneutrality/core/GuildConfigManager.java @@ -1,8 +1,9 @@ -package netneutrality.core;/* +package netneutrality.core; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Guild; @@ -10,9 +11,9 @@ import netneutrality.db.GSettings; import netneutrality.db.entities.OGuild; import netneutrality.db.entities.OGuildSetting; import netneutrality.utils.JpaUtils; -import org.hibernate.Session; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.hibernate.Session; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 166ed81..22332ab 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -2,8 +2,7 @@ package netneutrality.core; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Guild; @@ -19,9 +18,9 @@ import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.apache.logging.log4j.Logger; import java.util.HashSet; import java.util.Map; diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 10620f4..e0cdc4b 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -2,8 +2,7 @@ package netneutrality.core; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.Sentry; diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index 5b4d84f..fd4743a 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -2,20 +2,19 @@ package netneutrality.core; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.Sentry; import netneutrality.utils.Settings; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Environment; -import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index ff2d737..bd8e580 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -1,8 +1,9 @@ -package netneutrality.core.context;/* +package netneutrality.core.context; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.JDA; diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java index 32eb42c..595d2e0 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -2,8 +2,7 @@ package netneutrality.core.context; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.Breadcrumb; diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java index 9684e3c..352efa3 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -1,8 +1,9 @@ -package netneutrality.core.context;/* +package netneutrality.core.context; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.Sentry; diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/netneutrality/db/AbstractController.java index b282546..40f68a4 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/netneutrality/db/AbstractController.java @@ -3,8 +3,7 @@ package netneutrality.db; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.core.SessionManager; diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index a12fcbc..d6e0ab4 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -3,8 +3,7 @@ package netneutrality.db; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.core.SessionManager; diff --git a/src/main/java/netneutrality/db/GSettings.java b/src/main/java/netneutrality/db/GSettings.java index 75bb292..1a7edfe 100644 --- a/src/main/java/netneutrality/db/GSettings.java +++ b/src/main/java/netneutrality/db/GSettings.java @@ -2,8 +2,7 @@ package netneutrality.db; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ public enum GSettings { diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 31f8c68..de4ba04 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -2,8 +2,7 @@ package netneutrality.db.controllers; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 9183bd9..85e02ea 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -2,8 +2,7 @@ package netneutrality.db.controllers; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Member; @@ -13,9 +12,9 @@ import netneutrality.core.GuildManager; import netneutrality.db.AbstractController; import netneutrality.db.entities.OLogMessage; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.hibernate.Session; import org.hibernate.query.Query; -import org.apache.logging.log4j.Logger; import java.util.List; diff --git a/src/main/java/netneutrality/db/entities/OBlacklist.java b/src/main/java/netneutrality/db/entities/OBlacklist.java index d8f0228..477f3fa 100644 --- a/src/main/java/netneutrality/db/entities/OBlacklist.java +++ b/src/main/java/netneutrality/db/entities/OBlacklist.java @@ -3,8 +3,7 @@ package netneutrality.db.entities; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import jakarta.persistence.*; diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/netneutrality/db/entities/OGuild.java index 1be8b89..1ca2f9e 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/netneutrality/db/entities/OGuild.java @@ -3,11 +3,11 @@ package netneutrality.db.entities; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import jakarta.persistence.*; + import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/netneutrality/db/entities/OGuildSetting.java index 5116aae..00a9d39 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/netneutrality/db/entities/OGuildSetting.java @@ -3,8 +3,7 @@ package netneutrality.db.entities; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import jakarta.persistence.*; diff --git a/src/main/java/netneutrality/db/entities/OLogMessage.java b/src/main/java/netneutrality/db/entities/OLogMessage.java index dc0da9f..40cb4db 100644 --- a/src/main/java/netneutrality/db/entities/OLogMessage.java +++ b/src/main/java/netneutrality/db/entities/OLogMessage.java @@ -3,11 +3,11 @@ package netneutrality.db.entities; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import jakarta.persistence.*; + import java.time.Instant; @Entity diff --git a/src/main/java/netneutrality/db/entities/OLogging.java b/src/main/java/netneutrality/db/entities/OLogging.java index a690912..ede819c 100644 --- a/src/main/java/netneutrality/db/entities/OLogging.java +++ b/src/main/java/netneutrality/db/entities/OLogging.java @@ -3,8 +3,7 @@ package netneutrality.db.entities; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import jakarta.persistence.*; diff --git a/src/main/java/netneutrality/db/entities/OLoggingId.java b/src/main/java/netneutrality/db/entities/OLoggingId.java index f32f9bb..e551bb5 100644 --- a/src/main/java/netneutrality/db/entities/OLoggingId.java +++ b/src/main/java/netneutrality/db/entities/OLoggingId.java @@ -3,14 +3,13 @@ package netneutrality.db.entities; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ -import org.hibernate.Hibernate; - import jakarta.persistence.Column; import jakarta.persistence.Embeddable; +import org.hibernate.Hibernate; + import java.io.Serial; import java.io.Serializable; import java.util.Objects; diff --git a/src/main/java/netneutrality/exceptions/CommandException.java b/src/main/java/netneutrality/exceptions/CommandException.java index 55524ff..b87eff2 100644 --- a/src/main/java/netneutrality/exceptions/CommandException.java +++ b/src/main/java/netneutrality/exceptions/CommandException.java @@ -3,8 +3,7 @@ package netneutrality.exceptions; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.core.context.CommandContext; diff --git a/src/main/java/netneutrality/exceptions/CommandExecutionException.java b/src/main/java/netneutrality/exceptions/CommandExecutionException.java index 4a65787..c04cf31 100644 --- a/src/main/java/netneutrality/exceptions/CommandExecutionException.java +++ b/src/main/java/netneutrality/exceptions/CommandExecutionException.java @@ -3,8 +3,7 @@ package netneutrality.exceptions; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.core.context.CommandContext; diff --git a/src/main/java/netneutrality/exceptions/ExecutorException.java b/src/main/java/netneutrality/exceptions/ExecutorException.java index 8f58931..0aa97c5 100644 --- a/src/main/java/netneutrality/exceptions/ExecutorException.java +++ b/src/main/java/netneutrality/exceptions/ExecutorException.java @@ -3,8 +3,7 @@ package netneutrality.exceptions; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.core.LogHandler; diff --git a/src/main/java/netneutrality/hooks/SlashCommandHooks.java b/src/main/java/netneutrality/hooks/SlashCommandHooks.java index 598f733..6c6e809 100644 --- a/src/main/java/netneutrality/hooks/SlashCommandHooks.java +++ b/src/main/java/netneutrality/hooks/SlashCommandHooks.java @@ -2,8 +2,7 @@ package netneutrality.hooks; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; diff --git a/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java b/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java index f556970..cb33ea2 100644 --- a/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java +++ b/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java @@ -3,8 +3,7 @@ package netneutrality.hooks.guilds; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.events.guild.GuildJoinEvent; diff --git a/src/main/java/netneutrality/hooks/message/EditHandler.java b/src/main/java/netneutrality/hooks/message/EditHandler.java index 5ee3bd3..cf03953 100644 --- a/src/main/java/netneutrality/hooks/message/EditHandler.java +++ b/src/main/java/netneutrality/hooks/message/EditHandler.java @@ -3,8 +3,7 @@ package netneutrality.hooks.message; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; diff --git a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java index f9ec8c3..c1935ea 100644 --- a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java @@ -2,8 +2,7 @@ package netneutrality.hooks.message; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.Breadcrumb; diff --git a/src/main/java/netneutrality/hooks/message/ReactionHandler.java b/src/main/java/netneutrality/hooks/message/ReactionHandler.java index abcf8b2..994214d 100644 --- a/src/main/java/netneutrality/hooks/message/ReactionHandler.java +++ b/src/main/java/netneutrality/hooks/message/ReactionHandler.java @@ -2,8 +2,7 @@ package netneutrality.hooks.message; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Member; diff --git a/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java b/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java index 0ef6fe4..2b983c8 100644 --- a/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java +++ b/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java @@ -2,8 +2,7 @@ package netneutrality.hooks.voice; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; diff --git a/src/main/java/netneutrality/http/server/AbstractHandler.java b/src/main/java/netneutrality/http/server/AbstractHandler.java index 3fe8581..4b54c69 100644 --- a/src/main/java/netneutrality/http/server/AbstractHandler.java +++ b/src/main/java/netneutrality/http/server/AbstractHandler.java @@ -1,11 +1,11 @@ -package netneutrality.http.server;/* +package netneutrality.http.server; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ - import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index 7634b08..cc8a9af 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -1,8 +1,9 @@ -package netneutrality.http.server;/* +package netneutrality.http.server; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sun.net.httpserver.HttpExchange; diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/netneutrality/http/server/GuildHandler.java index b709f13..567e41c 100644 --- a/src/main/java/netneutrality/http/server/GuildHandler.java +++ b/src/main/java/netneutrality/http/server/GuildHandler.java @@ -3,8 +3,7 @@ package netneutrality.http.server; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sun.net.httpserver.HttpExchange; diff --git a/src/main/java/netneutrality/http/server/RootHandler.java b/src/main/java/netneutrality/http/server/RootHandler.java index 94d9b00..4a133c1 100644 --- a/src/main/java/netneutrality/http/server/RootHandler.java +++ b/src/main/java/netneutrality/http/server/RootHandler.java @@ -3,8 +3,7 @@ package netneutrality.http.server; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sun.net.httpserver.HttpExchange; diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index de2a307..e3251f2 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -3,8 +3,7 @@ package netneutrality.http.server; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sun.net.httpserver.HttpServer; diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index d21d8a6..837c522 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -12,7 +12,6 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.core.LogHandler; import netneutrality.utils.MessageFunction; diff --git a/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java b/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java index b6e961b..8f87a11 100644 --- a/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java +++ b/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java @@ -2,8 +2,7 @@ package netneutrality.music.loadable; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import org.json.JSONArray; diff --git a/src/main/java/netneutrality/music/loadable/CachedSource.java b/src/main/java/netneutrality/music/loadable/CachedSource.java index 3be39ed..749ffd8 100644 --- a/src/main/java/netneutrality/music/loadable/CachedSource.java +++ b/src/main/java/netneutrality/music/loadable/CachedSource.java @@ -2,8 +2,7 @@ package netneutrality.music.loadable; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ diff --git a/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java b/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java index c1f6cd4..fb2479c 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java +++ b/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java @@ -1,16 +1,9 @@ package netneutrality.music.loadable; -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import org.json.JSONObject; diff --git a/src/main/java/netneutrality/music/loadable/LoadableSong.java b/src/main/java/netneutrality/music/loadable/LoadableSong.java index d5e2872..6a7c0e2 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSong.java +++ b/src/main/java/netneutrality/music/loadable/LoadableSong.java @@ -2,8 +2,7 @@ package netneutrality.music.loadable; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ public record LoadableSong(String artist, String name, String artworkUrl) { diff --git a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java index 0d3102a..b16957e 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java +++ b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java @@ -2,14 +2,13 @@ package netneutrality.music.loadable; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; -import org.json.JSONObject; import org.apache.logging.log4j.Logger; +import org.json.JSONObject; import java.time.OffsetDateTime; import java.util.Collections; diff --git a/src/main/java/netneutrality/thread/BaseThreadFactory.java b/src/main/java/netneutrality/thread/BaseThreadFactory.java index 75a6f5a..d46a447 100644 --- a/src/main/java/netneutrality/thread/BaseThreadFactory.java +++ b/src/main/java/netneutrality/thread/BaseThreadFactory.java @@ -1,8 +1,9 @@ -package netneutrality.thread;/* +package netneutrality.thread; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.exceptions.ExecutorException; diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index 938745a..b0b5b5a 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -2,8 +2,7 @@ package netneutrality.thread; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/netneutrality/thread/ShutdownThread.java b/src/main/java/netneutrality/thread/ShutdownThread.java index ca926b7..72afaad 100644 --- a/src/main/java/netneutrality/thread/ShutdownThread.java +++ b/src/main/java/netneutrality/thread/ShutdownThread.java @@ -1,8 +1,9 @@ -package netneutrality.thread;/* +package netneutrality.thread; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.NetNeutrality; diff --git a/src/main/java/netneutrality/utils/ChannelMessagePurger.java b/src/main/java/netneutrality/utils/ChannelMessagePurger.java index 9ff2c31..774831c 100644 --- a/src/main/java/netneutrality/utils/ChannelMessagePurger.java +++ b/src/main/java/netneutrality/utils/ChannelMessagePurger.java @@ -2,8 +2,7 @@ package netneutrality.utils; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.ISpan; diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/netneutrality/utils/JpaUtils.java index 4625e84..ccca07e 100644 --- a/src/main/java/netneutrality/utils/JpaUtils.java +++ b/src/main/java/netneutrality/utils/JpaUtils.java @@ -1,8 +1,9 @@ -package netneutrality.utils;/* +package netneutrality.utils; + +/* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import io.sentry.Breadcrumb; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 39c31dc..91c16fa 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -3,8 +3,7 @@ package netneutrality.utils; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; diff --git a/src/main/java/netneutrality/utils/MiscUtils.java b/src/main/java/netneutrality/utils/MiscUtils.java index 1ff5648..83fd053 100644 --- a/src/main/java/netneutrality/utils/MiscUtils.java +++ b/src/main/java/netneutrality/utils/MiscUtils.java @@ -2,8 +2,7 @@ package netneutrality.utils; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/netneutrality/utils/MusicUtils.java index 71a1046..163f8c2 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/netneutrality/utils/MusicUtils.java @@ -2,8 +2,7 @@ package netneutrality.utils; /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import net.dv8tion.jda.api.entities.Member; diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/netneutrality/utils/UserFunction.java index cb33152..fbbe0f6 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/netneutrality/utils/UserFunction.java @@ -1,5 +1,11 @@ package netneutrality.utils; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; diff --git a/src/test/java/netneutrality/music/LoadableSourceTest.java b/src/test/java/netneutrality/music/LoadableSourceTest.java index 826a477..9100343 100644 --- a/src/test/java/netneutrality/music/LoadableSourceTest.java +++ b/src/test/java/netneutrality/music/LoadableSourceTest.java @@ -1,33 +1,24 @@ package netneutrality.music; + /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import netneutrality.music.loadable.AppleMostPlayed; import netneutrality.music.loadable.CachedSource; -import netneutrality.music.loadable.LoadableSong; import netneutrality.music.loadable.LoadableSourceManager; -import org.junit.Before; import org.junit.Test; -import java.util.List; - -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; public class LoadableSourceTest { - LoadableSourceManager loadableSourceManager; - - @Before - public void setUp() throws Exception { - loadableSourceManager = new LoadableSourceManager(); - } - @Test public void cachedSourceAccess() { + LoadableSourceManager loadableSourceManager = new LoadableSourceManager(); + CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed()); CachedSource sameCachedSource = loadableSourceManager.get(new AppleMostPlayed()); diff --git a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java index 238d43b..e82f49b 100644 --- a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java +++ b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java @@ -10,7 +10,7 @@ import com.sedmelluq.discord.lavaplayer.track.AudioReference; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; public class UdioAudioSourceManagerTest { diff --git a/src/test/java/netneutrality/utils/SettingsTest.java b/src/test/java/netneutrality/utils/SettingsTest.java index 3c7f452..38fd259 100644 --- a/src/test/java/netneutrality/utils/SettingsTest.java +++ b/src/test/java/netneutrality/utils/SettingsTest.java @@ -1,15 +1,15 @@ package netneutrality.utils; + /* * Copyright (c) anthorob * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ + * https://discord.gg/qUa6zNFZsd */ import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; public class SettingsTest { diff --git a/startup.sh b/startup.sh index 916905d..9b1262b 100644 --- a/startup.sh +++ b/startup.sh @@ -50,6 +50,3 @@ else echo "No connection to database, shutting down.." exit 1 fi - - - From e778fa28744cc723d91dc59f512b7bc0215a3801 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 14 May 2024 08:52:57 -0400 Subject: [PATCH 126/155] Update pom.xml with new groupId, remove unused plugins and dependencies --- pom.xml | 55 +++++++++---------------------------------------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/pom.xml b/pom.xml index a844e85..9f0e449 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - <groupId>com.xtremcommunity.discord</groupId> + <groupId>me.bobert</groupId> <artifactId>netneutrality</artifactId> <version>2.0.0</version> <name>netneutrality-discord-bot</name> @@ -12,6 +12,7 @@ <packaging>jar</packaging> <properties> + <main.class>netneutrality.NetNeutrality</main.class> <java.version>17</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> @@ -22,45 +23,15 @@ <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.8.0</version> - <configuration> - <release>17</release> - <encoding>UTF-8</encoding> - <source>17</source> - <target>17</target> - </configuration> - </plugin> - <plugin> - <!-- Build an executable JAR --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <version>3.2.0</version> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.7.1</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> - <classpathPrefix>lib/</classpathPrefix> - <mainClass>netneutrality.NetNeutrality</mainClass> + <mainClass>${main.class}</mainClass> </manifest> </archive> - </configuration> - </plugin> - - <plugin> - <artifactId>maven-assembly-plugin</artifactId> - <version>3.3.0</version> - <configuration> - <archive> - <manifest> - <mainClass>netneutrality.NetNeutrality</mainClass> - <addDefaultImplementationEntries>true</addDefaultImplementationEntries> - <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> - </manifest> - <manifestEntries> - <Multi-Release>true</Multi-Release> - </manifestEntries> - </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> @@ -82,7 +53,7 @@ <repositories> <repository> <id>central</id> - <url>https://repo1.maven.org/maven2/</url> + <url>https://repo.maven.apache.org/maven2/</url> </repository> <repository> @@ -96,19 +67,12 @@ <url>https://jitpack.io</url> </repository> - <repository> - <id>arbjergDev-snapshots</id> - <name>Lavalink Repository</name> - <url>https://maven.lavalink.dev/snapshots</url> - </repository> - <repository> <id>arbjergDev-releases</id> <name>Lavalink Repository</name> <url>https://maven.lavalink.dev/releases</url> </repository> - </repositories> <dependencies> @@ -126,7 +90,7 @@ <dependency> <groupId>dev.arbjerg</groupId> <artifactId>lavaplayer</artifactId> - <version>0eaeee195f0315b2617587aa3537fa202df07ddc-SNAPSHOT</version> + <version>2.1.2</version> </dependency> <dependency> <groupId>dev.lavalink.youtube</groupId> @@ -134,7 +98,6 @@ <version>1.2.0</version> </dependency> - <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> @@ -142,12 +105,12 @@ </dependency> <dependency> - <groupId>org.hibernate</groupId> + <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <version>6.1.7.Final</version> </dependency> <dependency> - <groupId>org.hibernate</groupId> + <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-hikaricp</artifactId> <version>6.1.7.Final</version> </dependency> From 9aaa2edfa9017ec232db05bd0c4baf5e852df5b3 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Mon, 20 May 2024 23:27:51 -0400 Subject: [PATCH 127/155] Udio: add more logging when track can't be loaded --- .../music/source/UdioAudioSourceManager.java | 26 +++++++++---------- .../music/source/UdioAudioTrack.java | 6 ++--- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java index 836c275..264e96e 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java @@ -91,6 +91,7 @@ public class UdioAudioSourceManager implements AudioSourceManager { JsonBrowser trackInfo = loadTrackInfoFromPageContent(content); if (trackInfo == null) { + log.debug("Udio HTML: {}", content); throw new FriendlyException("Udio: Failed to extract track information from web page.", SUSPICIOUS, null); } @@ -110,21 +111,20 @@ public class UdioAudioSourceManager implements AudioSourceManager { String json = DataFormatTools.extractBetween(content, "self.__next_f.push([1,\"8:", "\\n\"])"); - if (json != null) { - json = json.replace("\\", ""); - - try { - JsonBrowser parsedJson = JsonBrowser.parse(json); - return parsedJson.index(3).get("children").index(3).get("children").index(3).get("track"); - } catch (JsonParseException e) { - log.debug("Udio HTML: {}", content); - - return null; - } - + if (json == null) { + log.error("Track JSON not found in page"); + return null; } - return null; + try { + String unescapedJson = json.replace("\\", ""); + JsonBrowser parsedJson = JsonBrowser.parse(unescapedJson); + + return parsedJson.index(3).get("children").index(3).get("children").index(3).get("track"); + } catch (JsonParseException e) { + log.error("Failed to parse track JSON: {}", json); + return null; + } } @Override diff --git a/src/main/java/netneutrality/music/source/UdioAudioTrack.java b/src/main/java/netneutrality/music/source/UdioAudioTrack.java index 8829a08..3fd4d31 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioTrack.java +++ b/src/main/java/netneutrality/music/source/UdioAudioTrack.java @@ -44,8 +44,6 @@ public class UdioAudioTrack extends DelegatedAudioTrack { @Override public void process(LocalAudioTrackExecutor localExecutor) throws Exception { - - try (HttpInterface httpInterface = sourceManager.getHttpInterface()) { String playbackUrl = loadPlaybackUrl(httpInterface); @@ -58,7 +56,7 @@ public class UdioAudioTrack extends DelegatedAudioTrack { } private String loadPlaybackUrl(HttpInterface httpInterface) throws IOException { - JsonBrowser trackInfo = loadPlayerConfig(httpInterface); + JsonBrowser trackInfo = loadTrackInfo(httpInterface); if (trackInfo == null) { throw new FriendlyException("Udio: Failed to extract track information from web page.", SUSPICIOUS, null); @@ -67,7 +65,7 @@ public class UdioAudioTrack extends DelegatedAudioTrack { return trackInfo.get("song_path").text(); } - private JsonBrowser loadPlayerConfig(HttpInterface httpInterface) throws IOException { + private JsonBrowser loadTrackInfo(HttpInterface httpInterface) throws IOException { try (CloseableHttpResponse response = httpInterface.execute(new HttpGet(trackInfo.identifier))) { int statusCode = response.getStatusLine().getStatusCode(); From 278924e7d9d552ac67041d59a916241bc50e4cea Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Thu, 23 May 2024 01:31:46 -0400 Subject: [PATCH 128/155] Docker Compose: version is obsolete Docker Compose: persist logs folder pom.xml: add commons-io as dependency --- docker-compose-webapp.yml | 4 ++-- docker-compose.yml | 4 ++-- pom.xml | 23 ++++++++++------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/docker-compose-webapp.yml b/docker-compose-webapp.yml index ffec0e2..07b9f07 100644 --- a/docker-compose-webapp.yml +++ b/docker-compose-webapp.yml @@ -1,5 +1,3 @@ -version: '3.3' - services: db: image: mariadb:10.7 @@ -40,6 +38,8 @@ services: depends_on: - db - bot + volumes: + - ./logs:/app/logs environment: DB_CONNECTION: 'mysql' DB_HOST: 'db' diff --git a/docker-compose.yml b/docker-compose.yml index 3db4bf2..7aa7b13 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.3' - services: db: image: mariadb:lts @@ -25,6 +23,8 @@ services: restart: unless-stopped depends_on: - db + volumes: + - ./logs:/app/logs environment: MYSQL_HOST: 'db' MYSQL_USER: 'java' diff --git a/pom.xml b/pom.xml index 9f0e449..85df176 100644 --- a/pom.xml +++ b/pom.xml @@ -76,12 +76,6 @@ </repositories> <dependencies> - <dependency> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <version>3.7.1</version> - </dependency> - <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> @@ -114,6 +108,11 @@ <artifactId>hibernate-hikaricp</artifactId> <version>6.1.7.Final</version> </dependency> + <dependency> + <groupId>com.mysql</groupId> + <artifactId>mysql-connector-j</artifactId> + <version>8.3.0</version> + </dependency> <dependency> <groupId>io.sentry</groupId> @@ -133,12 +132,6 @@ <version>0.10.2</version> </dependency> - <dependency> - <groupId>com.mysql</groupId> - <artifactId>mysql-connector-j</artifactId> - <version>8.3.0</version> - </dependency> - <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> @@ -155,7 +148,6 @@ <version>2.23.1</version> </dependency> - <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> @@ -166,6 +158,11 @@ <artifactId>commons-codec</artifactId> <version>1.15</version> </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.16.1</version> + </dependency> <dependency> <groupId>junit</groupId> From 47e8332931eefd5b3a0a76a705af64c5cdb2844e Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 25 Jun 2024 23:49:58 -0400 Subject: [PATCH 129/155] Implement command results in execute function --- .../java/netneutrality/NetNeutrality.java | 2 +- .../command/AbstractCommand.java | 3 +- .../command/CommandExecutionResult.java | 64 ++++++++++ .../{core => command}/CommandManager.java | 5 +- .../java/netneutrality/command/ICommand.java | 4 +- .../command/admin/BlacklistCommand.java | 9 +- .../command/basic/HelpCommand.java | 8 +- .../command/basic/PingCommand.java | 9 +- .../command/bot/ConfigureCommand.java | 33 +++--- .../command/crypto/CryptoPriceCommand.java | 16 ++- .../command/music/BitconnectCommand.java | 8 +- .../command/music/ClearQueueCommand.java | 26 ++-- .../music/CurrentlyPlayingCommand.java | 8 +- .../command/music/JoinCommand.java | 20 ++-- .../command/music/LeaveCommand.java | 9 +- .../command/music/PlayCommand.java | 7 +- .../command/music/QueueCommand.java | 40 ++----- .../command/music/ShuffleCommand.java | 8 +- .../command/music/SkipCommand.java | 20 ++-- .../command/music/StopCommand.java | 14 ++- .../command/music/ViewQueueCommand.java | 10 +- .../command/music/VolumeCommand.java | 13 +- .../command/music/VoteSkipCommand.java | 11 +- .../netneutrality/core/CommandProcessor.java | 111 ++++++++++++++++++ .../core/context/CommandContext.java | 2 - .../core/context/MessageCommandContext.java | 39 ------ .../core/context/SlashCommandContext.java | 39 ++---- .../hooks/SlashCommandHooks.java | 5 +- .../hooks/message/MessageReceivedHandler.java | 5 +- .../netneutrality/music/MusicManager.java | 30 ++--- .../netneutrality/music/QueueManager.java | 72 +++++++++--- .../MusicPlayerAutoDisconnectThread.java | 8 +- .../netneutrality/utils/MessageFunction.java | 2 +- 33 files changed, 419 insertions(+), 241 deletions(-) create mode 100644 src/main/java/netneutrality/command/CommandExecutionResult.java rename src/main/java/netneutrality/{core => command}/CommandManager.java (97%) create mode 100644 src/main/java/netneutrality/core/CommandProcessor.java diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 3f5aa07..aaa9b7c 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -13,7 +13,7 @@ import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.exceptions.InvalidTokenException; import net.dv8tion.jda.api.requests.GatewayIntent; -import netneutrality.core.CommandManager; +import netneutrality.command.CommandManager; import netneutrality.core.LogHandler; import netneutrality.db.DBController; import netneutrality.hooks.SlashCommandHooks; diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/netneutrality/command/AbstractCommand.java index 158970d..c098e8d 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/netneutrality/command/AbstractCommand.java @@ -36,7 +36,8 @@ public abstract class AbstractCommand implements ICommand { @Deprecated @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { // Prefer slash commands + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/CommandExecutionResult.java b/src/main/java/netneutrality/command/CommandExecutionResult.java new file mode 100644 index 0000000..fd51e64 --- /dev/null +++ b/src/main/java/netneutrality/command/CommandExecutionResult.java @@ -0,0 +1,64 @@ +package netneutrality.command; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +public class CommandExecutionResult { + + public enum Result { + SUCCESS, INFO, WARN, ERROR, NOACTION + } + + private final Result result; + private final String message; + private final Exception exception; + + private CommandExecutionResult(Result result, String message, Exception exception) { + this.result = result; + this.message = message; + this.exception = exception; + } + + private CommandExecutionResult(Result result, String message) { + this(result, message, null); + } + + public Result getResult() { + return result; + } + + public String getMessage() { + return message; + } + + public Exception getException() { + return exception; + } + + public static CommandExecutionResult success(String message) { + return new CommandExecutionResult(Result.SUCCESS, message); + } + + public static CommandExecutionResult info(String message) { + return new CommandExecutionResult(Result.INFO, message); + } + + public static CommandExecutionResult warn(String message) { + return new CommandExecutionResult(Result.WARN, message); + } + + public static CommandExecutionResult error(String message, Exception exception) { + return new CommandExecutionResult(Result.ERROR, message, exception); + } + + public static CommandExecutionResult error(String message) { + return error(message, null); + } + + public static CommandExecutionResult none() { + return new CommandExecutionResult(Result.NOACTION, null); + } + +} diff --git a/src/main/java/netneutrality/core/CommandManager.java b/src/main/java/netneutrality/command/CommandManager.java similarity index 97% rename from src/main/java/netneutrality/core/CommandManager.java rename to src/main/java/netneutrality/command/CommandManager.java index f3f599b..1f9cd28 100644 --- a/src/main/java/netneutrality/core/CommandManager.java +++ b/src/main/java/netneutrality/command/CommandManager.java @@ -1,5 +1,4 @@ -package netneutrality.core; - +package netneutrality.command; /* * Copyright (c) anthorob * @@ -11,7 +10,7 @@ import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; import netneutrality.NetNeutrality; -import netneutrality.command.AbstractCommand; +import netneutrality.core.LogHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.reflections.Reflections; diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/netneutrality/command/ICommand.java index 19b3a2d..c7af286 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/netneutrality/command/ICommand.java @@ -38,7 +38,7 @@ public interface ICommand { boolean canBeExecutedFrom(Guild guild, MessageChannel channel); @Deprecated - void execute(MessageCommandContext context); + CommandExecutionResult execute(MessageCommandContext context); - void execute(SlashCommandContext context); + CommandExecutionResult execute(SlashCommandContext context); } diff --git a/src/main/java/netneutrality/command/admin/BlacklistCommand.java b/src/main/java/netneutrality/command/admin/BlacklistCommand.java index 86be8b1..b50f31f 100644 --- a/src/main/java/netneutrality/command/admin/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/admin/BlacklistCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.command.CommandType; import netneutrality.core.LogHandler; import netneutrality.core.context.MessageCommandContext; @@ -70,12 +71,12 @@ public class BlacklistCommand extends AbstractCommand { } @Override - public void execute(MessageCommandContext context) { - + public CommandExecutionResult execute(MessageCommandContext context) { + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { String sub = context.getEvent().getFullCommandName().split(" ")[1]; DBBlacklist controller = DBController.get(DBBlacklist.class); String word = context.getEvent().getOption("word", "", OptionMapping::getAsString); @@ -106,5 +107,7 @@ public class BlacklistCommand extends AbstractCommand { case "disable" -> controller.disable(word, context); case "enable" -> controller.enable(word, context); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index 0ec10e7..0648a7d 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -9,6 +9,7 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.command.CommandType; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; @@ -54,7 +55,7 @@ public class HelpCommand extends AbstractCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { if (context.getArgs().length == 0) { List<MessageEmbed> help = MessageFunction.buildHelpMessage(context.getGuildUser()); @@ -62,13 +63,14 @@ public class HelpCommand extends AbstractCommand { context.replyPrivate(help); } + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { List<MessageEmbed> help = MessageFunction.buildHelpMessage(context.getGuildUser()); - context.replyEphemeral("Help has been sent in DM!"); context.sendMessageInPrivate(help); + return CommandExecutionResult.success("Help has been sent in DM!"); } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index f832727..02c987d 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -7,6 +7,7 @@ package netneutrality.command.basic; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.command.CommandType; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; @@ -49,14 +50,16 @@ public class PingCommand extends AbstractCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { if (context.getArgs().length == 0) context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { - context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); + public CommandExecutionResult execute(SlashCommandContext context) { + return CommandExecutionResult.success(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); } } diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 61bcafa..4b33096 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -16,6 +16,7 @@ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.command.CommandType; import netneutrality.core.GuildManager; import netneutrality.core.context.MessageCommandContext; @@ -79,7 +80,7 @@ public class ConfigureCommand extends AbstractCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { String[] args = context.getArgs(); GuildManager guildManager = GuildManager.getManager(context.getGuild()); @@ -204,10 +205,12 @@ public class ConfigureCommand extends AbstractCommand { } } } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { String sub = context.getEvent().getFullCommandName().split(" ")[1]; GuildManager guildManager = GuildManager.getManager(context.getGuild()); context.ackAndWait(true); @@ -218,14 +221,14 @@ public class ConfigureCommand extends AbstractCommand { if (role.getPosition() == -1) { guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, null); - context.replyEphemeral("Everyone can now use music commands"); - return; + + return CommandExecutionResult.success("Everyone can now use music commands"); } if (role.getGuild().getId().equals(context.getGuild().getId())) { guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_ROLE, role.getId()); - context.replyEphemeral("Successfully set %s as the role needed for music command", role.getAsMention()); - return; + + return CommandExecutionResult.success(String.format("Successfully set %s as the role needed for music command", role.getAsMention())); } } @@ -234,15 +237,15 @@ public class ConfigureCommand extends AbstractCommand { if (channel == null) { guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_CHANNEL, null); - context.replyEphemeral("No channel restrictions for music commands"); - return; + + return CommandExecutionResult.success("No channel restrictions for music commands"); } if (channel instanceof TextChannel) { if (channel.getGuild().getId().equals(context.getGuild().getId())) { guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); - context.replyEphemeral("Successfully set %s as the channel required to execute music command", channel.getAsMention()); - return; + + return CommandExecutionResult.success(String.format("Successfully set %s as the channel required to execute music command", channel.getAsMention())); } } @@ -253,16 +256,14 @@ public class ConfigureCommand extends AbstractCommand { guildManager.getGuildConfigManager().setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); - context.replyEphemeral("Default volume for music player is now %d", volume); - return; + return CommandExecutionResult.success(String.format("Default volume for music player is now %d", volume)); } if ("debug".equals(sub)) { boolean debug = context.getEvent().getOption("debug", true, OptionMapping::getAsBoolean); - guildManager.setDebug(debug); - context.reply("Error logging is now %s for this guild", (debug ? "enabled" : "disabled")); - return; + + return CommandExecutionResult.success(String.format("Error logging is now %s for this guild", (debug ? "enabled" : "disabled"))); } if ("show-all".equals(sub)) { @@ -282,5 +283,7 @@ public class ConfigureCommand extends AbstractCommand { context.replyEphemeral(builder.build()); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 63a2e2b..14ec58d 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -9,6 +9,7 @@ import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.command.CommandType; import netneutrality.core.LogHandler; import netneutrality.core.context.MessageCommandContext; @@ -62,7 +63,7 @@ public class CryptoPriceCommand extends AbstractCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { String[] args = context.getArgs(); String currency = "USD"; @@ -71,8 +72,8 @@ public class CryptoPriceCommand extends AbstractCommand { try { currency = Currency.getInstance(args[1].toUpperCase()).getCurrencyCode(); } catch (IllegalArgumentException exception) { - context.reply("Please enter a valid currency"); - return; + + return CommandExecutionResult.warn("Please enter a valid currency"); } } @@ -101,10 +102,12 @@ public class CryptoPriceCommand extends AbstractCommand { } }); } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { Locale usa = new Locale("en", "US"); NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(usa); dollarFormat.setMaximumFractionDigits(24); @@ -115,8 +118,7 @@ public class CryptoPriceCommand extends AbstractCommand { try { currency = Currency.getInstance(currency).getCurrencyCode(); } catch (IllegalArgumentException exception) { - context.reply("Please enter a valid currency"); - return; + return CommandExecutionResult.error("Please enter a valid currency"); } String finalCurrency = currency.toUpperCase(); @@ -143,5 +145,7 @@ public class CryptoPriceCommand extends AbstractCommand { }); + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/netneutrality/command/music/BitconnectCommand.java index 6844b1b..e607263 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/netneutrality/command/music/BitconnectCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.command.CommandType; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; @@ -41,19 +42,20 @@ public class BitconnectCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", context, false, true); context.deleteMessage(); + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); context.ackAndWait(); player.play("https://www.youtube.com/watch?v=e5nyQmaq4k4", context, false, true); - context.reply("Ready to invest?"); + return CommandExecutionResult.success("Ready to invest?"); } } diff --git a/src/main/java/netneutrality/command/music/ClearQueueCommand.java b/src/main/java/netneutrality/command/music/ClearQueueCommand.java index 0daf844..da32cdd 100644 --- a/src/main/java/netneutrality/command/music/ClearQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ClearQueueCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -42,11 +43,11 @@ public class ClearQueueCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) - return; + return CommandExecutionResult.none(); if (context.getArgs().length == 0) { context.reply("Select the track you want to delete from the queue (track# or all)"); @@ -70,11 +71,7 @@ public class ClearQueueCommand extends AbstractMusicCommand { int num = Integer.parseInt(context.getArgument(0)); if (num > 0) { - if (player.removeFromQueue(num)) { - context.reply("Removed track #%d from the queue", num); - } else { - context.reply("Error while removing track #%d from the queue", num); - } + return player.getScheduler().getQueueManager().removeFromQueue(num); } else { context.reply("Number out of range"); } @@ -84,22 +81,19 @@ public class ClearQueueCommand extends AbstractMusicCommand { } } } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); if (!MusicUtils.checkIfConnected(manager, context)) - return; + return CommandExecutionResult.none(); - int queueSize = manager.getQueueSize(); - if (queueSize > 0) { - manager.getScheduler().getQueueManager().clearQueue(); - context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); - } else { - context.reply("Queue is empty!"); - } + return manager.getScheduler().getQueueManager().clearQueue(); } + } diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java index a852a4f..34d24d7 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -37,7 +38,7 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(player, context) && player.isCurrentlyPlaying()) { @@ -46,15 +47,18 @@ public class CurrentlyPlayingCommand extends AbstractMusicCommand { context.reply("Bot isn't playing any tracks right now"); } + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); if (MusicUtils.checkIfConnected(manager, context) && manager.isCurrentlyPlaying()) { context.reply(MessageFunction.buildCurrentlyPlayingMessage(manager)); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 627b3ec..c359e0f 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.exceptions.CommandExecutionException; @@ -37,7 +38,7 @@ public class JoinCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (context.getGuildUser().getVoiceState() == null) { @@ -45,13 +46,11 @@ public class JoinCommand extends AbstractMusicCommand { } if (!context.getGuildUser().getVoiceState().inAudioChannel()) { - context.reply("You are not in a voice channel"); - return; + return CommandExecutionResult.warn("You are not in a voice channel"); } if (player.isConnected()) { - context.reply("Player is already in a voice channel"); - return; + return CommandExecutionResult.warn("Player is already in a voice channel"); } VoiceChannel vChannel = (VoiceChannel) context.getGuildUser().getVoiceState().getChannel(); @@ -60,10 +59,11 @@ public class JoinCommand extends AbstractMusicCommand { context.reply("Joining current voice channel"); } + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); context.ackAndWait(); @@ -72,13 +72,11 @@ public class JoinCommand extends AbstractMusicCommand { } if (!context.getGuildUser().getVoiceState().inAudioChannel()) { - context.reply("You are not in a voice channel"); - return; + return CommandExecutionResult.warn("You are not in a voice channel"); } if (player.isConnected()) { - context.reply("Player is already in a voice channel"); - return; + return CommandExecutionResult.warn("Player is already in a voice channel"); } VoiceChannel vChannel = (VoiceChannel) context.getGuildUser().getVoiceState().getChannel(); @@ -86,5 +84,7 @@ public class JoinCommand extends AbstractMusicCommand { player.connect(vChannel); context.reply("Joining current voice channel"); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 8b948ce..6a6a318 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -36,17 +37,19 @@ public class LeaveCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(player, context)) { player.leave(); context.reply("Leaving voice channel and clearing queue"); } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); context.ackAndWait(); @@ -54,5 +57,7 @@ public class LeaveCommand extends AbstractMusicCommand { player.leave(); context.reply("Leaving voice channel and clearing queue"); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index f414c8c..39cf5e8 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -37,21 +38,23 @@ public class PlayCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (context.getArgs().length > 0) { player.play(context.getMessageText(), context, false, false); } + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); String query = context.getEvent().getOption("query", OptionMapping::getAsString); context.ackAndWait(); manager.play(query, context, false, false); + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/QueueCommand.java b/src/main/java/netneutrality/command/music/QueueCommand.java index 5615a82..32e5153 100644 --- a/src/main/java/netneutrality/command/music/QueueCommand.java +++ b/src/main/java/netneutrality/command/music/QueueCommand.java @@ -13,6 +13,7 @@ import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -58,11 +59,11 @@ public class QueueCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) - return; + return CommandExecutionResult.none(); if (context.getArgs().length == 0) { context.reply("Select the track you want to delete from the queue (track# or all)"); @@ -86,11 +87,7 @@ public class QueueCommand extends AbstractMusicCommand { int num = Integer.parseInt(context.getArgument(0)); if (num > 0) { - if (player.removeFromQueue(num)) { - context.reply("Removed track #%d from the queue", num); - } else { - context.reply("Error while removing track #%d from the queue", num); - } + return player.getScheduler().getQueueManager().removeFromQueue(num); } else { context.reply("Number out of range"); } @@ -100,47 +97,34 @@ public class QueueCommand extends AbstractMusicCommand { } } } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); String sub = context.getEvent().getFullCommandName().split(" ")[1]; if (!MusicUtils.checkIfConnected(manager, context)) { - return; + return CommandExecutionResult.none(); } switch (sub) { case "clear-all" -> { - int queueSize = manager.getQueueSize(); - - if (queueSize > 0) { - manager.getScheduler().getQueueManager().clearQueue(); - context.reply(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); - } else { - context.reply("Queue is already empty!"); - } + return manager.getScheduler().getQueueManager().clearQueue(); } case "delete-track" -> { int position = context.getEvent().getOption("position", 0, OptionMapping::getAsInt); - - if (position > 0) { - if (manager.removeFromQueue(position)) { - context.reply("Removed track #%d from the queue", position); - } else { - context.reply("Position is out of bounds"); - } - } + return manager.getScheduler().getQueueManager().removeFromQueue(position); } case "show-queue" -> context.reply(MessageFunction.buildViewQueueMessage(manager, true)); case "shuffle" -> { - manager.getScheduler().getQueueManager().shuffle(); - context.reply("Queue is now shuffled."); + return manager.getScheduler().getQueueManager().shuffle(); } case "from-user" -> { @@ -174,6 +158,6 @@ public class QueueCommand extends AbstractMusicCommand { } } - + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/ShuffleCommand.java b/src/main/java/netneutrality/command/music/ShuffleCommand.java index a5ee873..22c3623 100644 --- a/src/main/java/netneutrality/command/music/ShuffleCommand.java +++ b/src/main/java/netneutrality/command/music/ShuffleCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -34,13 +35,14 @@ public class ShuffleCommand extends AbstractMusicCommand { } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); if (MusicUtils.checkIfConnected(manager, context)) { - manager.getScheduler().getQueueManager().shuffle(); - context.reply("Queue is now shuffled."); + return manager.getScheduler().getQueueManager().shuffle(); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index e52642c..6133ae4 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -41,11 +42,11 @@ public class SkipCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) - return; + return CommandExecutionResult.none(); if (UserFunction.isAdmin(context.getGuildUser()) || MusicUtils.isUserDj(context.getGuildUser())) { if (UserFunction.isAdmin(context.getGuildUser()) && context.getArgs().length > 0) { @@ -65,22 +66,19 @@ public class SkipCommand extends AbstractMusicCommand { player.voteSkip(context); } + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); - int skips = context.getEvent().getOption("skip", 0, OptionMapping::getAsInt); + int skips = context.getEvent().getOption("skip", 1, OptionMapping::getAsInt); context.ackAndWait(); if (MusicUtils.checkIfConnected(manager, context)) { - if (skips > 0) { - context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : "")); - manager.getScheduler().getQueueManager().skip(skips); - } else { - context.reply("Skipping current track"); - manager.getScheduler().getQueueManager().skip(1); - } + return manager.getScheduler().getQueueManager().skip(skips); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index 3a87054..49c5928 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -8,6 +8,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -37,28 +38,31 @@ public class StopCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) - return; + return CommandExecutionResult.none(); // Need a resume command before - // if (UserFunction.isAdmin(context.getGuildUser()) || MusicUtils.isUserDj(context.getGuildUser())) { if (UserFunction.isAdmin(context.getGuildUser())) { player.stopTrack(); context.reply("Stopping current track"); } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); if (MusicUtils.checkIfConnected(manager, context)) { manager.stopTrack(); - context.reply("Stopping music playback"); + return CommandExecutionResult.success("Stopping music playback"); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 58a568f..d2c2ace 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -7,6 +7,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -36,7 +37,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(player, context)) { @@ -48,10 +49,11 @@ public class ViewQueueCommand extends AbstractMusicCommand { } } + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); context.ackAndWait(); @@ -61,8 +63,10 @@ public class ViewQueueCommand extends AbstractMusicCommand { if (queueSize > 0) { context.reply(MessageFunction.buildViewQueueMessage(manager, true)); } else { - context.reply("Queue is empty!"); + return CommandExecutionResult.warn("Queue is empty!"); } } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 0943481..ec69272 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -41,11 +42,11 @@ public class VolumeCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); if (!MusicUtils.checkIfConnected(player, context)) - return; + return CommandExecutionResult.none(); if (UserFunction.isAdmin(context.getGuildUser()) || MusicUtils.isUserDj(context.getGuildUser())) { try { @@ -61,16 +62,20 @@ public class VolumeCommand extends AbstractMusicCommand { context.reply("Please enter a value from 0 to 100"); } } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); int volume = context.getEvent().getOption("volume", 30, OptionMapping::getAsInt); if (MusicUtils.checkIfConnected(manager, context)) { - context.reply("Volume set to %s", volume); manager.setVolume(volume); + return CommandExecutionResult.success(String.format("Volume set to %s", volume)); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index ef29123..f07c358 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -7,6 +7,7 @@ package netneutrality.command.music; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import netneutrality.command.AbstractMusicCommand; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.context.MessageCommandContext; import netneutrality.core.context.SlashCommandContext; import netneutrality.music.MusicManager; @@ -35,20 +36,24 @@ public class VoteSkipCommand extends AbstractMusicCommand { } @Override - public void execute(MessageCommandContext context) { + public CommandExecutionResult execute(MessageCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(manager, context)) { manager.voteSkip(context); } + + return CommandExecutionResult.none(); } @Override - public void execute(SlashCommandContext context) { + public CommandExecutionResult execute(SlashCommandContext context) { MusicManager manager = MusicManager.get(context.getGuild()); if (MusicUtils.checkIfConnected(manager, context)) { - manager.voteSkip(context); + return manager.voteSkip(context); } + + return CommandExecutionResult.none(); } } diff --git a/src/main/java/netneutrality/core/CommandProcessor.java b/src/main/java/netneutrality/core/CommandProcessor.java new file mode 100644 index 0000000..0c31320 --- /dev/null +++ b/src/main/java/netneutrality/core/CommandProcessor.java @@ -0,0 +1,111 @@ +package netneutrality.core; +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import io.sentry.Sentry; +import netneutrality.command.AbstractCommand; +import netneutrality.command.CommandExecutionResult; +import netneutrality.command.CommandManager; +import netneutrality.core.context.CommandContext; +import netneutrality.core.context.MessageCommandContext; +import netneutrality.core.context.SlashCommandContext; +import netneutrality.exceptions.CommandExecutionException; +import netneutrality.utils.UserFunction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import static netneutrality.command.CommandExecutionResult.Result.*; + +public class CommandProcessor { + + private final static Logger logger = LogManager.getLogger(CommandProcessor.class); + private final String commandName; + private final CommandContext context; + + public CommandProcessor(String commandName, CommandContext context) { + this.commandName = commandName; + this.context = context; + } + + public void dispatch() { + + if (!CommandManager.isValidCommand(commandName)) { + return; + } + + AbstractCommand command = CommandManager.getCommand(commandName); + logger.info("Executing command {} on guild {}", command.getCommandName(), context.getGuild().getId()); + + if (context instanceof SlashCommandContext slashCommandContext) + logger.debug("SlashCommandInteractionId: {}", slashCommandContext.getEvent().getInteraction().getId()); + + configureSentry(command); + + try { + + if (context instanceof MessageCommandContext && command.needAdmin() && !UserFunction.isAdmin(context.getGuildUser())) { + context.reply("You are not powerful enough, scrub"); + return; + } + + if (command.canBeExecutedBy(context.getGuild(), context.getGuildUser())) { + if (command.canBeExecutedFrom(context.getGuild(), context.getChannel())) { + CommandExecutionResult commandExecutionResult = null; + + if (context instanceof SlashCommandContext slashCommandContext) { + commandExecutionResult = command.execute(slashCommandContext); + } + + if (context instanceof MessageCommandContext messageCommandContext) { + commandExecutionResult = command.execute(messageCommandContext); + } + + if (commandExecutionResult == null) { + throw new RuntimeException("Command type is not implemented."); + } + + CommandExecutionResult.Result result = commandExecutionResult.getResult(); + String message = commandExecutionResult.getMessage(); + if (result == NOACTION) { + return; + } + + if (result == ERROR) { + Exception exception = commandExecutionResult.getException(); + + logger.error("Error from command {}: {}", command.getCommandName(), message, exception); + } + + context.reply(message); + } + } + + //TODO: make better + } catch (CommandExecutionException exception) { + LogHandler.log(exception); + } catch (Exception exception) { + LogHandler.log(new CommandExecutionException("Error during command execution", context, exception)); + } + } + + private void configureSentry(AbstractCommand command) { + + Sentry.configureScope(scope -> { + scope.setContexts("command", command.getCommandName()); + scope.setContexts("isAdmin", UserFunction.isAdmin(context.getGuildUser())); + scope.setContexts("canBeExecuted", command.canBeExecutedBy(context.getGuild(), context.getGuildUser())); + scope.setTag("channel", context.getChannel().getId()); + + if (context instanceof SlashCommandContext slashCommandContext) + scope.setTag("interactionId", slashCommandContext.getEvent().getInteraction().getId()); + + if (context instanceof MessageCommandContext messageCommandContext) + scope.setTag("message", messageCommandContext.getMessage().getId()); + + scope.setTag("guild", context.getGuild().getId()); + }); + } +} diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index bd8e580..c812826 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -57,6 +57,4 @@ public interface CommandContext { default void replyToMessage(MessageEmbed... embeds) { replyToMessage(MessageCreateData.fromEmbeds(embeds)); } - - void dispatchToCommand(String commandName); } diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java index 595d2e0..2906077 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -13,13 +13,9 @@ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import netneutrality.command.AbstractCommand; -import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; -import netneutrality.core.LogHandler; -import netneutrality.exceptions.CommandExecutionException; import netneutrality.thread.ThreadManager; import netneutrality.utils.Settings; -import netneutrality.utils.UserFunction; import java.util.Collection; import java.util.concurrent.ExecutorService; @@ -193,39 +189,4 @@ public class MessageCommandContext implements CommandContext { return creatorId.equals(member.getId()); } - public void dispatchToCommand(String commandName) { - if (!CommandManager.isValidCommand(commandName)) { - return; - } - - AbstractCommand command = CommandManager.getCommand(commandName); - this.command = command; - //TODO: Add usage check - - Sentry.configureScope(scope -> { - scope.setContexts("command", command.getCommandName()); - scope.setContexts("isAdmin", UserFunction.isAdmin(member)); - scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); - scope.setTag("channel", channel.getId()); - scope.setTag("message", message.getId()); - scope.setTag("guild", guild.getId()); - }); - - try { - if (command.needAdmin() && !UserFunction.isAdmin(member)) { - reply("You are not powerful enough, scrub"); - return; - } - - if (command.canBeExecutedBy(guild, member)) { - if (command.canBeExecutedFrom(guild, channel)) { - command.execute(this); - } - } - } catch (CommandExecutionException e) { - LogHandler.log(e); - } catch (Exception e) { - LogHandler.log(new CommandExecutionException("Error during command execution", this, e)); - } - } } diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/netneutrality/core/context/SlashCommandContext.java index 352efa3..e46a880 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/netneutrality/core/context/SlashCommandContext.java @@ -1,12 +1,10 @@ package netneutrality.core.context; - /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ -import io.sentry.Sentry; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -19,9 +17,6 @@ import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import net.dv8tion.jda.api.utils.messages.MessageEditData; import netneutrality.command.AbstractCommand; -import netneutrality.core.CommandManager; -import netneutrality.core.LogHandler; -import netneutrality.exceptions.CommandExecutionException; import java.util.Collection; @@ -174,32 +169,12 @@ public class SlashCommandContext implements CommandContext { ackAndWait(false); } - public void dispatchToCommand(String commandName) { - if (!CommandManager.isValidCommand(commandName)) { - return; - } - - AbstractCommand command = CommandManager.getCommand(commandName); - this.command = command; - - Sentry.configureScope(scope -> { - scope.setContexts("command", command.getCommandName()); - scope.setContexts("canBeExecuted", command.canBeExecutedBy(guild, member)); - scope.setTag("channel", channel.getId()); - scope.setTag("interactionId", event.getInteraction().getId()); - scope.setTag("guild", guild.getId()); - }); - - try { - if (command.canBeExecutedBy(guild, member)) { - command.execute(this); - } - - } catch (CommandExecutionException exception) { - LogHandler.log(exception); - } catch (Exception exception) { - LogHandler.log(new CommandExecutionException("Error during command execution", this, exception)); - } - + public void ack() { + ackAndWait(); } + + public void ephemeral() { + ackAndWait(true); + } + } diff --git a/src/main/java/netneutrality/hooks/SlashCommandHooks.java b/src/main/java/netneutrality/hooks/SlashCommandHooks.java index 6c6e809..6e5d99b 100644 --- a/src/main/java/netneutrality/hooks/SlashCommandHooks.java +++ b/src/main/java/netneutrality/hooks/SlashCommandHooks.java @@ -7,6 +7,7 @@ package netneutrality.hooks; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.core.CommandProcessor; import netneutrality.core.context.SlashCommandContext; import org.jetbrains.annotations.NotNull; @@ -17,6 +18,8 @@ public class SlashCommandHooks extends ListenerAdapter { String commandName = event.getName(); SlashCommandContext commandContext = SlashCommandContext.createContext(event); - commandContext.dispatchToCommand(commandName); + CommandProcessor processor = new CommandProcessor(commandName, commandContext); + processor.dispatch(); + } } diff --git a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java index c1935ea..f7a87c8 100644 --- a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java @@ -10,6 +10,7 @@ import io.sentry.Sentry; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import netneutrality.core.CommandProcessor; import netneutrality.core.GuildManager; import netneutrality.core.context.MessageCommandContext; import netneutrality.utils.Settings; @@ -28,7 +29,6 @@ public class MessageReceivedHandler extends ListenerAdapter { Message message = event.getMessage(); MessageCommandContext context = MessageCommandContext.createContext(event); - Sentry.addBreadcrumb(Breadcrumb.info("New message from " + context.getGuildUser().getEffectiveName())); GuildManager.getManager(context.getGuild()).checkAndLogMessage(message, context.getGuildUser(), context.getChannel()); @@ -40,7 +40,8 @@ public class MessageReceivedHandler extends ListenerAdapter { // rawMessage = rawMessage.substring(prefix.length()).trim(); String commandString = rawMessage.split(" ", 2)[0]; - context.dispatchToCommand(commandString); + CommandProcessor processor = new CommandProcessor(commandString, context); + processor.dispatch(); } } } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index b6c07ce..d096bc7 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -17,6 +17,7 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import netneutrality.command.CommandExecutionResult; import netneutrality.core.GuildManager; import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; @@ -152,7 +153,7 @@ public class MusicManager { } public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { - logger.debug("Guild {}: request to play {} by user {}", guild.getId(), url, context.getGuildUser().getId()); + logger.debug("Guild {}: request to play '{}' by user {}", guild.getId(), url, context.getGuildUser().getId()); List<LoadableSong> toLoad = new ArrayList<>(); toLoad.add(new LoadableSong(null, url, null)); @@ -194,24 +195,24 @@ public class MusicManager { loader.loadAllSongs(songs); } - public synchronized boolean removeFromQueue(int index) { - return scheduler.getQueueManager().removeFromQueue(index); - } - public synchronized void stopTrack() { player.stopTrack(); } - public synchronized void voteSkip(CommandContext context) { + public synchronized CommandExecutionResult voteSkip(CommandContext context) { VoiceChannel voiceChannel = (VoiceChannel) guild.getAudioManager().getConnectedChannel(); - QueueManager.TrackInfo info = scheduler.getQueueManager().peekHeadOfQueue(); - if (!isCurrentlyPlaying() || voiceChannel == null) { - return; + if (voiceChannel == null) { + return CommandExecutionResult.none(); } + if (!isCurrentlyPlaying()) { + return CommandExecutionResult.none(); + } + + QueueManager.TrackInfo info = scheduler.getQueueManager().peekHeadOfQueue(); if (info == null) { - return; + return CommandExecutionResult.none(); } // Minus the bot itself @@ -219,9 +220,9 @@ public class MusicManager { if (connected < 3) { context.reply("Skipping current track since not enough people are connected to the voice channel."); - scheduler.getQueueManager().skip(1); + scheduler.getQueueManager().skip(); - return; + return CommandExecutionResult.none(); } double needed = connected / 2.1; @@ -230,11 +231,12 @@ public class MusicManager { logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId()); if (info.getSkips().size() > needed) { - context.reply("Skipping current track: %s", info.getTrack().getInfo().title); - scheduler.getQueueManager().skip(1); + return scheduler.getQueueManager().skip(); } else { context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); } + + return CommandExecutionResult.none(); } public synchronized void setVolume(int volume) { diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index d6bab24..70c0d1e 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -9,6 +9,7 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; +import netneutrality.command.CommandExecutionResult; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -136,12 +137,22 @@ public class QueueManager { } } - public void clearQueue() { + public CommandExecutionResult clearQueue() { scheduler.getMusicManager().stopLoading(); scheduler.getMusicManager().leave(); + if (queue.isEmpty()) { + return CommandExecutionResult.warn("Queue is empty!"); + } + synchronized (queue) { + int queueSize = queue.size(); + if (queueSize == 0) { + return CommandExecutionResult.warn("Queue is empty!"); + } + queue.clear(); + return CommandExecutionResult.success(String.format("Removed %d track%s from the queue", queueSize--, (queueSize > 1 ? "s" : ""))); } } @@ -210,19 +221,19 @@ public class QueueManager { } } - public void skip() { - skip(1); + public CommandExecutionResult skip() { + return skip(1); } - public void skip(int nbTrack) { - if (nbTrack == 0) - return; + public CommandExecutionResult skip(int nbTrack) { + if (nbTrack == 0) { + nbTrack = 1; + } synchronized (queue) { - if (queue.isEmpty()) { scheduler.getMusicManager().leave(); - return; + return CommandExecutionResult.info("Queue is empty, leaving voice channel"); } if (nbTrack > queue.size()) { @@ -234,11 +245,22 @@ public class QueueManager { queue.poll(); } + if (queue.isEmpty()) { + scheduler.getMusicManager().leave(); + return CommandExecutionResult.info("Queue is empty, leaving voice channel"); + } + startNextTrack(); + + return CommandExecutionResult.success(String.format("Skipping %s track%s..", nbTrack, (nbTrack > 1 ? "s" : ""))); } } - public void shuffle() { + public CommandExecutionResult shuffle() { + if (queue.size() > 3) { + return CommandExecutionResult.none(); + } + synchronized (queue) { if (queue.size() > 3) { logger.debug("Guild {}: shuffling queue", guild.getId()); @@ -251,29 +273,43 @@ public class QueueManager { queue.clear(); queue.add(current); queue.addAll(newQueue); + + return CommandExecutionResult.success("Queue is now shuffled."); } + + return CommandExecutionResult.none(); } } - public boolean removeFromQueue(int index) { + public CommandExecutionResult removeFromQueue(int index) { + if (queue.isEmpty() || index < 1) { + return CommandExecutionResult.none(); + } + synchronized (queue) { - if (queue.size() > 0 && index <= queue.size()) { - logger.debug("Guild {}: removing index {} from queue", guild.getId(), index - 1); + if (queue.isEmpty()) { + return CommandExecutionResult.none(); + } - if (index == 1) { - skip(1); - return true; - } + if (index > queue.size()) { + return CommandExecutionResult.error("Position is out of bounds"); + } + logger.debug("Guild {}: removing index {} from queue", guild.getId(), index - 1); + + if (index > 1) { List<TrackInfo> newQueue = new ArrayList<>(queue); newQueue.remove(index - 1); queue.clear(); queue.addAll(newQueue); - return true; + + return CommandExecutionResult.success(String.format("Removed track #%d from the queue", index)); } - return false; + skip(); + return CommandExecutionResult.none(); + } } diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index b0b5b5a..d367442 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -11,12 +11,14 @@ import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import netneutrality.NetNeutrality; import netneutrality.music.MusicManager; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.List; public class MusicPlayerAutoDisconnectThread implements Runnable { - final MusicManager manager; + private final Logger logger = LogManager.getLogger(MusicPlayerAutoDisconnectThread.class); + private final MusicManager manager; //TODO: move to scheduler public MusicPlayerAutoDisconnectThread(MusicManager musicManager) { @@ -35,7 +37,7 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { Thread.sleep(30000); if (conditionsMetToDisconnect(channel)) { - LogManager.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); + logger.debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId()); manager.leave(); } } @@ -48,6 +50,6 @@ public class MusicPlayerAutoDisconnectThread implements Runnable { private boolean conditionsMetToDisconnect(VoiceChannel channel) { List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); - return members.size() == 0 || manager.getScheduler().getQueueManager().isEmpty(); + return members.isEmpty() || manager.getScheduler().getQueueManager().isEmpty(); } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 91c16fa..72fcc92 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -17,7 +17,7 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; -import netneutrality.core.CommandManager; +import netneutrality.command.CommandManager; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandException; import netneutrality.music.MusicManager; From 1ced46e07558f3de498123ca94289913ba7faa58 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Tue, 25 Jun 2024 23:50:32 -0400 Subject: [PATCH 130/155] Remove obsolete PurgeCommand --- .../command/admin/PurgeCommand.java | 94 ------------------- 1 file changed, 94 deletions(-) delete mode 100644 src/main/java/netneutrality/command/admin/PurgeCommand.java diff --git a/src/main/java/netneutrality/command/admin/PurgeCommand.java b/src/main/java/netneutrality/command/admin/PurgeCommand.java deleted file mode 100644 index 72942aa..0000000 --- a/src/main/java/netneutrality/command/admin/PurgeCommand.java +++ /dev/null @@ -1,94 +0,0 @@ -package netneutrality.command.admin; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; -import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; -import net.dv8tion.jda.api.interactions.commands.OptionMapping; -import net.dv8tion.jda.api.interactions.commands.OptionType; -import net.dv8tion.jda.api.interactions.commands.build.OptionData; -import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.utils.ChannelMessagePurger; - -public class PurgeCommand extends AbstractCommand { - - @Override - public boolean needAdmin() { - return true; - } - - @Override - public boolean isEnabled() { - return false; - } - - @Override - public boolean isGuildOnly() { - return true; - } - - @Override - public String getCommandName() { - return "purge"; - } - - @Override - public String getDescription() { - return "Delete messages from the channel you are currently on"; - } - - @Override - public DefaultMemberPermissions getSlashCommandPermission() { - return DefaultMemberPermissions.DISABLED; - } - - @Override - public void registerSlashCommandOptions(SlashCommandData data) { - - data.addOptions( - new OptionData(OptionType.INTEGER, "to-purge", "Number of messages to delete (max 2500)", true) - .setRequiredRange(1, 2500)); - } - - @Override - public CommandType getType() { - return CommandType.ADMINISTRATION; - } - - @Override - public void execute(MessageCommandContext context) { - if (context.getArgs().length == 1) { - GuildMessageChannel messageChannel = context.getEvent().getGuildChannel(); - ChannelMessagePurger channelMessagePurger = ChannelMessagePurger.getPurger(messageChannel); - channelMessagePurger.purgeMessages(context, Integer.parseInt(context.getArgument(0))); - } else { - context.getChannel().sendMessage("Failed to delete messages!").queue(); - } - } - - @Override - public void execute(SlashCommandContext context) { - int toDelete = context.getEvent().getOption("to-purge", 0, OptionMapping::getAsInt); - context.ackAndWait(true); - - if (toDelete > 0) { - GuildMessageChannel messageChannel = context.getEvent().getGuildChannel(); - ChannelMessagePurger channelMessagePurger = ChannelMessagePurger.getPurger(messageChannel); - boolean lock = channelMessagePurger.canLockBeAcquired(); - channelMessagePurger.purgeMessages(context, toDelete); - - context.replyEphemeral("Processing purge command.. This can take some time."); - - if (!lock) { - context.replyEphemeral("Another purge is currently in progress on this channel, please wait before purging again"); - } - } - } -} From b392d892adf943d9e704cca472a4283f6d66003c Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Wed, 26 Jun 2024 00:05:07 -0400 Subject: [PATCH 131/155] Udio: fix json extraction from updated webpage and add artwork url to audio track --- .../music/source/UdioAudioSourceManager.java | 76 +++++++++++-------- .../netneutrality/utils/MessageFunction.java | 4 + .../source/UdioAudioSourceManagerTest.java | 7 ++ 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java index 264e96e..dd6f9bc 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java @@ -48,10 +48,6 @@ public class UdioAudioSourceManager implements AudioSourceManager { httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager(); } - public HttpInterface getHttpInterface() { - return httpInterfaceManager.getInterface(); - } - @Override public String getSourceName() { return "udio"; @@ -71,6 +67,32 @@ public class UdioAudioSourceManager implements AudioSourceManager { } + + + @Override + public boolean isTrackEncodable(AudioTrack track) { + return true; + } + + @Override + public void encodeTrack(AudioTrack track, DataOutput output) throws IOException { + + } + + @Override + public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException { + return new UdioAudioTrack(trackInfo, this); + } + + @Override + public void shutdown() { + ExceptionTools.closeWithWarnings(httpInterfaceManager); + } + + public HttpInterface getHttpInterface() { + return httpInterfaceManager.getInterface(); + } + private AudioItem loadFromTrackPage(HttpInterface httpInterface, String trackUrl) throws IOException { try (CloseableHttpResponse response = httpInterface.execute(new HttpGet(trackUrl))) { @@ -95,21 +117,22 @@ public class UdioAudioSourceManager implements AudioSourceManager { throw new FriendlyException("Udio: Failed to extract track information from web page.", SUSPICIOUS, null); } - return new UdioAudioTrack(new AudioTrackInfo( - trackInfo.get("title").text(), - trackInfo.get("artist").text(), - (long) (trackInfo.get("duration").as(Double.class) * 1000.0), - trackUrl, - false, - trackUrl - ), this); + String title = trackInfo.get("title").text(); + String artist = trackInfo.get("artist").text(); + long duration = (long) (trackInfo.get("duration").as(Double.class) * 1000.0); + String playbackUrl = trackInfo.get("song_path").text(); + String artworkUrl = getArtworkUrlFromImagePath(trackInfo); + + AudioTrackInfo audioTrackInfo = new AudioTrackInfo(title, artist, duration, trackUrl, false, playbackUrl, artworkUrl, null); + + return new UdioAudioTrack(audioTrackInfo, this); } - JsonBrowser loadTrackInfoFromPageContent(String content) throws IOException { - // start = self.__next_f.push([1,"8: - // end = \n"]) + protected JsonBrowser loadTrackInfoFromPageContent(String content) throws IOException { + String startTag = "self.__next_f.push([1,\"9:"; + String endTag = "\\n\"])"; - String json = DataFormatTools.extractBetween(content, "self.__next_f.push([1,\"8:", "\\n\"])"); + String json = DataFormatTools.extractBetween(content, startTag, endTag); if (json == null) { log.error("Track JSON not found in page"); @@ -127,24 +150,11 @@ public class UdioAudioSourceManager implements AudioSourceManager { } } - @Override - public boolean isTrackEncodable(AudioTrack track) { - return true; - } + private String getArtworkUrlFromImagePath(JsonBrowser trackInfo) { + String imagePath = trackInfo.get("image_path").text(); + String artworkOptions = "width=3840,quality=50"; - @Override - public void encodeTrack(AudioTrack track, DataOutput output) throws IOException { - - } - - @Override - public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException { - return new UdioAudioTrack(trackInfo, this); - } - - @Override - public void shutdown() { - ExceptionTools.closeWithWarnings(httpInterfaceManager); + return imagePath.replace("public", artworkOptions); } } diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 72fcc92..35408b1 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -63,6 +63,10 @@ public class MessageFunction { thumbnail = String.format("https://i3.ytimg.com/vi/%s/hqdefault.jpg", track.getIdentifier()); } + if (type == SourceFinder.AudioSourceType.Udio) { + thumbnail = track.getInfo().artworkUrl; + } + if (thumbnail != null) { message.setThumbnail(thumbnail); } diff --git a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java index e82f49b..0ce0ba3 100644 --- a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java +++ b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java @@ -11,6 +11,7 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import org.junit.Test; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class UdioAudioSourceManagerTest { @@ -27,5 +28,11 @@ public class UdioAudioSourceManagerTest { AudioTrackInfo info = audioTrack.getInfo(); assertNotNull(info); + + assertNotNull(info.artworkUrl); + + String artworkOptions = "width=3840,quality=50"; + assertTrue(info.artworkUrl.contains(artworkOptions)); + } } From 7b2098a27dc6c6b0358f1fa83c015c05312fcc68 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Fri, 28 Jun 2024 20:49:02 -0400 Subject: [PATCH 132/155] Udio: fix wrong artwork url --- .../java/netneutrality/music/source/UdioAudioSourceManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java index dd6f9bc..54cca31 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java @@ -152,7 +152,7 @@ public class UdioAudioSourceManager implements AudioSourceManager { private String getArtworkUrlFromImagePath(JsonBrowser trackInfo) { String imagePath = trackInfo.get("image_path").text(); - String artworkOptions = "width=3840,quality=50"; + String artworkOptions = "width=3840,quality=75"; return imagePath.replace("public", artworkOptions); } From eb7136d5b9a6b164ee877afb3b33cace65561fce Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Fri, 28 Jun 2024 20:49:56 -0400 Subject: [PATCH 133/155] Add simple script to build bot and update CI image --- .gitlab-ci.yml | 2 +- build-bot.sh | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 build-bot.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 904a55f..942e883 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: openjdk:17-jdk-slim +image: eclipse-temurin:17-jdk-alpine variables: MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode" diff --git a/build-bot.sh b/build-bot.sh new file mode 100644 index 0000000..80881c4 --- /dev/null +++ b/build-bot.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +git fetch || exit 1 +git pull || exit 1 + +sudo docker compose down || exit 1 +sudo docker compose pull || exit 1 +sudo docker compose build || exit 1 + +sudo docker compose up -d +sudo docker compose logs -f \ No newline at end of file From 0b1c326f40008d1ed91d0d7da94ee9951218b29b Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Mon, 1 Jul 2024 02:42:51 -0400 Subject: [PATCH 134/155] Udio: update test case --- .../netneutrality/music/source/UdioAudioSourceManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java index 0ce0ba3..ad4efde 100644 --- a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java +++ b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java @@ -31,7 +31,7 @@ public class UdioAudioSourceManagerTest { assertNotNull(info.artworkUrl); - String artworkOptions = "width=3840,quality=50"; + String artworkOptions = "width=3840,quality=75"; assertTrue(info.artworkUrl.contains(artworkOptions)); } From f51ae465bda06e5a6f018944ffbe7b5e7fe333d3 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Wed, 10 Jul 2024 20:28:28 -0400 Subject: [PATCH 135/155] change how properties file is loaded and rely on environment variables if it doesn't exist --- README.md | 7 ++- pom.xml | 6 -- .../java/netneutrality/NetNeutrality.java | 29 +++++++--- .../netneutrality/core/SessionManager.java | 2 +- .../core/context/MessageCommandContext.java | 2 +- .../java/netneutrality/utils/Settings.java | 56 +++++++------------ .../netneutrality/utils/SettingsTest.java | 33 ----------- 7 files changed, 46 insertions(+), 89 deletions(-) delete mode 100644 src/test/java/netneutrality/utils/SettingsTest.java diff --git a/README.md b/README.md index 41c062b..9aff4d0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Net Neutrality Discord bot -This is the source code for my custom discord bot. This is a personal project, so I offer no support on how to build it. +This is the source code for my custom discord bot. +This is a personal project, so I offer no support on how to build it. -The configuration is contained in the file "bot.properties". There is an example file for all the variables, they can also be overwritten by environment variables. The preferred method for running the bot is by using Docker Compose like this: @@ -10,3 +10,6 @@ The preferred method for running the bot is by using Docker Compose like this: docker compose build docker compose up -d ``` + +The environment variables needed for the bot to run are available in the file **bot.properties.example** +If running locally without Docker, you need to copy the example file to **bot.properties** and fill the values. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 85df176..bc81439 100644 --- a/pom.xml +++ b/pom.xml @@ -56,12 +56,6 @@ <url>https://repo.maven.apache.org/maven2/</url> </repository> - <repository> - <id>dv8tion</id> - <name>m2-dv8tion</name> - <url>https://m2.dv8tion.net/releases</url> - </repository> - <repository> <id>jitpack</id> <url>https://jitpack.io</url> diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index aaa9b7c..39c7e0d 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -39,15 +39,20 @@ public class NetNeutrality { public static final String VERSION = "2.0.0"; public static void main(String[] args) { - String sentryDsn = Settings.getInstance().get("SENTRY_DSN"); String env = Settings.getInstance().get("BOT_ENV", "dev"); - Sentry.init(options -> { - options.setDsn(sentryDsn); - options.setEnvironment(env); - options.setTracesSampleRate(1.0); - options.setDebug(false); - options.setRelease(String.format("netneutrality@%s", VERSION)); - }); + + String sentryDsn = Settings.getInstance().get("SENTRY_DSN"); + if (sentryDsn != null) { + logger.info("Found Sentry DSN in config, setting up the SDK.."); + + Sentry.init(options -> { + options.setDsn(sentryDsn); + options.setEnvironment(env); + options.setTracesSampleRate(1.0); + options.setDebug(false); + options.setRelease(String.format("netneutrality@%s", VERSION)); + }); + } if ("dev".equals(env)) { Configurator.setLevel("net.dv8tion.jda", Level.DEBUG); @@ -67,9 +72,15 @@ public class NetNeutrality { } public static void initJDA() { + String token = Settings.getInstance().get("BOT_TOKEN"); + if (token == null) { + DBController.shutdown(); + throw new RuntimeException("No bot token provided, exiting."); + } + try { jda = JDABuilder - .createDefault(Settings.getInstance().get("BOT_TOKEN")) + .createDefault(token) .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES, GatewayIntent.MESSAGE_CONTENT) .setActivity(Activity.watching("me load...")) .build(); diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index fd4743a..bb38ce1 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -52,7 +52,7 @@ public class SessionManager { } shutdown(); - logger.error("Error connecting to database. Shutting down..", e); + logger.error("Error connecting to database. Shutting down.."); System.exit(1); } } diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java index 2906077..3491a66 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -184,7 +184,7 @@ public class MessageCommandContext implements CommandContext { } public boolean isMessageFromCreator() { - String creatorId = Settings.getInstance().getCreatorId(); + String creatorId = Settings.getInstance().get("BOT_OWNER"); return creatorId.equals(member.getId()); } diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 10f9bf9..c35ba2b 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -6,7 +6,7 @@ package netneutrality.utils; * https://discord.gg/qUa6zNFZsd */ -import org.apache.commons.io.FileUtils; +import org.apache.logging.log4j.LogManager; import java.io.File; import java.io.FileInputStream; @@ -18,46 +18,28 @@ public class Settings { private static Settings INSTANCE; private final Properties prop = new Properties(); + public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - public Settings() { + private Settings() { + checkAndLoadPropertiesFile(); + loadEnvironmentVariables(); + } + + private void checkAndLoadPropertiesFile() { File propFile = new File("bot.properties"); - File exampleFile = new File("bot.properties.example"); - FileInputStream fis = null; - try { - if (!propFile.exists() && !exampleFile.exists()) { - System.err.println("Missing example config file in root directory."); - System.exit(1); - } - - if (!propFile.exists()) { - FileUtils.copyFile(exampleFile, propFile); - System.err.println("Config file was created, please edit bot.properties before launching bot"); - } - - fis = new FileInputStream(propFile); + try (FileInputStream fis = new FileInputStream(propFile)) { prop.load(fis); - - loadEnvironmentVariables(); } catch (IOException e) { - System.err.println("Can't find config file or config file is empty: bot.properties"); - System.exit(1); - } finally { - try { - if (fis != null) - fis.close(); - } catch (IOException ignored) { } + LogManager.getLogger(Settings.class).info("Can't load settings from bot.properties, bot is most likely running in docker. Using environment variables instead."); } - } private void loadEnvironmentVariables() { Map<String, String> envs = System.getenv(); for (Map.Entry<String, String> env : envs.entrySet()) { - if (prop.containsKey(env.getKey())) { - prop.setProperty(env.getKey(), env.getValue()); - } + prop.setProperty(env.getKey(), env.getValue()); } } @@ -70,11 +52,17 @@ public class Settings { } public String get(String key) { - return prop.getProperty(key); + String property = prop.getProperty(key); + + if (property == null) { + LogManager.getLogger(Settings.class).error("Can't find property with key {}", key); + } + + return property; } public String get(String key, String def) { - String property = prop.getProperty(key); + String property = get(key); if (property == null || property.isEmpty()) return def; @@ -82,10 +70,4 @@ public class Settings { return property; } - public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; - - public String getCreatorId() { - return get("BOT_OWNER"); - } - } diff --git a/src/test/java/netneutrality/utils/SettingsTest.java b/src/test/java/netneutrality/utils/SettingsTest.java deleted file mode 100644 index 38fd259..0000000 --- a/src/test/java/netneutrality/utils/SettingsTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package netneutrality.utils; - -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; - -public class SettingsTest { - - private Settings instance; - - @Before - public void setUp() { - instance = Settings.getInstance(); - } - - @Test - public void get() { - assertNotNull(instance.get("BOT_TOKEN")); - } - - @Test - public void getCreator() { - String creator = instance.getCreatorId(); - assertNotNull(creator); - } -} From f3d11a5f98f25b246580169332f7dc8f88b7a5d6 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Thu, 11 Jul 2024 21:07:47 -0400 Subject: [PATCH 136/155] Changed properties name and update build process --- .env.example | 13 ++++++++++ .gitignore | 4 ++- Dockerfile | 2 -- bot.properties.example | 25 ++++++++----------- docker-compose-webapp.yml | 12 ++++++--- pom.xml | 3 +++ .../java/netneutrality/NetNeutrality.java | 9 +++---- .../netneutrality/core/SessionManager.java | 10 ++++---- .../core/context/MessageCommandContext.java | 6 ++--- .../hooks/message/MessageReceivedHandler.java | 2 +- .../java/netneutrality/utils/Settings.java | 3 +-- src/main/resources/META-INF/MANIFEST.MF | 1 - 12 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ffdbd3b --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +NETNEUTRALITY_BOT_ENV=dev +NETNEUTRALITY_BOT_TOKEN= +NETNEUTRALITY_BOT_PREFIX=$ +NETNEUTRALITY_BOT_OWNER= +NETNEUTRALITY_API_PORT=9000 + +NETNEUTRALITY_MYSQL_HOST=127.0.0.1 +NETNEUTRALITY_MYSQL_USER=root +NETNEUTRALITY_MYSQL_PASSWORD= +NETNEUTRALITY_MYSQL_DATABASE= +NETNEUTRALITY_MYSQL_PORT=3306 + +NETNEUTRALITY_SENTRY_DSN= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1a12202..d7ff51c 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,6 @@ log/ target/ #log4j -logs/ \ No newline at end of file +logs/ + +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index aed3bb3..cc852a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ FROM eclipse-temurin:17-jdk-alpine as build COPY .mvn/ .mvn COPY mvnw pom.xml ./ COPY src ./src -COPY bot.properties.example bot.properties ./ RUN ["chmod", "+x", "./mvnw"] RUN ./mvnw install @@ -19,7 +18,6 @@ WORKDIR /app ARG API_PORT=9000 EXPOSE ${API_PORT} -COPY bot.properties.example bot.properties ./ COPY startup.sh ./ COPY --from=build /target/netneutrality-jar-with-dependencies.jar ./ diff --git a/bot.properties.example b/bot.properties.example index 29a40f3..62682ba 100644 --- a/bot.properties.example +++ b/bot.properties.example @@ -1,16 +1,13 @@ -BOT_ENV=dev -BOT_VERSION=1.0.0 -BOT_TOKEN= -BOT_PREFIX= -BOT_OWNER= -GG_EMAIL= -GG_PASS= -API_PORT=9000 +NETNEUTRALITY_BOT_ENV=dev +NETNEUTRALITY_BOT_TOKEN= +NETNEUTRALITY_BOT_PREFIX= +NETNEUTRALITY_BOT_OWNER= +NETNEUTRALITY_API_PORT=9000 -MYSQL_HOST=127.0.0.1 -MYSQL_USER=root -MYSQL_PASSWORD= -MYSQL_DATABASE= -MYSQL_PORT=3306 +NETNEUTRALITY_MYSQL_HOST=127.0.0.1 +NETNEUTRALITY_MYSQL_USER=root +NETNEUTRALITY_MYSQL_PASSWORD= +NETNEUTRALITY_MYSQL_DATABASE= +NETNEUTRALITY_MYSQL_PORT=3306 -SENTRY_DSN= \ No newline at end of file +NETNEUTRALITY_SENTRY_DSN= \ No newline at end of file diff --git a/docker-compose-webapp.yml b/docker-compose-webapp.yml index 07b9f07..bd39fd7 100644 --- a/docker-compose-webapp.yml +++ b/docker-compose-webapp.yml @@ -1,7 +1,8 @@ services: db: - image: mariadb:10.7 - restart: always + image: mariadb:lts + container_name: db + restart: unless-stopped volumes: - netneutrality-db:/var/lib/mysql - ./sql:/docker-entrypoint-initdb.d @@ -10,17 +11,20 @@ services: MYSQL_PASSWORD: 'password' MYSQL_DATABASE: 'netneutrality' MYSQL_ROOT_PASSWORD: 'password' + MARIADB_AUTO_UPGRADE: '1' ports: - "3306" networks: - internal bot: - image: netneutrality:dev + container_name: bot build: ./ - restart: always + restart: unless-stopped depends_on: - db + volumes: + - ./logs:/app/logs environment: MYSQL_HOST: 'db' MYSQL_USER: 'java' diff --git a/pom.xml b/pom.xml index bc81439..37612b8 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,9 @@ <version>3.7.1</version> <configuration> <archive> + <manifestEntries> + <Multi-Release>true</Multi-Release> + </manifestEntries> <manifest> <addClasspath>true</addClasspath> <mainClass>${main.class}</mainClass> diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 39c7e0d..3155d74 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -39,9 +39,9 @@ public class NetNeutrality { public static final String VERSION = "2.0.0"; public static void main(String[] args) { - String env = Settings.getInstance().get("BOT_ENV", "dev"); + String env = Settings.getInstance().get("NETNEUTRALITY_BOT_ENV", "dev"); - String sentryDsn = Settings.getInstance().get("SENTRY_DSN"); + String sentryDsn = Settings.getInstance().get("NETNEUTRALITY_SENTRY_DSN"); if (sentryDsn != null) { logger.info("Found Sentry DSN in config, setting up the SDK.."); @@ -50,7 +50,6 @@ public class NetNeutrality { options.setEnvironment(env); options.setTracesSampleRate(1.0); options.setDebug(false); - options.setRelease(String.format("netneutrality@%s", VERSION)); }); } @@ -64,7 +63,7 @@ public class NetNeutrality { MusicManager.initPlayerManager(); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); jda.addEventListener(new SlashCommandHooks()); - new WebApi(Integer.parseInt(Settings.getInstance().get("API_PORT", "9000"))); + new WebApi(Integer.parseInt(Settings.getInstance().get("NETNEUTRALITY_API_PORT", "9000"))); jda.getPresence().setActivity(Activity.watching("you")); Runtime.getRuntime().addShutdownHook(new BaseThreadFactory("shutdown").newThread(new ShutdownThread())); @@ -72,7 +71,7 @@ public class NetNeutrality { } public static void initJDA() { - String token = Settings.getInstance().get("BOT_TOKEN"); + String token = Settings.getInstance().get("NETNEUTRALITY_BOT_TOKEN"); if (token == null) { DBController.shutdown(); throw new RuntimeException("No bot token provided, exiting."); diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index bb38ce1..5d398c8 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -29,10 +29,10 @@ public class SessionManager { try { StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder().configure(); Map<String, Object> settings = new HashMap<>(); - String dbName = Settings.getInstance().get("MYSQL_DATABASE", "netneutrality"); - String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); - String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); - String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); + String dbName = Settings.getInstance().get("NETNEUTRALITY_MYSQL_DATABASE", "netneutrality"); + String dbUser = Settings.getInstance().get("NETNEUTRALITY_MYSQL_USER", "root"); + String dbPass = Settings.getInstance().get("NETNEUTRALITY_MYSQL_PASSWORD", ""); + String dbHost = Settings.getInstance().get("NETNEUTRALITY_MYSQL_HOST", "localhost"); logger.info(String.format("Connecting to database '%s' at %s:3306 with user '%s'", dbName, dbHost, dbUser)); settings.put(Environment.URL, String.format("jdbc:mysql://%s:3306/%s", dbHost, dbName)); @@ -46,7 +46,7 @@ public class SessionManager { sessionFactory = metadata.getSessionFactoryBuilder().build(); } catch (Exception e) { - String env = Settings.getInstance().get("BOT_ENV", "dev"); + String env = Settings.getInstance().get("NETNEUTRALITY_BOT_ENV", "dev"); if (!"dev".equals(env)) { Sentry.captureException(e); } diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/netneutrality/core/context/MessageCommandContext.java index 3491a66..52484fe 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/netneutrality/core/context/MessageCommandContext.java @@ -72,7 +72,7 @@ public class MessageCommandContext implements CommandContext { public String[] getArgs() { String msg = message.getContentDisplay().trim(); - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + msg = msg.substring(Settings.getInstance().get("NETNEUTRALITY_BOT_PREFIX", "$").length()).trim(); String cmd = msg.split(" ", 2)[0]; String[] args = msg.replaceFirst("(" + cmd + ")(\\s+)?", "").split("\s"); @@ -84,7 +84,7 @@ public class MessageCommandContext implements CommandContext { public String getMessageText() { String msg = message.getContentDisplay().trim(); - msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); + msg = msg.substring(Settings.getInstance().get("NETNEUTRALITY_BOT_PREFIX", "$").length()).trim(); String cmd = msg.split(" ", 2)[0]; return msg.replaceFirst("(" + cmd + ")(\s)?", ""); @@ -184,7 +184,7 @@ public class MessageCommandContext implements CommandContext { } public boolean isMessageFromCreator() { - String creatorId = Settings.getInstance().get("BOT_OWNER"); + String creatorId = Settings.getInstance().get("NETNEUTRALITY_BOT_OWNER"); return creatorId.equals(member.getId()); } diff --git a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java index f7a87c8..6f19d32 100644 --- a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java @@ -33,7 +33,7 @@ public class MessageReceivedHandler extends ListenerAdapter { GuildManager.getManager(context.getGuild()).checkAndLogMessage(message, context.getGuildUser(), context.getChannel()); String rawMessage = message.getContentDisplay().trim(); - String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); + String prefix = Settings.getInstance().get("NETNEUTRALITY_BOT_PREFIX", "$"); if (rawMessage.startsWith(prefix)) { rawMessage = rawMessage.replaceFirst(String.format("^[%s\\s]{1,}", prefix), "").trim(); diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index c35ba2b..21738d4 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -17,6 +17,7 @@ import java.util.Properties; public class Settings { private static Settings INSTANCE; + private final File propFile = new File("bot.properties"); private final Properties prop = new Properties(); public final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; @@ -26,8 +27,6 @@ public class Settings { } private void checkAndLoadPropertiesFile() { - File propFile = new File("bot.properties"); - try (FileInputStream fis = new FileInputStream(propFile)) { prop.load(fis); } catch (IOException e) { diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF index 329b72b..2cd435e 100644 --- a/src/main/resources/META-INF/MANIFEST.MF +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -1,3 +1,2 @@ Manifest-Version: 1.0 Main-Class: netneutrality.NetNeutrality - From e239be6c9a0e1d33b19e0a4f18729154fd02c054 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 13 Jul 2024 22:11:17 -0400 Subject: [PATCH 137/155] ci: add commitizen configs and ci scripts --- .cz.toml | 13 +++++++++++++ ci-scripts/commit_java_version.sh | 2 ++ ci-scripts/prepare_java_version.sh | 2 ++ 3 files changed, 17 insertions(+) create mode 100644 .cz.toml create mode 100644 ci-scripts/commit_java_version.sh create mode 100644 ci-scripts/prepare_java_version.sh diff --git a/.cz.toml b/.cz.toml new file mode 100644 index 0000000..b390a9b --- /dev/null +++ b/.cz.toml @@ -0,0 +1,13 @@ +[tool.commitizen] +name = "cz_conventional_commits" +tag_format = "$version" +version_scheme = "semver" +version = "2.0.0" +update_changelog_on_bump = true +major_version_zero = false +pre_bump_hooks = [ + "ci-scripts/prepare_java_version.sh" +] +post_bump_hooks = [ + "ci-scripts/commit_java_version.sh" +] \ No newline at end of file diff --git a/ci-scripts/commit_java_version.sh b/ci-scripts/commit_java_version.sh new file mode 100644 index 0000000..469a776 --- /dev/null +++ b/ci-scripts/commit_java_version.sh @@ -0,0 +1,2 @@ +#!/bin/bash +../mvnw versions:commit \ No newline at end of file diff --git a/ci-scripts/prepare_java_version.sh b/ci-scripts/prepare_java_version.sh new file mode 100644 index 0000000..9cac26b --- /dev/null +++ b/ci-scripts/prepare_java_version.sh @@ -0,0 +1,2 @@ +#!/bin/bash +../mvnw versions:set -DnewVersion=$CZ_PRE_NEW_VERSION From 2b08351f6d3f7d18c31db8277e1a2181570772f3 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 13 Jul 2024 22:24:07 -0400 Subject: [PATCH 138/155] feat(Settings): add helpers to get version number of bot --- .../java/netneutrality/http/WebModule.java | 12 +++-- .../java/netneutrality/utils/Settings.java | 47 +++++++++++++++++++ .../netneutrality/utils/SettingsTest.java | 30 ++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/test/java/netneutrality/utils/SettingsTest.java diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/netneutrality/http/WebModule.java index ce17a78..ab9d508 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/netneutrality/http/WebModule.java @@ -170,11 +170,17 @@ public class WebModule { * * @return the response as a JSONArray */ - public JSONArray getAsArray() throws JSONException, IOException { + public JSONArray getAsArray() { if (response == null) throw new RuntimeException("Request has not been sent"); - - return new JSONArray(response.body().string()); + + try { + ResponseBody body = response.body(); + return new JSONArray(body.string()); + } catch (IOException | NullPointerException e) { + LogHandler.log(e); + return new JSONArray(); + } } /** diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/netneutrality/utils/Settings.java index 21738d4..4c73597 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/netneutrality/utils/Settings.java @@ -6,11 +6,15 @@ package netneutrality.utils; * https://discord.gg/qUa6zNFZsd */ +import netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.Map; import java.util.Properties; @@ -69,4 +73,47 @@ public class Settings { return property; } + public String getMavenVersion() { + String version = null; + + // try to load from maven properties first + try { + Properties p = new Properties(); + InputStream is = getClass().getResourceAsStream("/META-INF/maven/me.bobert/netneutrality/pom.properties"); + if (is != null) { + p.load(is); + version = p.getProperty("version", ""); + } + } catch (Exception ignored) {} + + // fallback to using Java API + if (version == null) { + Package aPackage = getClass().getPackage(); + if (aPackage != null) { + version = aPackage.getImplementationVersion(); + if (version == null) { + version = aPackage.getSpecificationVersion(); + } + } + } + + if (version == null) { + version = "0.0.0"; + } + + return version; + } + + public String getGitVersion() { + String gitlabHost = "https://git.bobert.me"; + String gitlabProjectId = "22"; + String latestReleaseUrl = String.format("%s/api/v4/projects/%s/releases/", gitlabHost, gitlabProjectId); + + JSONArray json = new WebModule(latestReleaseUrl).request().getAsArray(); + if (json.isNull(0)) { + return "0.0.0"; + } + + return json.getJSONObject(0).getString("tag_name"); + } } diff --git a/src/test/java/netneutrality/utils/SettingsTest.java b/src/test/java/netneutrality/utils/SettingsTest.java new file mode 100644 index 0000000..732b3b7 --- /dev/null +++ b/src/test/java/netneutrality/utils/SettingsTest.java @@ -0,0 +1,30 @@ +package netneutrality.utils; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SettingsTest { + + @Test + public void getMavenVersion() { + String version = Settings.getInstance().getMavenVersion(); + System.out.println(version); + + assertNotNull(version); + } + + @Test + public void getGitVersion() { + String version = Settings.getInstance().getGitVersion(); + System.out.println(version); + + assertNotNull(version); + } +} \ No newline at end of file From f4c7e9c7039da726b8d4f21195c67f7b67a95d5c Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 13 Jul 2024 23:10:06 -0400 Subject: [PATCH 139/155] refactor: change package path to reflect group id of pom.xml BREAKING CHANGE: --- pom.xml | 17 +++++++++- .../bobert}/netneutrality/NetNeutrality.java | 31 +++++++++---------- .../command/AbstractCommand.java | 4 +-- .../command/AbstractMusicCommand.java | 8 ++--- .../command/CommandExecutionResult.java | 2 +- .../netneutrality/command/CommandManager.java | 6 ++-- .../netneutrality/command/CommandType.java | 2 +- .../netneutrality/command/ICommand.java | 6 ++-- .../command/admin/BlacklistCommand.java | 20 ++++++------ .../command/basic/HelpCommand.java | 14 ++++----- .../command/basic/PingCommand.java | 12 +++---- .../command/bot/ConfigureCommand.java | 18 +++++------ .../command/crypto/CryptoPriceCommand.java | 16 +++++----- .../netneutrality/command/custom/.gitignore | 0 .../command/music/BitconnectCommand.java | 14 ++++----- .../command/music/ClearQueueCommand.java | 16 +++++----- .../music/CurrentlyPlayingCommand.java | 16 +++++----- .../command/music/JoinCommand.java | 14 ++++----- .../command/music/LeaveCommand.java | 14 ++++----- .../command/music/PlayCommand.java | 12 +++---- .../command/music/QueueCommand.java | 16 +++++----- .../command/music/ShuffleCommand.java | 12 +++---- .../command/music/SkipCommand.java | 16 +++++----- .../command/music/StopCommand.java | 16 +++++----- .../command/music/ViewQueueCommand.java | 16 +++++----- .../command/music/VolumeCommand.java | 16 +++++----- .../command/music/VoteSkipCommand.java | 14 ++++----- .../bobert}/netneutrality/core/BotState.java | 6 ++-- .../netneutrality/core/CommandProcessor.java | 21 +++++++------ .../core/GuildConfigManager.java | 10 +++--- .../netneutrality/core/GuildManager.java | 18 +++++------ .../netneutrality/core/LogHandler.java | 12 +++---- .../netneutrality/core/SessionManager.java | 4 +-- .../core/context/CommandContext.java | 4 +-- .../core/context/MessageCommandContext.java | 10 +++--- .../core/context/SlashCommandContext.java | 4 +-- .../netneutrality/db/AbstractController.java | 4 +-- .../netneutrality/db/DBController.java | 4 +-- .../bobert}/netneutrality/db/GSettings.java | 2 +- .../db/controllers/DBBlacklist.java | 14 ++++----- .../db/controllers/DBMessage.java | 8 ++--- .../netneutrality/db/entities/OBlacklist.java | 2 +- .../netneutrality/db/entities/OGuild.java | 2 +- .../db/entities/OGuildSetting.java | 2 +- .../db/entities/OLogMessage.java | 2 +- .../netneutrality/db/entities/OLogging.java | 2 +- .../netneutrality/db/entities/OLoggingId.java | 2 +- .../exceptions/CommandException.java | 4 +-- .../exceptions/CommandExecutionException.java | 4 +-- .../exceptions/ExecutorException.java | 4 +-- .../hooks/SlashCommandHooks.java | 6 ++-- .../hooks/guilds/ServerJoinHandler.java | 4 +-- .../hooks/message/EditHandler.java | 16 +++++----- .../hooks/message/MessageReceivedHandler.java | 12 +++---- .../hooks/message/ReactionHandler.java | 2 +- .../hooks/voice/VoiceEventHandler.java | 2 +- .../bobert}/netneutrality/http/WebModule.java | 7 ++--- .../http/server/AbstractHandler.java | 2 +- .../http/server/ActionHandler.java | 8 ++--- .../http/server/GuildHandler.java | 4 +-- .../http/server/RootHandler.java | 2 +- .../netneutrality/http/server/WebApi.java | 4 +-- .../music/AudioPlayerSendHandler.java | 2 +- .../netneutrality/music/MusicManager.java | 22 ++++++------- .../netneutrality/music/QueueManager.java | 4 +-- .../netneutrality/music/SourceFinder.java | 2 +- .../netneutrality/music/TrackLoader.java | 14 ++++----- .../music/TrackLoadingHandler.java | 8 ++--- .../netneutrality/music/TrackScheduler.java | 6 ++-- .../music/loadable/AppleMostPlayed.java | 2 +- .../music/loadable/CachedSource.java | 2 +- .../music/loadable/LoadableMusicSource.java | 2 +- .../music/loadable/LoadableSong.java | 2 +- .../music/loadable/LoadableSourceManager.java | 4 +-- .../music/source/UdioAudioSourceManager.java | 2 +- .../music/source/UdioAudioTrack.java | 2 +- .../thread/BaseThreadFactory.java | 4 +-- .../MusicPlayerAutoDisconnectThread.java | 6 ++-- .../netneutrality/thread/ShutdownThread.java | 4 +-- .../netneutrality/thread/ThreadManager.java | 2 +- .../utils/ChannelMessagePurger.java | 6 ++-- .../bobert}/netneutrality/utils/JpaUtils.java | 8 ++--- .../netneutrality/utils/MessageFunction.java | 18 +++++------ .../netneutrality/utils/MiscUtils.java | 2 +- .../netneutrality/utils/MusicUtils.java | 8 ++--- .../bobert}/netneutrality/utils/Settings.java | 21 +++---------- .../netneutrality/utils/UserFunction.java | 2 +- src/main/resources/META-INF/MANIFEST.MF | 2 +- src/main/resources/app.properties | 1 + src/main/resources/hibernate.cfg.xml | 12 +++---- src/main/resources/log4j2.properties | 2 +- .../music/LoadableSourceTest.java | 6 ++-- .../source/UdioAudioSourceManagerTest.java | 2 ++ .../netneutrality/utils/SettingsTest.java | 3 +- 94 files changed, 373 insertions(+), 372 deletions(-) rename src/main/java/{ => me/bobert}/netneutrality/NetNeutrality.java (80%) rename src/main/java/{ => me/bobert}/netneutrality/command/AbstractCommand.java (90%) rename src/main/java/{ => me/bobert}/netneutrality/command/AbstractMusicCommand.java (90%) rename src/main/java/{ => me/bobert}/netneutrality/command/CommandExecutionResult.java (97%) rename src/main/java/{ => me/bobert}/netneutrality/command/CommandManager.java (95%) rename src/main/java/{ => me/bobert}/netneutrality/command/CommandType.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/command/ICommand.java (85%) rename src/main/java/{ => me/bobert}/netneutrality/command/admin/BlacklistCommand.java (86%) rename src/main/java/{ => me/bobert}/netneutrality/command/basic/HelpCommand.java (81%) rename src/main/java/{ => me/bobert}/netneutrality/command/basic/PingCommand.java (78%) rename src/main/java/{ => me/bobert}/netneutrality/command/bot/ConfigureCommand.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/command/crypto/CryptoPriceCommand.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/command/custom/.gitignore (100%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/BitconnectCommand.java (76%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/ClearQueueCommand.java (84%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/CurrentlyPlayingCommand.java (76%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/JoinCommand.java (85%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/LeaveCommand.java (77%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/PlayCommand.java (80%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/QueueCommand.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/ShuffleCommand.java (73%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/SkipCommand.java (84%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/StopCommand.java (76%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/ViewQueueCommand.java (78%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/VolumeCommand.java (83%) rename src/main/java/{ => me/bobert}/netneutrality/command/music/VoteSkipCommand.java (75%) rename src/main/java/{ => me/bobert}/netneutrality/core/BotState.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/core/CommandProcessor.java (84%) rename src/main/java/{ => me/bobert}/netneutrality/core/GuildConfigManager.java (91%) rename src/main/java/{ => me/bobert}/netneutrality/core/GuildManager.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/core/LogHandler.java (89%) rename src/main/java/{ => me/bobert}/netneutrality/core/SessionManager.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/core/context/CommandContext.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/core/context/MessageCommandContext.java (95%) rename src/main/java/{ => me/bobert}/netneutrality/core/context/SlashCommandContext.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/db/AbstractController.java (80%) rename src/main/java/{ => me/bobert}/netneutrality/db/DBController.java (90%) rename src/main/java/{ => me/bobert}/netneutrality/db/GSettings.java (93%) rename src/main/java/{ => me/bobert}/netneutrality/db/controllers/DBBlacklist.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/db/controllers/DBMessage.java (93%) rename src/main/java/{ => me/bobert}/netneutrality/db/entities/OBlacklist.java (97%) rename src/main/java/{ => me/bobert}/netneutrality/db/entities/OGuild.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/db/entities/OGuildSetting.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/db/entities/OLogMessage.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/db/entities/OLogging.java (95%) rename src/main/java/{ => me/bobert}/netneutrality/db/entities/OLoggingId.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/exceptions/CommandException.java (84%) rename src/main/java/{ => me/bobert}/netneutrality/exceptions/CommandExecutionException.java (81%) rename src/main/java/{ => me/bobert}/netneutrality/exceptions/ExecutorException.java (74%) rename src/main/java/{ => me/bobert}/netneutrality/hooks/SlashCommandHooks.java (80%) rename src/main/java/{ => me/bobert}/netneutrality/hooks/guilds/ServerJoinHandler.java (86%) rename src/main/java/{ => me/bobert}/netneutrality/hooks/message/EditHandler.java (82%) rename src/main/java/{ => me/bobert}/netneutrality/hooks/message/MessageReceivedHandler.java (83%) rename src/main/java/{ => me/bobert}/netneutrality/hooks/message/ReactionHandler.java (94%) rename src/main/java/{ => me/bobert}/netneutrality/hooks/voice/VoiceEventHandler.java (90%) rename src/main/java/{ => me/bobert}/netneutrality/http/WebModule.java (97%) rename src/main/java/{ => me/bobert}/netneutrality/http/server/AbstractHandler.java (95%) rename src/main/java/{ => me/bobert}/netneutrality/http/server/ActionHandler.java (93%) rename src/main/java/{ => me/bobert}/netneutrality/http/server/GuildHandler.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/http/server/RootHandler.java (90%) rename src/main/java/{ => me/bobert}/netneutrality/http/server/WebApi.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/music/AudioPlayerSendHandler.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/music/MusicManager.java (93%) rename src/main/java/{ => me/bobert}/netneutrality/music/QueueManager.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/music/SourceFinder.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/music/TrackLoader.java (91%) rename src/main/java/{ => me/bobert}/netneutrality/music/TrackLoadingHandler.java (95%) rename src/main/java/{ => me/bobert}/netneutrality/music/TrackScheduler.java (97%) rename src/main/java/{ => me/bobert}/netneutrality/music/loadable/AppleMostPlayed.java (95%) rename src/main/java/{ => me/bobert}/netneutrality/music/loadable/CachedSource.java (94%) rename src/main/java/{ => me/bobert}/netneutrality/music/loadable/LoadableMusicSource.java (84%) rename src/main/java/{ => me/bobert}/netneutrality/music/loadable/LoadableSong.java (89%) rename src/main/java/{ => me/bobert}/netneutrality/music/loadable/LoadableSourceManager.java (94%) rename src/main/java/{ => me/bobert}/netneutrality/music/source/UdioAudioSourceManager.java (99%) rename src/main/java/{ => me/bobert}/netneutrality/music/source/UdioAudioTrack.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/thread/BaseThreadFactory.java (87%) rename src/main/java/{ => me/bobert}/netneutrality/thread/MusicPlayerAutoDisconnectThread.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/thread/ShutdownThread.java (87%) rename src/main/java/{ => me/bobert}/netneutrality/thread/ThreadManager.java (98%) rename src/main/java/{ => me/bobert}/netneutrality/utils/ChannelMessagePurger.java (97%) rename src/main/java/{ => me/bobert}/netneutrality/utils/JpaUtils.java (93%) rename src/main/java/{ => me/bobert}/netneutrality/utils/MessageFunction.java (96%) rename src/main/java/{ => me/bobert}/netneutrality/utils/MiscUtils.java (92%) rename src/main/java/{ => me/bobert}/netneutrality/utils/MusicUtils.java (86%) rename src/main/java/{ => me/bobert}/netneutrality/utils/Settings.java (79%) rename src/main/java/{ => me/bobert}/netneutrality/utils/UserFunction.java (92%) create mode 100644 src/main/resources/app.properties diff --git a/pom.xml b/pom.xml index 37612b8..a887824 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ <packaging>jar</packaging> <properties> - <main.class>netneutrality.NetNeutrality</main.class> + <main.class>me.bobert.netneutrality.NetNeutrality</main.class> <java.version>17</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> @@ -20,7 +20,22 @@ </properties> <build> + <resources> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>3.3.1</version> + <configuration> + <propertiesEncoding>UTF-8</propertiesEncoding> + </configuration> + </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/me/bobert/netneutrality/NetNeutrality.java similarity index 80% rename from src/main/java/netneutrality/NetNeutrality.java rename to src/main/java/me/bobert/netneutrality/NetNeutrality.java index 3155d74..ea394f2 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/me/bobert/netneutrality/NetNeutrality.java @@ -1,4 +1,4 @@ -package netneutrality; +package me.bobert.netneutrality; /* * Copyright (c) anthorob @@ -13,19 +13,19 @@ import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.exceptions.InvalidTokenException; import net.dv8tion.jda.api.requests.GatewayIntent; -import netneutrality.command.CommandManager; -import netneutrality.core.LogHandler; -import netneutrality.db.DBController; -import netneutrality.hooks.SlashCommandHooks; -import netneutrality.hooks.guilds.ServerJoinHandler; -import netneutrality.hooks.message.EditHandler; -import netneutrality.hooks.message.MessageReceivedHandler; -import netneutrality.http.server.WebApi; -import netneutrality.music.MusicManager; -import netneutrality.thread.BaseThreadFactory; -import netneutrality.thread.ShutdownThread; -import netneutrality.thread.ThreadManager; -import netneutrality.utils.Settings; +import me.bobert.netneutrality.command.CommandManager; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.db.DBController; +import me.bobert.netneutrality.hooks.SlashCommandHooks; +import me.bobert.netneutrality.hooks.guilds.ServerJoinHandler; +import me.bobert.netneutrality.hooks.message.EditHandler; +import me.bobert.netneutrality.hooks.message.MessageReceivedHandler; +import me.bobert.netneutrality.http.server.WebApi; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.thread.BaseThreadFactory; +import me.bobert.netneutrality.thread.ShutdownThread; +import me.bobert.netneutrality.thread.ThreadManager; +import me.bobert.netneutrality.utils.Settings; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -35,8 +35,7 @@ public class NetNeutrality { private static JDA jda; public final static Logger logger = LogManager.getLogger(NetNeutrality.class); - - public static final String VERSION = "2.0.0"; + public static final String VERSION = Settings.getInstance().getMavenVersion(); public static void main(String[] args) { String env = Settings.getInstance().get("NETNEUTRALITY_BOT_ENV", "dev"); diff --git a/src/main/java/netneutrality/command/AbstractCommand.java b/src/main/java/me/bobert/netneutrality/command/AbstractCommand.java similarity index 90% rename from src/main/java/netneutrality/command/AbstractCommand.java rename to src/main/java/me/bobert/netneutrality/command/AbstractCommand.java index c098e8d..f02d43b 100644 --- a/src/main/java/netneutrality/command/AbstractCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/AbstractCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command; +package me.bobert.netneutrality.command; /* * Copyright (c) anthorob @@ -6,11 +6,11 @@ package netneutrality.command; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.context.MessageCommandContext; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; -import netneutrality.core.context.MessageCommandContext; public abstract class AbstractCommand implements ICommand { diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/me/bobert/netneutrality/command/AbstractMusicCommand.java similarity index 90% rename from src/main/java/netneutrality/command/AbstractMusicCommand.java rename to src/main/java/me/bobert/netneutrality/command/AbstractMusicCommand.java index 36d95b1..c59f7a3 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/AbstractMusicCommand.java @@ -1,18 +1,18 @@ -package netneutrality.command; +package me.bobert.netneutrality.command; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.db.GSettings; +import me.bobert.netneutrality.utils.UserFunction; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.channel.ChannelType; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.core.GuildManager; -import netneutrality.db.GSettings; -import netneutrality.utils.UserFunction; public abstract class AbstractMusicCommand extends AbstractCommand { diff --git a/src/main/java/netneutrality/command/CommandExecutionResult.java b/src/main/java/me/bobert/netneutrality/command/CommandExecutionResult.java similarity index 97% rename from src/main/java/netneutrality/command/CommandExecutionResult.java rename to src/main/java/me/bobert/netneutrality/command/CommandExecutionResult.java index fd51e64..45a2f4a 100644 --- a/src/main/java/netneutrality/command/CommandExecutionResult.java +++ b/src/main/java/me/bobert/netneutrality/command/CommandExecutionResult.java @@ -1,4 +1,4 @@ -package netneutrality.command; +package me.bobert.netneutrality.command; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/command/CommandManager.java b/src/main/java/me/bobert/netneutrality/command/CommandManager.java similarity index 95% rename from src/main/java/netneutrality/command/CommandManager.java rename to src/main/java/me/bobert/netneutrality/command/CommandManager.java index 1f9cd28..540a084 100644 --- a/src/main/java/netneutrality/command/CommandManager.java +++ b/src/main/java/me/bobert/netneutrality/command/CommandManager.java @@ -1,16 +1,16 @@ -package netneutrality.command; +package me.bobert.netneutrality.command; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.NetNeutrality; +import me.bobert.netneutrality.core.LogHandler; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; -import netneutrality.NetNeutrality; -import netneutrality.core.LogHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.reflections.Reflections; diff --git a/src/main/java/netneutrality/command/CommandType.java b/src/main/java/me/bobert/netneutrality/command/CommandType.java similarity index 92% rename from src/main/java/netneutrality/command/CommandType.java rename to src/main/java/me/bobert/netneutrality/command/CommandType.java index 84ecc69..340993e 100644 --- a/src/main/java/netneutrality/command/CommandType.java +++ b/src/main/java/me/bobert/netneutrality/command/CommandType.java @@ -1,4 +1,4 @@ -package netneutrality.command; +package me.bobert.netneutrality.command; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/command/ICommand.java b/src/main/java/me/bobert/netneutrality/command/ICommand.java similarity index 85% rename from src/main/java/netneutrality/command/ICommand.java rename to src/main/java/me/bobert/netneutrality/command/ICommand.java index c7af286..6d290b3 100644 --- a/src/main/java/netneutrality/command/ICommand.java +++ b/src/main/java/me/bobert/netneutrality/command/ICommand.java @@ -1,17 +1,17 @@ -package netneutrality.command; +package me.bobert.netneutrality.command; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; public interface ICommand { diff --git a/src/main/java/netneutrality/command/admin/BlacklistCommand.java b/src/main/java/me/bobert/netneutrality/command/admin/BlacklistCommand.java similarity index 86% rename from src/main/java/netneutrality/command/admin/BlacklistCommand.java rename to src/main/java/me/bobert/netneutrality/command/admin/BlacklistCommand.java index b50f31f..9267025 100644 --- a/src/main/java/netneutrality/command/admin/BlacklistCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/admin/BlacklistCommand.java @@ -1,24 +1,24 @@ -package netneutrality.command.admin; +package me.bobert.netneutrality.command.admin; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.db.DBController; +import me.bobert.netneutrality.db.controllers.DBBlacklist; +import me.bobert.netneutrality.db.entities.OBlacklist; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandType; -import netneutrality.core.LogHandler; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBBlacklist; -import netneutrality.db.entities.OBlacklist; import java.util.ArrayList; diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java similarity index 81% rename from src/main/java/netneutrality/command/basic/HelpCommand.java rename to src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java index 0648a7d..840ab45 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java @@ -1,19 +1,19 @@ -package netneutrality.command.basic; +package me.bobert.netneutrality.command.basic; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandType; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.utils.MessageFunction; import java.util.List; diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/me/bobert/netneutrality/command/basic/PingCommand.java similarity index 78% rename from src/main/java/netneutrality/command/basic/PingCommand.java rename to src/main/java/me/bobert/netneutrality/command/basic/PingCommand.java index 02c987d..e287444 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/basic/PingCommand.java @@ -1,16 +1,16 @@ -package netneutrality.command.basic; +package me.bobert.netneutrality.command.basic; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandType; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; public class PingCommand extends AbstractCommand { diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/me/bobert/netneutrality/command/bot/ConfigureCommand.java similarity index 96% rename from src/main/java/netneutrality/command/bot/ConfigureCommand.java rename to src/main/java/me/bobert/netneutrality/command/bot/ConfigureCommand.java index 4b33096..a74d50d 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/bot/ConfigureCommand.java @@ -1,10 +1,18 @@ -package netneutrality.command.bot; +package me.bobert.netneutrality.command.bot; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.db.GSettings; +import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; @@ -15,14 +23,6 @@ import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandType; -import netneutrality.core.GuildManager; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.db.GSettings; -import netneutrality.music.MusicManager; import java.util.List; import java.util.Map; diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/me/bobert/netneutrality/command/crypto/CryptoPriceCommand.java similarity index 92% rename from src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java rename to src/main/java/me/bobert/netneutrality/command/crypto/CryptoPriceCommand.java index 14ec58d..597492c 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/crypto/CryptoPriceCommand.java @@ -1,20 +1,20 @@ -package netneutrality.command.crypto; +package me.bobert.netneutrality.command.crypto; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.http.WebModule; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandType; -import netneutrality.core.LogHandler; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; diff --git a/src/main/java/netneutrality/command/custom/.gitignore b/src/main/java/me/bobert/netneutrality/command/custom/.gitignore similarity index 100% rename from src/main/java/netneutrality/command/custom/.gitignore rename to src/main/java/me/bobert/netneutrality/command/custom/.gitignore diff --git a/src/main/java/netneutrality/command/music/BitconnectCommand.java b/src/main/java/me/bobert/netneutrality/command/music/BitconnectCommand.java similarity index 76% rename from src/main/java/netneutrality/command/music/BitconnectCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/BitconnectCommand.java index e607263..5e5947b 100644 --- a/src/main/java/netneutrality/command/music/BitconnectCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/BitconnectCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,13 +6,13 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandType; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; public class BitconnectCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/ClearQueueCommand.java b/src/main/java/me/bobert/netneutrality/command/music/ClearQueueCommand.java similarity index 84% rename from src/main/java/netneutrality/command/music/ClearQueueCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/ClearQueueCommand.java index da32cdd..30f06a6 100644 --- a/src/main/java/netneutrality/command/music/ClearQueueCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/ClearQueueCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,14 +6,14 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MessageFunction; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MessageFunction; -import netneutrality.utils.MusicUtils; public class ClearQueueCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java b/src/main/java/me/bobert/netneutrality/command/music/CurrentlyPlayingCommand.java similarity index 76% rename from src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/CurrentlyPlayingCommand.java index 34d24d7..9c432c0 100644 --- a/src/main/java/netneutrality/command/music/CurrentlyPlayingCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/CurrentlyPlayingCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,14 +6,14 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MessageFunction; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MessageFunction; -import netneutrality.utils.MusicUtils; public class CurrentlyPlayingCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/me/bobert/netneutrality/command/music/JoinCommand.java similarity index 85% rename from src/main/java/netneutrality/command/music/JoinCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/JoinCommand.java index c359e0f..85c4d78 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/JoinCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,14 +6,14 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.exceptions.CommandExecutionException; +import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.exceptions.CommandExecutionException; -import netneutrality.music.MusicManager; public class JoinCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/me/bobert/netneutrality/command/music/LeaveCommand.java similarity index 77% rename from src/main/java/netneutrality/command/music/LeaveCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/LeaveCommand.java index 6a6a318..806d5a7 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/LeaveCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,13 +6,13 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; public class LeaveCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/me/bobert/netneutrality/command/music/PlayCommand.java similarity index 80% rename from src/main/java/netneutrality/command/music/PlayCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/PlayCommand.java index 39cf5e8..5f3da37 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/PlayCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,14 +6,14 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; public class PlayCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/QueueCommand.java b/src/main/java/me/bobert/netneutrality/command/music/QueueCommand.java similarity index 92% rename from src/main/java/netneutrality/command/music/QueueCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/QueueCommand.java index 32e5153..1d7075f 100644 --- a/src/main/java/netneutrality/command/music/QueueCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/QueueCommand.java @@ -1,10 +1,17 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MessageFunction; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionMapping; @@ -12,13 +19,6 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MessageFunction; -import netneutrality.utils.MusicUtils; public class QueueCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/ShuffleCommand.java b/src/main/java/me/bobert/netneutrality/command/music/ShuffleCommand.java similarity index 73% rename from src/main/java/netneutrality/command/music/ShuffleCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/ShuffleCommand.java index 22c3623..e4ea2c2 100644 --- a/src/main/java/netneutrality/command/music/ShuffleCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/ShuffleCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,12 +6,12 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; public class ShuffleCommand extends AbstractMusicCommand { @Override diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/me/bobert/netneutrality/command/music/SkipCommand.java similarity index 84% rename from src/main/java/netneutrality/command/music/SkipCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/SkipCommand.java index 6133ae4..7db97f4 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/SkipCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,17 +6,17 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MusicUtils; +import me.bobert.netneutrality.utils.UserFunction; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; -import netneutrality.utils.UserFunction; public class SkipCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/me/bobert/netneutrality/command/music/StopCommand.java similarity index 76% rename from src/main/java/netneutrality/command/music/StopCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/StopCommand.java index 49c5928..48e772d 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/StopCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,14 +6,14 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MusicUtils; +import me.bobert.netneutrality.utils.UserFunction; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; -import netneutrality.utils.UserFunction; public class StopCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/me/bobert/netneutrality/command/music/ViewQueueCommand.java similarity index 78% rename from src/main/java/netneutrality/command/music/ViewQueueCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/ViewQueueCommand.java index d2c2ace..84808dc 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/ViewQueueCommand.java @@ -1,18 +1,18 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MessageFunction; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MessageFunction; -import netneutrality.utils.MusicUtils; public class ViewQueueCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/me/bobert/netneutrality/command/music/VolumeCommand.java similarity index 83% rename from src/main/java/netneutrality/command/music/VolumeCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/VolumeCommand.java index ec69272..1a7178c 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/VolumeCommand.java @@ -1,4 +1,4 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob @@ -6,17 +6,17 @@ package netneutrality.command.music; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MusicUtils; +import me.bobert.netneutrality.utils.UserFunction; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; -import netneutrality.utils.UserFunction; public class VolumeCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/me/bobert/netneutrality/command/music/VoteSkipCommand.java similarity index 75% rename from src/main/java/netneutrality/command/music/VoteSkipCommand.java rename to src/main/java/me/bobert/netneutrality/command/music/VoteSkipCommand.java index f07c358..ce84c07 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/music/VoteSkipCommand.java @@ -1,17 +1,17 @@ -package netneutrality.command.music; +package me.bobert.netneutrality.command.music; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractMusicCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import netneutrality.command.AbstractMusicCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.music.MusicManager; -import netneutrality.utils.MusicUtils; public class VoteSkipCommand extends AbstractMusicCommand { diff --git a/src/main/java/netneutrality/core/BotState.java b/src/main/java/me/bobert/netneutrality/core/BotState.java similarity index 92% rename from src/main/java/netneutrality/core/BotState.java rename to src/main/java/me/bobert/netneutrality/core/BotState.java index f2023c1..db78b80 100644 --- a/src/main/java/netneutrality/core/BotState.java +++ b/src/main/java/me/bobert/netneutrality/core/BotState.java @@ -1,13 +1,13 @@ -package netneutrality.core; +package me.bobert.netneutrality.core; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.music.TrackScheduler; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.music.MusicManager; -import netneutrality.music.TrackScheduler; import org.json.JSONArray; import org.json.JSONObject; diff --git a/src/main/java/netneutrality/core/CommandProcessor.java b/src/main/java/me/bobert/netneutrality/core/CommandProcessor.java similarity index 84% rename from src/main/java/netneutrality/core/CommandProcessor.java rename to src/main/java/me/bobert/netneutrality/core/CommandProcessor.java index 0c31320..e76021a 100644 --- a/src/main/java/netneutrality/core/CommandProcessor.java +++ b/src/main/java/me/bobert/netneutrality/core/CommandProcessor.java @@ -1,4 +1,4 @@ -package netneutrality.core; +package me.bobert.netneutrality.core; /* * Copyright (c) anthorob * @@ -6,18 +6,19 @@ package netneutrality.core; */ import io.sentry.Sentry; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandExecutionResult; -import netneutrality.command.CommandManager; -import netneutrality.core.context.CommandContext; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.exceptions.CommandExecutionException; -import netneutrality.utils.UserFunction; +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.command.CommandManager; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.exceptions.CommandExecutionException; +import me.bobert.netneutrality.utils.UserFunction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import static netneutrality.command.CommandExecutionResult.Result.*; +import static me.bobert.netneutrality.command.CommandExecutionResult.Result.ERROR; +import static me.bobert.netneutrality.command.CommandExecutionResult.Result.NOACTION; public class CommandProcessor { diff --git a/src/main/java/netneutrality/core/GuildConfigManager.java b/src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java similarity index 91% rename from src/main/java/netneutrality/core/GuildConfigManager.java rename to src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java index 4d23ff3..d494b32 100644 --- a/src/main/java/netneutrality/core/GuildConfigManager.java +++ b/src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java @@ -1,4 +1,4 @@ -package netneutrality.core; +package me.bobert.netneutrality.core; /* * Copyright (c) anthorob @@ -6,11 +6,11 @@ package netneutrality.core; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.db.GSettings; +import me.bobert.netneutrality.db.entities.OGuild; +import me.bobert.netneutrality.db.entities.OGuildSetting; +import me.bobert.netneutrality.utils.JpaUtils; import net.dv8tion.jda.api.entities.Guild; -import netneutrality.db.GSettings; -import netneutrality.db.entities.OGuild; -import netneutrality.db.entities.OGuildSetting; -import netneutrality.utils.JpaUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.hibernate.Session; diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/me/bobert/netneutrality/core/GuildManager.java similarity index 92% rename from src/main/java/netneutrality/core/GuildManager.java rename to src/main/java/me/bobert/netneutrality/core/GuildManager.java index 22332ab..26aa6bf 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/me/bobert/netneutrality/core/GuildManager.java @@ -1,22 +1,22 @@ -package netneutrality.core; +package me.bobert.netneutrality.core; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.NetNeutrality; +import me.bobert.netneutrality.db.DBController; +import me.bobert.netneutrality.db.controllers.DBMessage; +import me.bobert.netneutrality.db.entities.OBlacklist; +import me.bobert.netneutrality.db.entities.OGuild; +import me.bobert.netneutrality.thread.ThreadManager; +import me.bobert.netneutrality.utils.JpaUtils; +import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.NetNeutrality; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBMessage; -import netneutrality.db.entities.OBlacklist; -import netneutrality.db.entities.OGuild; -import netneutrality.thread.ThreadManager; -import netneutrality.utils.JpaUtils; -import netneutrality.utils.MessageFunction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.hibernate.Session; diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/me/bobert/netneutrality/core/LogHandler.java similarity index 89% rename from src/main/java/netneutrality/core/LogHandler.java rename to src/main/java/me/bobert/netneutrality/core/LogHandler.java index e0cdc4b..c8b7fcc 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/me/bobert/netneutrality/core/LogHandler.java @@ -1,4 +1,4 @@ -package netneutrality.core; +package me.bobert.netneutrality.core; /* * Copyright (c) anthorob * @@ -6,13 +6,13 @@ package netneutrality.core; */ import io.sentry.Sentry; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.context.SlashCommandContext; +import me.bobert.netneutrality.exceptions.CommandException; +import me.bobert.netneutrality.exceptions.CommandExecutionException; +import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import netneutrality.core.context.CommandContext; -import netneutrality.core.context.SlashCommandContext; -import netneutrality.exceptions.CommandException; -import netneutrality.exceptions.CommandExecutionException; -import netneutrality.utils.MessageFunction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/me/bobert/netneutrality/core/SessionManager.java similarity index 96% rename from src/main/java/netneutrality/core/SessionManager.java rename to src/main/java/me/bobert/netneutrality/core/SessionManager.java index 5d398c8..e79cf8e 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/me/bobert/netneutrality/core/SessionManager.java @@ -1,4 +1,4 @@ -package netneutrality.core; +package me.bobert.netneutrality.core; /* * Copyright (c) anthorob * @@ -6,7 +6,7 @@ package netneutrality.core; */ import io.sentry.Sentry; -import netneutrality.utils.Settings; +import me.bobert.netneutrality.utils.Settings; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.hibernate.SessionFactory; diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/me/bobert/netneutrality/core/context/CommandContext.java similarity index 92% rename from src/main/java/netneutrality/core/context/CommandContext.java rename to src/main/java/me/bobert/netneutrality/core/context/CommandContext.java index c812826..74d7abb 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/me/bobert/netneutrality/core/context/CommandContext.java @@ -1,4 +1,4 @@ -package netneutrality.core.context; +package me.bobert.netneutrality.core.context; /* * Copyright (c) anthorob @@ -6,6 +6,7 @@ package netneutrality.core.context; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -14,7 +15,6 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.Event; import net.dv8tion.jda.api.utils.messages.MessageCreateData; -import netneutrality.command.AbstractCommand; public interface CommandContext { diff --git a/src/main/java/netneutrality/core/context/MessageCommandContext.java b/src/main/java/me/bobert/netneutrality/core/context/MessageCommandContext.java similarity index 95% rename from src/main/java/netneutrality/core/context/MessageCommandContext.java rename to src/main/java/me/bobert/netneutrality/core/context/MessageCommandContext.java index 52484fe..9ef63af 100644 --- a/src/main/java/netneutrality/core/context/MessageCommandContext.java +++ b/src/main/java/me/bobert/netneutrality/core/context/MessageCommandContext.java @@ -1,4 +1,4 @@ -package netneutrality.core.context; +package me.bobert.netneutrality.core.context; /* * Copyright (c) anthorob * @@ -7,15 +7,15 @@ package netneutrality.core.context; import io.sentry.Breadcrumb; import io.sentry.Sentry; +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.thread.ThreadManager; +import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.utils.messages.MessageCreateData; -import netneutrality.command.AbstractCommand; -import netneutrality.core.GuildManager; -import netneutrality.thread.ThreadManager; -import netneutrality.utils.Settings; import java.util.Collection; import java.util.concurrent.ExecutorService; diff --git a/src/main/java/netneutrality/core/context/SlashCommandContext.java b/src/main/java/me/bobert/netneutrality/core/context/SlashCommandContext.java similarity index 98% rename from src/main/java/netneutrality/core/context/SlashCommandContext.java rename to src/main/java/me/bobert/netneutrality/core/context/SlashCommandContext.java index e46a880..35064c1 100644 --- a/src/main/java/netneutrality/core/context/SlashCommandContext.java +++ b/src/main/java/me/bobert/netneutrality/core/context/SlashCommandContext.java @@ -1,10 +1,11 @@ -package netneutrality.core.context; +package me.bobert.netneutrality.core.context; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.command.AbstractCommand; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -16,7 +17,6 @@ import net.dv8tion.jda.api.interactions.InteractionHook; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import net.dv8tion.jda.api.utils.messages.MessageEditData; -import netneutrality.command.AbstractCommand; import java.util.Collection; diff --git a/src/main/java/netneutrality/db/AbstractController.java b/src/main/java/me/bobert/netneutrality/db/AbstractController.java similarity index 80% rename from src/main/java/netneutrality/db/AbstractController.java rename to src/main/java/me/bobert/netneutrality/db/AbstractController.java index 40f68a4..6fad802 100644 --- a/src/main/java/netneutrality/db/AbstractController.java +++ b/src/main/java/me/bobert/netneutrality/db/AbstractController.java @@ -1,4 +1,4 @@ -package netneutrality.db; +package me.bobert.netneutrality.db; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.db; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.core.SessionManager; +import me.bobert.netneutrality.core.SessionManager; import org.hibernate.SessionFactory; public abstract class AbstractController { diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/me/bobert/netneutrality/db/DBController.java similarity index 90% rename from src/main/java/netneutrality/db/DBController.java rename to src/main/java/me/bobert/netneutrality/db/DBController.java index d6e0ab4..aab0723 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/me/bobert/netneutrality/db/DBController.java @@ -1,4 +1,4 @@ -package netneutrality.db; +package me.bobert.netneutrality.db; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.db; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.core.SessionManager; +import me.bobert.netneutrality.core.SessionManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/db/GSettings.java b/src/main/java/me/bobert/netneutrality/db/GSettings.java similarity index 93% rename from src/main/java/netneutrality/db/GSettings.java rename to src/main/java/me/bobert/netneutrality/db/GSettings.java index 1a7edfe..5945ff5 100644 --- a/src/main/java/netneutrality/db/GSettings.java +++ b/src/main/java/me/bobert/netneutrality/db/GSettings.java @@ -1,4 +1,4 @@ -package netneutrality.db; +package me.bobert.netneutrality.db; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java similarity index 92% rename from src/main/java/netneutrality/db/controllers/DBBlacklist.java rename to src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java index de4ba04..8f213fc 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java @@ -1,17 +1,17 @@ -package netneutrality.db.controllers; +package me.bobert.netneutrality.db.controllers; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.db.AbstractController; +import me.bobert.netneutrality.db.entities.OBlacklist; +import me.bobert.netneutrality.db.entities.OGuild; +import me.bobert.netneutrality.utils.JpaUtils; import net.dv8tion.jda.api.entities.Guild; -import netneutrality.core.GuildManager; -import netneutrality.core.context.CommandContext; -import netneutrality.db.AbstractController; -import netneutrality.db.entities.OBlacklist; -import netneutrality.db.entities.OGuild; -import netneutrality.utils.JpaUtils; import org.hibernate.Session; import org.hibernate.query.Query; diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java similarity index 93% rename from src/main/java/netneutrality/db/controllers/DBMessage.java rename to src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java index 85e02ea..50d8c21 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java @@ -1,16 +1,16 @@ -package netneutrality.db.controllers; +package me.bobert.netneutrality.db.controllers; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.db.AbstractController; +import me.bobert.netneutrality.db.entities.OLogMessage; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.core.GuildManager; -import netneutrality.db.AbstractController; -import netneutrality.db.entities.OLogMessage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.hibernate.Session; diff --git a/src/main/java/netneutrality/db/entities/OBlacklist.java b/src/main/java/me/bobert/netneutrality/db/entities/OBlacklist.java similarity index 97% rename from src/main/java/netneutrality/db/entities/OBlacklist.java rename to src/main/java/me/bobert/netneutrality/db/entities/OBlacklist.java index 477f3fa..5db94c6 100644 --- a/src/main/java/netneutrality/db/entities/OBlacklist.java +++ b/src/main/java/me/bobert/netneutrality/db/entities/OBlacklist.java @@ -1,4 +1,4 @@ -package netneutrality.db.entities; +package me.bobert.netneutrality.db.entities; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/db/entities/OGuild.java b/src/main/java/me/bobert/netneutrality/db/entities/OGuild.java similarity index 98% rename from src/main/java/netneutrality/db/entities/OGuild.java rename to src/main/java/me/bobert/netneutrality/db/entities/OGuild.java index 1ca2f9e..021b560 100644 --- a/src/main/java/netneutrality/db/entities/OGuild.java +++ b/src/main/java/me/bobert/netneutrality/db/entities/OGuild.java @@ -1,4 +1,4 @@ -package netneutrality.db.entities; +package me.bobert.netneutrality.db.entities; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/db/entities/OGuildSetting.java b/src/main/java/me/bobert/netneutrality/db/entities/OGuildSetting.java similarity index 96% rename from src/main/java/netneutrality/db/entities/OGuildSetting.java rename to src/main/java/me/bobert/netneutrality/db/entities/OGuildSetting.java index 00a9d39..a868311 100644 --- a/src/main/java/netneutrality/db/entities/OGuildSetting.java +++ b/src/main/java/me/bobert/netneutrality/db/entities/OGuildSetting.java @@ -1,4 +1,4 @@ -package netneutrality.db.entities; +package me.bobert.netneutrality.db.entities; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/db/entities/OLogMessage.java b/src/main/java/me/bobert/netneutrality/db/entities/OLogMessage.java similarity index 98% rename from src/main/java/netneutrality/db/entities/OLogMessage.java rename to src/main/java/me/bobert/netneutrality/db/entities/OLogMessage.java index 40cb4db..e8b8a82 100644 --- a/src/main/java/netneutrality/db/entities/OLogMessage.java +++ b/src/main/java/me/bobert/netneutrality/db/entities/OLogMessage.java @@ -1,4 +1,4 @@ -package netneutrality.db.entities; +package me.bobert.netneutrality.db.entities; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/db/entities/OLogging.java b/src/main/java/me/bobert/netneutrality/db/entities/OLogging.java similarity index 95% rename from src/main/java/netneutrality/db/entities/OLogging.java rename to src/main/java/me/bobert/netneutrality/db/entities/OLogging.java index ede819c..7dd2992 100644 --- a/src/main/java/netneutrality/db/entities/OLogging.java +++ b/src/main/java/me/bobert/netneutrality/db/entities/OLogging.java @@ -1,4 +1,4 @@ -package netneutrality.db.entities; +package me.bobert.netneutrality.db.entities; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/db/entities/OLoggingId.java b/src/main/java/me/bobert/netneutrality/db/entities/OLoggingId.java similarity index 96% rename from src/main/java/netneutrality/db/entities/OLoggingId.java rename to src/main/java/me/bobert/netneutrality/db/entities/OLoggingId.java index e551bb5..9cf3671 100644 --- a/src/main/java/netneutrality/db/entities/OLoggingId.java +++ b/src/main/java/me/bobert/netneutrality/db/entities/OLoggingId.java @@ -1,4 +1,4 @@ -package netneutrality.db.entities; +package me.bobert.netneutrality.db.entities; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/exceptions/CommandException.java b/src/main/java/me/bobert/netneutrality/exceptions/CommandException.java similarity index 84% rename from src/main/java/netneutrality/exceptions/CommandException.java rename to src/main/java/me/bobert/netneutrality/exceptions/CommandException.java index b87eff2..c006425 100644 --- a/src/main/java/netneutrality/exceptions/CommandException.java +++ b/src/main/java/me/bobert/netneutrality/exceptions/CommandException.java @@ -1,4 +1,4 @@ -package netneutrality.exceptions; +package me.bobert.netneutrality.exceptions; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.exceptions; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.context.CommandContext; public abstract class CommandException extends RuntimeException { diff --git a/src/main/java/netneutrality/exceptions/CommandExecutionException.java b/src/main/java/me/bobert/netneutrality/exceptions/CommandExecutionException.java similarity index 81% rename from src/main/java/netneutrality/exceptions/CommandExecutionException.java rename to src/main/java/me/bobert/netneutrality/exceptions/CommandExecutionException.java index c04cf31..0639059 100644 --- a/src/main/java/netneutrality/exceptions/CommandExecutionException.java +++ b/src/main/java/me/bobert/netneutrality/exceptions/CommandExecutionException.java @@ -1,4 +1,4 @@ -package netneutrality.exceptions; +package me.bobert.netneutrality.exceptions; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.exceptions; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.context.CommandContext; /** * Logs the error internally, without sending a message diff --git a/src/main/java/netneutrality/exceptions/ExecutorException.java b/src/main/java/me/bobert/netneutrality/exceptions/ExecutorException.java similarity index 74% rename from src/main/java/netneutrality/exceptions/ExecutorException.java rename to src/main/java/me/bobert/netneutrality/exceptions/ExecutorException.java index 0aa97c5..2704a27 100644 --- a/src/main/java/netneutrality/exceptions/ExecutorException.java +++ b/src/main/java/me/bobert/netneutrality/exceptions/ExecutorException.java @@ -1,4 +1,4 @@ -package netneutrality.exceptions; +package me.bobert.netneutrality.exceptions; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.exceptions; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.LogHandler; public class ExecutorException implements Thread.UncaughtExceptionHandler { diff --git a/src/main/java/netneutrality/hooks/SlashCommandHooks.java b/src/main/java/me/bobert/netneutrality/hooks/SlashCommandHooks.java similarity index 80% rename from src/main/java/netneutrality/hooks/SlashCommandHooks.java rename to src/main/java/me/bobert/netneutrality/hooks/SlashCommandHooks.java index 6e5d99b..1cf33e0 100644 --- a/src/main/java/netneutrality/hooks/SlashCommandHooks.java +++ b/src/main/java/me/bobert/netneutrality/hooks/SlashCommandHooks.java @@ -1,14 +1,14 @@ -package netneutrality.hooks; +package me.bobert.netneutrality.hooks; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.CommandProcessor; +import me.bobert.netneutrality.core.context.SlashCommandContext; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.core.CommandProcessor; -import netneutrality.core.context.SlashCommandContext; import org.jetbrains.annotations.NotNull; public class SlashCommandHooks extends ListenerAdapter { diff --git a/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java b/src/main/java/me/bobert/netneutrality/hooks/guilds/ServerJoinHandler.java similarity index 86% rename from src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java rename to src/main/java/me/bobert/netneutrality/hooks/guilds/ServerJoinHandler.java index cb33ea2..ebdb410 100644 --- a/src/main/java/netneutrality/hooks/guilds/ServerJoinHandler.java +++ b/src/main/java/me/bobert/netneutrality/hooks/guilds/ServerJoinHandler.java @@ -1,4 +1,4 @@ -package netneutrality.hooks.guilds; +package me.bobert.netneutrality.hooks.guilds; /* * Copyright (c) anthorob @@ -6,10 +6,10 @@ package netneutrality.hooks.guilds; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.GuildManager; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.core.GuildManager; import org.jetbrains.annotations.NotNull; public class ServerJoinHandler extends ListenerAdapter { diff --git a/src/main/java/netneutrality/hooks/message/EditHandler.java b/src/main/java/me/bobert/netneutrality/hooks/message/EditHandler.java similarity index 82% rename from src/main/java/netneutrality/hooks/message/EditHandler.java rename to src/main/java/me/bobert/netneutrality/hooks/message/EditHandler.java index cf03953..3fab697 100644 --- a/src/main/java/netneutrality/hooks/message/EditHandler.java +++ b/src/main/java/me/bobert/netneutrality/hooks/message/EditHandler.java @@ -1,4 +1,4 @@ -package netneutrality.hooks.message; +package me.bobert.netneutrality.hooks.message; /* * Copyright (c) anthorob @@ -6,16 +6,16 @@ package netneutrality.hooks.message; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.core.SessionManager; +import me.bobert.netneutrality.db.DBController; +import me.bobert.netneutrality.db.controllers.DBMessage; +import me.bobert.netneutrality.db.entities.OGuild; +import me.bobert.netneutrality.utils.JpaUtils; +import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.core.GuildManager; -import netneutrality.core.SessionManager; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBMessage; -import netneutrality.db.entities.OGuild; -import netneutrality.utils.JpaUtils; -import netneutrality.utils.MessageFunction; import org.hibernate.Session; import java.util.stream.Collectors; diff --git a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java similarity index 83% rename from src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java rename to src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java index 6f19d32..c143659 100644 --- a/src/main/java/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java @@ -1,19 +1,17 @@ -package netneutrality.hooks.message; +package me.bobert.netneutrality.hooks.message; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ -import io.sentry.Breadcrumb; -import io.sentry.Sentry; +import me.bobert.netneutrality.core.CommandProcessor; +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.core.context.MessageCommandContext; +import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import netneutrality.core.CommandProcessor; -import netneutrality.core.GuildManager; -import netneutrality.core.context.MessageCommandContext; -import netneutrality.utils.Settings; import org.jetbrains.annotations.NotNull; public class MessageReceivedHandler extends ListenerAdapter { diff --git a/src/main/java/netneutrality/hooks/message/ReactionHandler.java b/src/main/java/me/bobert/netneutrality/hooks/message/ReactionHandler.java similarity index 94% rename from src/main/java/netneutrality/hooks/message/ReactionHandler.java rename to src/main/java/me/bobert/netneutrality/hooks/message/ReactionHandler.java index 994214d..bcbae8c 100644 --- a/src/main/java/netneutrality/hooks/message/ReactionHandler.java +++ b/src/main/java/me/bobert/netneutrality/hooks/message/ReactionHandler.java @@ -1,4 +1,4 @@ -package netneutrality.hooks.message; +package me.bobert.netneutrality.hooks.message; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java b/src/main/java/me/bobert/netneutrality/hooks/voice/VoiceEventHandler.java similarity index 90% rename from src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java rename to src/main/java/me/bobert/netneutrality/hooks/voice/VoiceEventHandler.java index 2b983c8..00543ca 100644 --- a/src/main/java/netneutrality/hooks/voice/VoiceEventHandler.java +++ b/src/main/java/me/bobert/netneutrality/hooks/voice/VoiceEventHandler.java @@ -1,4 +1,4 @@ -package netneutrality.hooks.voice; +package me.bobert.netneutrality.hooks.voice; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/http/WebModule.java b/src/main/java/me/bobert/netneutrality/http/WebModule.java similarity index 97% rename from src/main/java/netneutrality/http/WebModule.java rename to src/main/java/me/bobert/netneutrality/http/WebModule.java index ab9d508..2eb19d4 100644 --- a/src/main/java/netneutrality/http/WebModule.java +++ b/src/main/java/me/bobert/netneutrality/http/WebModule.java @@ -1,4 +1,4 @@ -package netneutrality.http; +package me.bobert.netneutrality.http; /* * Copyright (c) anthorob @@ -8,11 +8,10 @@ package netneutrality.http; import io.sentry.Breadcrumb; import io.sentry.Sentry; -import netneutrality.NetNeutrality; -import netneutrality.core.LogHandler; +import me.bobert.netneutrality.NetNeutrality; +import me.bobert.netneutrality.core.LogHandler; import okhttp3.*; import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; diff --git a/src/main/java/netneutrality/http/server/AbstractHandler.java b/src/main/java/me/bobert/netneutrality/http/server/AbstractHandler.java similarity index 95% rename from src/main/java/netneutrality/http/server/AbstractHandler.java rename to src/main/java/me/bobert/netneutrality/http/server/AbstractHandler.java index 4b54c69..21f9300 100644 --- a/src/main/java/netneutrality/http/server/AbstractHandler.java +++ b/src/main/java/me/bobert/netneutrality/http/server/AbstractHandler.java @@ -1,4 +1,4 @@ -package netneutrality.http.server; +package me.bobert.netneutrality.http.server; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/me/bobert/netneutrality/http/server/ActionHandler.java similarity index 93% rename from src/main/java/netneutrality/http/server/ActionHandler.java rename to src/main/java/me/bobert/netneutrality/http/server/ActionHandler.java index cc8a9af..a2b8f65 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/me/bobert/netneutrality/http/server/ActionHandler.java @@ -1,4 +1,4 @@ -package netneutrality.http.server; +package me.bobert.netneutrality.http.server; /* * Copyright (c) anthorob @@ -7,10 +7,10 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpExchange; +import me.bobert.netneutrality.NetNeutrality; +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.http.WebModule; import net.dv8tion.jda.api.entities.Guild; -import netneutrality.NetNeutrality; -import netneutrality.core.GuildManager; -import netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; import org.json.JSONObject; diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/me/bobert/netneutrality/http/server/GuildHandler.java similarity index 96% rename from src/main/java/netneutrality/http/server/GuildHandler.java rename to src/main/java/me/bobert/netneutrality/http/server/GuildHandler.java index 567e41c..26016b8 100644 --- a/src/main/java/netneutrality/http/server/GuildHandler.java +++ b/src/main/java/me/bobert/netneutrality/http/server/GuildHandler.java @@ -1,4 +1,4 @@ -package netneutrality.http.server; +package me.bobert.netneutrality.http.server; /* * Copyright (c) anthorob @@ -7,8 +7,8 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpExchange; +import me.bobert.netneutrality.NetNeutrality; import net.dv8tion.jda.api.JDA; -import netneutrality.NetNeutrality; import org.json.JSONArray; import org.json.JSONObject; diff --git a/src/main/java/netneutrality/http/server/RootHandler.java b/src/main/java/me/bobert/netneutrality/http/server/RootHandler.java similarity index 90% rename from src/main/java/netneutrality/http/server/RootHandler.java rename to src/main/java/me/bobert/netneutrality/http/server/RootHandler.java index 4a133c1..6d8a8d1 100644 --- a/src/main/java/netneutrality/http/server/RootHandler.java +++ b/src/main/java/me/bobert/netneutrality/http/server/RootHandler.java @@ -1,4 +1,4 @@ -package netneutrality.http.server; +package me.bobert.netneutrality.http.server; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/me/bobert/netneutrality/http/server/WebApi.java similarity index 92% rename from src/main/java/netneutrality/http/server/WebApi.java rename to src/main/java/me/bobert/netneutrality/http/server/WebApi.java index e3251f2..7828fce 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/me/bobert/netneutrality/http/server/WebApi.java @@ -1,4 +1,4 @@ -package netneutrality.http.server; +package me.bobert.netneutrality.http.server; /* * Copyright (c) anthorob @@ -7,7 +7,7 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpServer; -import netneutrality.thread.BaseThreadFactory; +import me.bobert.netneutrality.thread.BaseThreadFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/me/bobert/netneutrality/music/AudioPlayerSendHandler.java similarity index 96% rename from src/main/java/netneutrality/music/AudioPlayerSendHandler.java rename to src/main/java/me/bobert/netneutrality/music/AudioPlayerSendHandler.java index 2b4f108..9307f62 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/me/bobert/netneutrality/music/AudioPlayerSendHandler.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/me/bobert/netneutrality/music/MusicManager.java similarity index 93% rename from src/main/java/netneutrality/music/MusicManager.java rename to src/main/java/me/bobert/netneutrality/music/MusicManager.java index d096bc7..f32fd1a 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/me/bobert/netneutrality/music/MusicManager.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob @@ -13,20 +13,20 @@ import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import dev.lavalink.youtube.YoutubeAudioSourceManager; +import me.bobert.netneutrality.command.CommandExecutionResult; +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.db.GSettings; +import me.bobert.netneutrality.exceptions.CommandExecutionException; +import me.bobert.netneutrality.music.loadable.LoadableSong; +import me.bobert.netneutrality.music.source.UdioAudioSourceManager; +import me.bobert.netneutrality.thread.MusicPlayerAutoDisconnectThread; +import me.bobert.netneutrality.thread.ThreadManager; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.command.CommandExecutionResult; -import netneutrality.core.GuildManager; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.db.GSettings; -import netneutrality.exceptions.CommandExecutionException; -import netneutrality.music.loadable.LoadableSong; -import netneutrality.music.source.UdioAudioSourceManager; -import netneutrality.thread.MusicPlayerAutoDisconnectThread; -import netneutrality.thread.ThreadManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/me/bobert/netneutrality/music/QueueManager.java similarity index 98% rename from src/main/java/netneutrality/music/QueueManager.java rename to src/main/java/me/bobert/netneutrality/music/QueueManager.java index 70c0d1e..1689fed 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/me/bobert/netneutrality/music/QueueManager.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob * @@ -7,9 +7,9 @@ package netneutrality.music; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import me.bobert.netneutrality.command.CommandExecutionResult; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -import netneutrality.command.CommandExecutionResult; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/me/bobert/netneutrality/music/SourceFinder.java similarity index 98% rename from src/main/java/netneutrality/music/SourceFinder.java rename to src/main/java/me/bobert/netneutrality/music/SourceFinder.java index 41e1b66..b42bc6f 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/me/bobert/netneutrality/music/SourceFinder.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/me/bobert/netneutrality/music/TrackLoader.java similarity index 91% rename from src/main/java/netneutrality/music/TrackLoader.java rename to src/main/java/me/bobert/netneutrality/music/TrackLoader.java index 4aea43d..614a8c7 100644 --- a/src/main/java/netneutrality/music/TrackLoader.java +++ b/src/main/java/me/bobert/netneutrality/music/TrackLoader.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob * @@ -6,12 +6,12 @@ package netneutrality.music; */ import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.music.loadable.CachedSource; -import netneutrality.music.loadable.LoadableMusicSource; -import netneutrality.music.loadable.LoadableSong; -import netneutrality.thread.ThreadManager; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.music.loadable.CachedSource; +import me.bobert.netneutrality.music.loadable.LoadableMusicSource; +import me.bobert.netneutrality.music.loadable.LoadableSong; +import me.bobert.netneutrality.thread.ThreadManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java similarity index 95% rename from src/main/java/netneutrality/music/TrackLoadingHandler.java rename to src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java index f655008..f4accf2 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob * @@ -10,10 +10,10 @@ import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.Guild; -import netneutrality.core.LogHandler; -import netneutrality.core.context.CommandContext; -import netneutrality.utils.MessageFunction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/me/bobert/netneutrality/music/TrackScheduler.java similarity index 97% rename from src/main/java/netneutrality/music/TrackScheduler.java rename to src/main/java/me/bobert/netneutrality/music/TrackScheduler.java index 837c522..2860151 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/me/bobert/netneutrality/music/TrackScheduler.java @@ -1,4 +1,4 @@ -package netneutrality.music; +package me.bobert.netneutrality.music; /* * Copyright (c) anthorob * @@ -10,11 +10,11 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.core.LogHandler; -import netneutrality.utils.MessageFunction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java b/src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java similarity index 95% rename from src/main/java/netneutrality/music/loadable/AppleMostPlayed.java rename to src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java index 8f87a11..7d21eef 100644 --- a/src/main/java/netneutrality/music/loadable/AppleMostPlayed.java +++ b/src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java @@ -1,4 +1,4 @@ -package netneutrality.music.loadable; +package me.bobert.netneutrality.music.loadable; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/loadable/CachedSource.java b/src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java similarity index 94% rename from src/main/java/netneutrality/music/loadable/CachedSource.java rename to src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java index 749ffd8..d04b000 100644 --- a/src/main/java/netneutrality/music/loadable/CachedSource.java +++ b/src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java @@ -1,4 +1,4 @@ -package netneutrality.music.loadable; +package me.bobert.netneutrality.music.loadable; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java similarity index 84% rename from src/main/java/netneutrality/music/loadable/LoadableMusicSource.java rename to src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java index fb2479c..8e08cb6 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableMusicSource.java +++ b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java @@ -1,4 +1,4 @@ -package netneutrality.music.loadable; +package me.bobert.netneutrality.music.loadable; /* * Copyright (c) anthorob diff --git a/src/main/java/netneutrality/music/loadable/LoadableSong.java b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java similarity index 89% rename from src/main/java/netneutrality/music/loadable/LoadableSong.java rename to src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java index 6a7c0e2..1d476bc 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSong.java +++ b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java @@ -1,4 +1,4 @@ -package netneutrality.music.loadable; +package me.bobert.netneutrality.music.loadable; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java similarity index 94% rename from src/main/java/netneutrality/music/loadable/LoadableSourceManager.java rename to src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java index b16957e..a3ed29c 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java +++ b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java @@ -1,11 +1,11 @@ -package netneutrality.music.loadable; +package me.bobert.netneutrality.music.loadable; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ -import netneutrality.http.WebModule; +import me.bobert.netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.json.JSONObject; diff --git a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java similarity index 99% rename from src/main/java/netneutrality/music/source/UdioAudioSourceManager.java rename to src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java index 54cca31..9bf26e7 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java @@ -1,4 +1,4 @@ -package netneutrality.music.source; +package me.bobert.netneutrality.music.source; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/source/UdioAudioTrack.java b/src/main/java/me/bobert/netneutrality/music/source/UdioAudioTrack.java similarity index 98% rename from src/main/java/netneutrality/music/source/UdioAudioTrack.java rename to src/main/java/me/bobert/netneutrality/music/source/UdioAudioTrack.java index 3fd4d31..7b90151 100644 --- a/src/main/java/netneutrality/music/source/UdioAudioTrack.java +++ b/src/main/java/me/bobert/netneutrality/music/source/UdioAudioTrack.java @@ -1,4 +1,4 @@ -package netneutrality.music.source; +package me.bobert.netneutrality.music.source; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/thread/BaseThreadFactory.java b/src/main/java/me/bobert/netneutrality/thread/BaseThreadFactory.java similarity index 87% rename from src/main/java/netneutrality/thread/BaseThreadFactory.java rename to src/main/java/me/bobert/netneutrality/thread/BaseThreadFactory.java index d46a447..1c33201 100644 --- a/src/main/java/netneutrality/thread/BaseThreadFactory.java +++ b/src/main/java/me/bobert/netneutrality/thread/BaseThreadFactory.java @@ -1,4 +1,4 @@ -package netneutrality.thread; +package me.bobert.netneutrality.thread; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.thread; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.exceptions.ExecutorException; +import me.bobert.netneutrality.exceptions.ExecutorException; import org.jetbrains.annotations.NotNull; import java.util.concurrent.ThreadFactory; diff --git a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/me/bobert/netneutrality/thread/MusicPlayerAutoDisconnectThread.java similarity index 92% rename from src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java rename to src/main/java/me/bobert/netneutrality/thread/MusicPlayerAutoDisconnectThread.java index d367442..e97e091 100644 --- a/src/main/java/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/me/bobert/netneutrality/thread/MusicPlayerAutoDisconnectThread.java @@ -1,15 +1,15 @@ -package netneutrality.thread; +package me.bobert.netneutrality.thread; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.NetNeutrality; +import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; -import netneutrality.NetNeutrality; -import netneutrality.music.MusicManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/thread/ShutdownThread.java b/src/main/java/me/bobert/netneutrality/thread/ShutdownThread.java similarity index 87% rename from src/main/java/netneutrality/thread/ShutdownThread.java rename to src/main/java/me/bobert/netneutrality/thread/ShutdownThread.java index 72afaad..c9900e0 100644 --- a/src/main/java/netneutrality/thread/ShutdownThread.java +++ b/src/main/java/me/bobert/netneutrality/thread/ShutdownThread.java @@ -1,4 +1,4 @@ -package netneutrality.thread; +package me.bobert.netneutrality.thread; /* * Copyright (c) anthorob @@ -6,7 +6,7 @@ package netneutrality.thread; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.NetNeutrality; +import me.bobert.netneutrality.NetNeutrality; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configurator; diff --git a/src/main/java/netneutrality/thread/ThreadManager.java b/src/main/java/me/bobert/netneutrality/thread/ThreadManager.java similarity index 98% rename from src/main/java/netneutrality/thread/ThreadManager.java rename to src/main/java/me/bobert/netneutrality/thread/ThreadManager.java index 7854b0f..f2d88e7 100644 --- a/src/main/java/netneutrality/thread/ThreadManager.java +++ b/src/main/java/me/bobert/netneutrality/thread/ThreadManager.java @@ -1,4 +1,4 @@ -package netneutrality.thread; +package me.bobert.netneutrality.thread; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/utils/ChannelMessagePurger.java b/src/main/java/me/bobert/netneutrality/utils/ChannelMessagePurger.java similarity index 97% rename from src/main/java/netneutrality/utils/ChannelMessagePurger.java rename to src/main/java/me/bobert/netneutrality/utils/ChannelMessagePurger.java index 774831c..95ae067 100644 --- a/src/main/java/netneutrality/utils/ChannelMessagePurger.java +++ b/src/main/java/me/bobert/netneutrality/utils/ChannelMessagePurger.java @@ -1,4 +1,4 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob * @@ -9,12 +9,12 @@ import io.sentry.ISpan; import io.sentry.ITransaction; import io.sentry.Sentry; import io.sentry.SpanStatus; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.thread.ThreadManager; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageHistory; import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; -import netneutrality.core.context.CommandContext; -import netneutrality.thread.ThreadManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/utils/JpaUtils.java b/src/main/java/me/bobert/netneutrality/utils/JpaUtils.java similarity index 93% rename from src/main/java/netneutrality/utils/JpaUtils.java rename to src/main/java/me/bobert/netneutrality/utils/JpaUtils.java index ccca07e..3339ae6 100644 --- a/src/main/java/netneutrality/utils/JpaUtils.java +++ b/src/main/java/me/bobert/netneutrality/utils/JpaUtils.java @@ -1,4 +1,4 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob @@ -9,9 +9,9 @@ package netneutrality.utils; import io.sentry.Breadcrumb; import io.sentry.Sentry; import io.sentry.SentryLevel; -import netneutrality.core.GuildManager; -import netneutrality.core.SessionManager; -import netneutrality.db.entities.OGuild; +import me.bobert.netneutrality.core.GuildManager; +import me.bobert.netneutrality.core.SessionManager; +import me.bobert.netneutrality.db.entities.OGuild; import org.hibernate.HibernateException; import org.hibernate.ObjectNotFoundException; import org.hibernate.Session; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/me/bobert/netneutrality/utils/MessageFunction.java similarity index 96% rename from src/main/java/netneutrality/utils/MessageFunction.java rename to src/main/java/me/bobert/netneutrality/utils/MessageFunction.java index 35408b1..5b31a74 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/me/bobert/netneutrality/utils/MessageFunction.java @@ -1,4 +1,4 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob @@ -10,19 +10,19 @@ import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import io.sentry.Sentry; +import me.bobert.netneutrality.command.AbstractCommand; +import me.bobert.netneutrality.command.CommandManager; +import me.bobert.netneutrality.command.CommandType; +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.exceptions.CommandException; +import me.bobert.netneutrality.music.MusicManager; +import me.bobert.netneutrality.music.QueueManager; +import me.bobert.netneutrality.music.SourceFinder; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import netneutrality.command.AbstractCommand; -import netneutrality.command.CommandType; -import netneutrality.command.CommandManager; -import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandException; -import netneutrality.music.MusicManager; -import netneutrality.music.QueueManager; -import netneutrality.music.SourceFinder; import org.apache.commons.lang3.time.DurationFormatUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/netneutrality/utils/MiscUtils.java b/src/main/java/me/bobert/netneutrality/utils/MiscUtils.java similarity index 92% rename from src/main/java/netneutrality/utils/MiscUtils.java rename to src/main/java/me/bobert/netneutrality/utils/MiscUtils.java index 83fd053..c4af9f3 100644 --- a/src/main/java/netneutrality/utils/MiscUtils.java +++ b/src/main/java/me/bobert/netneutrality/utils/MiscUtils.java @@ -1,4 +1,4 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/utils/MusicUtils.java b/src/main/java/me/bobert/netneutrality/utils/MusicUtils.java similarity index 86% rename from src/main/java/netneutrality/utils/MusicUtils.java rename to src/main/java/me/bobert/netneutrality/utils/MusicUtils.java index 163f8c2..47a36e7 100644 --- a/src/main/java/netneutrality/utils/MusicUtils.java +++ b/src/main/java/me/bobert/netneutrality/utils/MusicUtils.java @@ -1,15 +1,15 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.exceptions.CommandExecutionException; +import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; -import netneutrality.core.context.CommandContext; -import netneutrality.exceptions.CommandExecutionException; -import netneutrality.music.MusicManager; public class MusicUtils { diff --git a/src/main/java/netneutrality/utils/Settings.java b/src/main/java/me/bobert/netneutrality/utils/Settings.java similarity index 79% rename from src/main/java/netneutrality/utils/Settings.java rename to src/main/java/me/bobert/netneutrality/utils/Settings.java index 4c73597..e1084da 100644 --- a/src/main/java/netneutrality/utils/Settings.java +++ b/src/main/java/me/bobert/netneutrality/utils/Settings.java @@ -1,4 +1,4 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob @@ -6,10 +6,9 @@ package netneutrality.utils; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.http.WebModule; +import me.bobert.netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; import org.json.JSONArray; -import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; @@ -76,27 +75,15 @@ public class Settings { public String getMavenVersion() { String version = null; - // try to load from maven properties first try { Properties p = new Properties(); - InputStream is = getClass().getResourceAsStream("/META-INF/maven/me.bobert/netneutrality/pom.properties"); + InputStream is = getClass().getResourceAsStream("/app.properties"); if (is != null) { p.load(is); - version = p.getProperty("version", ""); + version = p.getProperty("app.version", ""); } } catch (Exception ignored) {} - // fallback to using Java API - if (version == null) { - Package aPackage = getClass().getPackage(); - if (aPackage != null) { - version = aPackage.getImplementationVersion(); - if (version == null) { - version = aPackage.getSpecificationVersion(); - } - } - } - if (version == null) { version = "0.0.0"; } diff --git a/src/main/java/netneutrality/utils/UserFunction.java b/src/main/java/me/bobert/netneutrality/utils/UserFunction.java similarity index 92% rename from src/main/java/netneutrality/utils/UserFunction.java rename to src/main/java/me/bobert/netneutrality/utils/UserFunction.java index fbbe0f6..f3ef127 100644 --- a/src/main/java/netneutrality/utils/UserFunction.java +++ b/src/main/java/me/bobert/netneutrality/utils/UserFunction.java @@ -1,4 +1,4 @@ -package netneutrality.utils; +package me.bobert.netneutrality.utils; /* * Copyright (c) anthorob diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF index 2cd435e..9250482 100644 --- a/src/main/resources/META-INF/MANIFEST.MF +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -1,2 +1,2 @@ Manifest-Version: 1.0 -Main-Class: netneutrality.NetNeutrality +Main-Class: me.bobert.netneutrality.NetNeutrality diff --git a/src/main/resources/app.properties b/src/main/resources/app.properties new file mode 100644 index 0000000..4bc4ae6 --- /dev/null +++ b/src/main/resources/app.properties @@ -0,0 +1 @@ +app.version=${project.version} \ No newline at end of file diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml index d92de99..817a6be 100644 --- a/src/main/resources/hibernate.cfg.xml +++ b/src/main/resources/hibernate.cfg.xml @@ -8,12 +8,12 @@ <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property> <property name="hibernate.connection.provider_class">org.hibernate.hikaricp.internal.HikariCPConnectionProvider</property> - <mapping class="netneutrality.db.entities.OGuild"/> - <mapping class="netneutrality.db.entities.OBlacklist"/> - <mapping class="netneutrality.db.entities.OGuildSetting"/> - <mapping class="netneutrality.db.entities.OLogMessage"/> - <mapping class="netneutrality.db.entities.OLogging"/> - <mapping class="netneutrality.db.entities.OLoggingId"/> + <mapping class="me.bobert.netneutrality.db.entities.OGuild"/> + <mapping class="me.bobert.netneutrality.db.entities.OBlacklist"/> + <mapping class="me.bobert.netneutrality.db.entities.OGuildSetting"/> + <mapping class="me.bobert.netneutrality.db.entities.OLogMessage"/> + <mapping class="me.bobert.netneutrality.db.entities.OLogging"/> + <mapping class="me.bobert.netneutrality.db.entities.OLoggingId"/> </session-factory> </hibernate-configuration> \ No newline at end of file diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties index 42be505..836ebf0 100644 --- a/src/main/resources/log4j2.properties +++ b/src/main/resources/log4j2.properties @@ -38,7 +38,7 @@ logger.lavaplayer.appenderRef.console.ref = consoleLogger -logger.app.name = netneutrality +logger.app.name = me.bobert.netneutrality logger.app.level = debug logger.app.additivity = false logger.app.appenderRef.rolling.ref = LogToRollingFile diff --git a/src/test/java/netneutrality/music/LoadableSourceTest.java b/src/test/java/netneutrality/music/LoadableSourceTest.java index 9100343..1bf7da9 100644 --- a/src/test/java/netneutrality/music/LoadableSourceTest.java +++ b/src/test/java/netneutrality/music/LoadableSourceTest.java @@ -6,9 +6,9 @@ package netneutrality.music; * https://discord.gg/qUa6zNFZsd */ -import netneutrality.music.loadable.AppleMostPlayed; -import netneutrality.music.loadable.CachedSource; -import netneutrality.music.loadable.LoadableSourceManager; +import me.bobert.netneutrality.music.loadable.AppleMostPlayed; +import me.bobert.netneutrality.music.loadable.CachedSource; +import me.bobert.netneutrality.music.loadable.LoadableSourceManager; import org.junit.Test; import static org.junit.Assert.assertTrue; diff --git a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java index ad4efde..745e5e2 100644 --- a/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java +++ b/src/test/java/netneutrality/music/source/UdioAudioSourceManagerTest.java @@ -8,6 +8,8 @@ package netneutrality.music.source; import com.sedmelluq.discord.lavaplayer.track.AudioItem; import com.sedmelluq.discord.lavaplayer.track.AudioReference; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import me.bobert.netneutrality.music.source.UdioAudioSourceManager; +import me.bobert.netneutrality.music.source.UdioAudioTrack; import org.junit.Test; import static org.junit.Assert.assertNotNull; diff --git a/src/test/java/netneutrality/utils/SettingsTest.java b/src/test/java/netneutrality/utils/SettingsTest.java index 732b3b7..3e13580 100644 --- a/src/test/java/netneutrality/utils/SettingsTest.java +++ b/src/test/java/netneutrality/utils/SettingsTest.java @@ -6,6 +6,7 @@ package netneutrality.utils; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.utils.Settings; import org.junit.Test; import static org.junit.Assert.*; @@ -15,7 +16,6 @@ public class SettingsTest { @Test public void getMavenVersion() { String version = Settings.getInstance().getMavenVersion(); - System.out.println(version); assertNotNull(version); } @@ -23,7 +23,6 @@ public class SettingsTest { @Test public void getGitVersion() { String version = Settings.getInstance().getGitVersion(); - System.out.println(version); assertNotNull(version); } From 53c3ddb7321fce6483de13b099dcd3385d11ec39 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 13 Jul 2024 23:25:33 -0400 Subject: [PATCH 140/155] fix: bump youtube-source to 1.4.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a887824..0cea8e5 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ <dependency> <groupId>dev.lavalink.youtube</groupId> <artifactId>common</artifactId> - <version>1.2.0</version> + <version>1.4.0</version> </dependency> <dependency> From dc4ea8c6611540ed0de787fa20419c780a6efaf6 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 13 Jul 2024 23:43:16 -0400 Subject: [PATCH 141/155] build: fix environment variables in startup script --- build-bot.sh | 10 +++++----- startup.sh | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build-bot.sh b/build-bot.sh index 80881c4..854e33b 100644 --- a/build-bot.sh +++ b/build-bot.sh @@ -3,9 +3,9 @@ git fetch || exit 1 git pull || exit 1 -sudo docker compose down || exit 1 -sudo docker compose pull || exit 1 -sudo docker compose build || exit 1 +docker compose down || exit 1 +docker compose pull || exit 1 +docker compose build || exit 1 -sudo docker compose up -d -sudo docker compose logs -f \ No newline at end of file +docker compose up -d +docker compose logs -f \ No newline at end of file diff --git a/startup.sh b/startup.sh index 9b1262b..b8b0a25 100644 --- a/startup.sh +++ b/startup.sh @@ -24,23 +24,23 @@ if [ ! -f /usr/bin/nc ]; then exit 1 fi -if [ -z "$API_PORT" ]; then +if [ -z $API_PORT ]; then API_PORT=9000; fi -if [ -z "$MYSQL_HOST" ]; then - MYSQL_HOST="$(prop 'MYSQL_HOST')" +if [ -z $MYSQL_HOST ]; then + MYSQL_HOST="localhost" fi -if [ -z "$MYSQL_PORT" ]; then - MYSQL_PORT=$(prop 'MYSQL_PORT') +if [ -z $MYSQL_PORT ]; then + MYSQL_PORT=3306 fi echo "Waiting 10 seconds for database to start.." sleep 10 echo "Checking if MySQL / MariaDB is started.." -if /usr/bin/nc -z "$MYSQL_HOST" "$MYSQL_PORT"; then +if /usr/bin/nc -z $MYSQL_HOST $MYSQL_PORT; then echo "Database OK. Starting bot.."; /opt/java/openjdk/bin/java -jar /app/netneutrality-jar-with-dependencies.jar & From 2099c1753a28d1fa946b394f04c336841e36acbb Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sat, 13 Jul 2024 23:55:21 -0400 Subject: [PATCH 142/155] fix: fix wrongly named environment variables --- .env.example | 10 +++++----- bot.properties.example | 10 +++++----- docker-compose.yml | 1 + .../me/bobert/netneutrality/core/SessionManager.java | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index ffdbd3b..81b3a9a 100644 --- a/.env.example +++ b/.env.example @@ -4,10 +4,10 @@ NETNEUTRALITY_BOT_PREFIX=$ NETNEUTRALITY_BOT_OWNER= NETNEUTRALITY_API_PORT=9000 -NETNEUTRALITY_MYSQL_HOST=127.0.0.1 -NETNEUTRALITY_MYSQL_USER=root -NETNEUTRALITY_MYSQL_PASSWORD= -NETNEUTRALITY_MYSQL_DATABASE= -NETNEUTRALITY_MYSQL_PORT=3306 +MYSQL_HOST=127.0.0.1 +MYSQL_USER=root +MYSQL_PASSWORD= +MYSQL_DATABASE= +MYSQL_PORT=3306 NETNEUTRALITY_SENTRY_DSN= \ No newline at end of file diff --git a/bot.properties.example b/bot.properties.example index 62682ba..fe1be76 100644 --- a/bot.properties.example +++ b/bot.properties.example @@ -4,10 +4,10 @@ NETNEUTRALITY_BOT_PREFIX= NETNEUTRALITY_BOT_OWNER= NETNEUTRALITY_API_PORT=9000 -NETNEUTRALITY_MYSQL_HOST=127.0.0.1 -NETNEUTRALITY_MYSQL_USER=root -NETNEUTRALITY_MYSQL_PASSWORD= -NETNEUTRALITY_MYSQL_DATABASE= -NETNEUTRALITY_MYSQL_PORT=3306 +MYSQL_HOST=127.0.0.1 +MYSQL_USER=root +MYSQL_PASSWORD= +MYSQL_DATABASE= +MYSQL_PORT=3306 NETNEUTRALITY_SENTRY_DSN= \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 7aa7b13..19e1c1b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,7 @@ services: MYSQL_USER: 'java' MYSQL_PASSWORD: 'password' MYSQL_DATABASE: 'netneutrality' + env_file: ".env" ports: - "9000:9000" networks: diff --git a/src/main/java/me/bobert/netneutrality/core/SessionManager.java b/src/main/java/me/bobert/netneutrality/core/SessionManager.java index e79cf8e..fab89e5 100644 --- a/src/main/java/me/bobert/netneutrality/core/SessionManager.java +++ b/src/main/java/me/bobert/netneutrality/core/SessionManager.java @@ -29,10 +29,10 @@ public class SessionManager { try { StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder().configure(); Map<String, Object> settings = new HashMap<>(); - String dbName = Settings.getInstance().get("NETNEUTRALITY_MYSQL_DATABASE", "netneutrality"); - String dbUser = Settings.getInstance().get("NETNEUTRALITY_MYSQL_USER", "root"); - String dbPass = Settings.getInstance().get("NETNEUTRALITY_MYSQL_PASSWORD", ""); - String dbHost = Settings.getInstance().get("NETNEUTRALITY_MYSQL_HOST", "localhost"); + String dbName = Settings.getInstance().get("MYSQL_DATABASE", "netneutrality"); + String dbUser = Settings.getInstance().get("MYSQL_USER", "root"); + String dbPass = Settings.getInstance().get("MYSQL_PASSWORD", ""); + String dbHost = Settings.getInstance().get("MYSQL_HOST", "localhost"); logger.info(String.format("Connecting to database '%s' at %s:3306 with user '%s'", dbName, dbHost, dbUser)); settings.put(Environment.URL, String.format("jdbc:mysql://%s:3306/%s", dbHost, dbName)); From aba0441021c424e7f62c44f956bfb78be737fbee Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 00:00:42 -0400 Subject: [PATCH 143/155] fix: fix relection package to new path --- .../java/me/bobert/netneutrality/command/CommandManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/bobert/netneutrality/command/CommandManager.java b/src/main/java/me/bobert/netneutrality/command/CommandManager.java index 540a084..99d7e23 100644 --- a/src/main/java/me/bobert/netneutrality/command/CommandManager.java +++ b/src/main/java/me/bobert/netneutrality/command/CommandManager.java @@ -43,7 +43,7 @@ public class CommandManager { private static void initCommands() { logger.info("Loading commands.."); - Reflections reflections = new Reflections("netneutrality.command"); + Reflections reflections = new Reflections("me.bobert.netneutrality.command"); Set<Class<? extends AbstractCommand>> classes = reflections.getSubTypesOf(AbstractCommand.class); for (Class<? extends AbstractCommand> s : classes) { From 0db751af4401e036e8007a670ba92affea015bd7 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 00:12:14 -0400 Subject: [PATCH 144/155] refactor(LogHandler): use the exception itself instead of a string for buildSentryErrorMessage --- src/main/java/me/bobert/netneutrality/core/LogHandler.java | 2 +- .../me/bobert/netneutrality/music/TrackLoadingHandler.java | 2 +- .../java/me/bobert/netneutrality/music/TrackScheduler.java | 2 +- .../java/me/bobert/netneutrality/utils/MessageFunction.java | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/bobert/netneutrality/core/LogHandler.java b/src/main/java/me/bobert/netneutrality/core/LogHandler.java index c8b7fcc..9e9a09b 100644 --- a/src/main/java/me/bobert/netneutrality/core/LogHandler.java +++ b/src/main/java/me/bobert/netneutrality/core/LogHandler.java @@ -79,7 +79,7 @@ public class LogHandler { private static void tryGracefulSlashContextError(CommandException exception, CommandContext context) { if (context instanceof SlashCommandContext slashCommandContext) { - slashCommandContext.reply(MessageFunction.buildSentryErrorMessage(exception.getMessage())); + slashCommandContext.reply(MessageFunction.buildSentryErrorMessage(exception)); } } } diff --git a/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java b/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java index f4accf2..01cd090 100644 --- a/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java @@ -124,6 +124,6 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { LogHandler.log(e); if (!silent) - context.replyToMessage(MessageFunction.buildSentryErrorMessage("Failed to load track: " + e.getMessage())); + context.replyToMessage(MessageFunction.buildSentryErrorMessage(new RuntimeException("Failed to load track: " + e.getMessage()))); } } diff --git a/src/main/java/me/bobert/netneutrality/music/TrackScheduler.java b/src/main/java/me/bobert/netneutrality/music/TrackScheduler.java index 2860151..99de059 100644 --- a/src/main/java/me/bobert/netneutrality/music/TrackScheduler.java +++ b/src/main/java/me/bobert/netneutrality/music/TrackScheduler.java @@ -118,7 +118,7 @@ public class TrackScheduler extends AudioEventAdapter { public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { logger.debug("Guild {}: exception while playing track [{}]: {}", guild.getId(), track.getIdentifier(), exception.getMessage()); LogHandler.log(exception); - sendMessageToChannel(MessageFunction.buildSentryErrorMessage(String.format("Error while playing track [%s]: %s", track.getInfo().title, exception.getMessage()))); + sendMessageToChannel(MessageFunction.buildSentryErrorMessage(new RuntimeException(String.format("Error while playing track [%s]: %s", track.getInfo().title, exception.getMessage())))); } @Override diff --git a/src/main/java/me/bobert/netneutrality/utils/MessageFunction.java b/src/main/java/me/bobert/netneutrality/utils/MessageFunction.java index 5b31a74..3cd26b6 100644 --- a/src/main/java/me/bobert/netneutrality/utils/MessageFunction.java +++ b/src/main/java/me/bobert/netneutrality/utils/MessageFunction.java @@ -212,11 +212,11 @@ public class MessageFunction { return messages; } - public static MessageEmbed buildSentryErrorMessage(String error) { + public static MessageEmbed buildSentryErrorMessage(Exception ex) { EmbedBuilder message = new EmbedBuilder(); message.setColor(Color.RED); message.setTitle(":warning: Error during execution :warning:"); - message.addField("Error message:", error, false); + message.addField("Error message:", ex.getMessage(), false); message.addField("Error ID:", Sentry.getLastEventId().toString(), false); message.setTimestamp(OffsetDateTime.now()); From 2aa75ce0fc33035887c752db46fec0d35021c07c Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 00:28:44 -0400 Subject: [PATCH 145/155] refactor: remove convoluted TrackLoader and LoadableSongs abstraction BREAKING CHANGE: removed TrackLoader amd LoadableSongs --- .../netneutrality/music/MusicManager.java | 29 ++-- .../netneutrality/music/QueueManager.java | 1 - .../netneutrality/music/TrackLoader.java | 126 ------------------ .../music/TrackLoadingHandler.java | 37 ----- .../music/loadable/AppleMostPlayed.java | 41 ------ .../music/loadable/CachedSource.java | 39 ------ .../music/loadable/LoadableMusicSource.java | 19 --- .../music/loadable/LoadableSong.java | 18 --- .../music/loadable/LoadableSourceManager.java | 57 -------- .../music/LoadableSourceTest.java | 27 ---- 10 files changed, 9 insertions(+), 385 deletions(-) delete mode 100644 src/main/java/me/bobert/netneutrality/music/TrackLoader.java delete mode 100644 src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java delete mode 100644 src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java delete mode 100644 src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java delete mode 100644 src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java delete mode 100644 src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java delete mode 100644 src/test/java/netneutrality/music/LoadableSourceTest.java diff --git a/src/main/java/me/bobert/netneutrality/music/MusicManager.java b/src/main/java/me/bobert/netneutrality/music/MusicManager.java index f32fd1a..4b69cbc 100644 --- a/src/main/java/me/bobert/netneutrality/music/MusicManager.java +++ b/src/main/java/me/bobert/netneutrality/music/MusicManager.java @@ -19,7 +19,6 @@ import me.bobert.netneutrality.core.LogHandler; import me.bobert.netneutrality.core.context.CommandContext; import me.bobert.netneutrality.db.GSettings; import me.bobert.netneutrality.exceptions.CommandExecutionException; -import me.bobert.netneutrality.music.loadable.LoadableSong; import me.bobert.netneutrality.music.source.UdioAudioSourceManager; import me.bobert.netneutrality.thread.MusicPlayerAutoDisconnectThread; import me.bobert.netneutrality.thread.ThreadManager; @@ -30,8 +29,6 @@ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; @@ -48,7 +45,6 @@ public class MusicManager { private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; - private TrackLoader lastTrackLoader; private ScheduledFuture<?> autoDisconnectThread; private final int baseVolume; @@ -126,10 +122,6 @@ public class MusicManager { return guild; } - public void stopLoading() { - lastTrackLoader.stopLoading(); - } - public synchronized void leave() { if (guild != null && guild.getAudioManager().getConnectedChannel() != null) { logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId()); @@ -152,16 +144,9 @@ public class MusicManager { } } - public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { - logger.debug("Guild {}: request to play '{}' by user {}", guild.getId(), url, context.getGuildUser().getId()); + public synchronized void play(String query, CommandContext context, boolean needToBeConnected, boolean silent) { + logger.debug("Guild {}: request to play '{}' by user {}", guild.getId(), query, context.getGuildUser().getId()); - List<LoadableSong> toLoad = new ArrayList<>(); - toLoad.add(new LoadableSong(null, url, null)); - - play(toLoad, context, needToBeConnected, silent); - } - - public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); MessageChannel channel = context.getChannel(); @@ -189,10 +174,14 @@ public class MusicManager { scheduler.attachTextChannel(channel); } - TrackLoader loader = new TrackLoader(this, context, playerManager, silent); - lastTrackLoader = loader; + SourceFinder.AudioSourceType type = SourceFinder.getSource(query); + String identifier = SourceFinder.getIdentifier(query); - loader.loadAllSongs(songs); + if (identifier != null) { + TrackLoadingHandler loadingHandler = new TrackLoadingHandler(context, this, identifier, type, silent); + + playerManager.loadItemOrdered(this, identifier, loadingHandler); + } } public synchronized void stopTrack() { diff --git a/src/main/java/me/bobert/netneutrality/music/QueueManager.java b/src/main/java/me/bobert/netneutrality/music/QueueManager.java index 1689fed..9676928 100644 --- a/src/main/java/me/bobert/netneutrality/music/QueueManager.java +++ b/src/main/java/me/bobert/netneutrality/music/QueueManager.java @@ -138,7 +138,6 @@ public class QueueManager { } public CommandExecutionResult clearQueue() { - scheduler.getMusicManager().stopLoading(); scheduler.getMusicManager().leave(); if (queue.isEmpty()) { diff --git a/src/main/java/me/bobert/netneutrality/music/TrackLoader.java b/src/main/java/me/bobert/netneutrality/music/TrackLoader.java deleted file mode 100644 index 614a8c7..0000000 --- a/src/main/java/me/bobert/netneutrality/music/TrackLoader.java +++ /dev/null @@ -1,126 +0,0 @@ -package me.bobert.netneutrality.music; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; -import me.bobert.netneutrality.core.LogHandler; -import me.bobert.netneutrality.core.context.CommandContext; -import me.bobert.netneutrality.music.loadable.CachedSource; -import me.bobert.netneutrality.music.loadable.LoadableMusicSource; -import me.bobert.netneutrality.music.loadable.LoadableSong; -import me.bobert.netneutrality.thread.ThreadManager; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.List; - -public class TrackLoader implements Runnable { - - private final Logger logger = LogManager.getLogger(TrackLoader.class); - private final CommandContext context; - private final MusicManager musicManager; - private final AudioPlayerManager audioPlayerManager; - private TrackLoadingHandler lastLoadingHandler; - private List<LoadableSong> songs; - private LoadableMusicSource source; - private int numberOfTracksLoaded; - private int totalNumberOfTracks; - private boolean loadingDisabled = false; - private boolean silent; - private final Object sync = new Object(); - - public TrackLoader(MusicManager musicManager, CommandContext context, AudioPlayerManager playerManager, boolean silent) { - this.musicManager = musicManager; - this.context = context; - this.audioPlayerManager = playerManager; - this.silent = silent; - } - - public void loadAllSongs(List<LoadableSong> songs) { - this.songs = songs; - if (songs.size() > 1) { - this.silent = true; - } - - ThreadManager.getMusicExecutor().submit(this); - } - - public void loadAllSongs(CachedSource cachedSource) { - this.source = cachedSource.getSource(); - - loadAllSongs(cachedSource.getSongs()); - } - - public void stopLoading() { - loadingDisabled = true; - - if (lastLoadingHandler != null) { - lastLoadingHandler.stopLoading(); - } - } - - @Override - public void run() { - List<LoadableSong> copy = new ArrayList<>(songs); - - for (LoadableSong song : songs) { - if (loadingDisabled) { - copy.remove(song); - break; - } - - SourceFinder.AudioSourceType type = SourceFinder.getSource(song.name()); - String identifier = SourceFinder.getIdentifier(song.name()); - - if (identifier != null) { - TrackLoadingHandler loadingHandler = new TrackLoadingHandler(context, musicManager, identifier, type, silent); - loadingHandler.useCallbackOnLoad(success -> { - - synchronized (sync) { - if (success) { - numberOfTracksLoaded++; - } - - totalNumberOfTracks++; - - logger.debug("callback notify; total={}, loaded={}", totalNumberOfTracks, numberOfTracksLoaded); - sync.notify(); - } - - }); - lastLoadingHandler = loadingHandler; - - audioPlayerManager.loadItemOrdered(this, identifier, loadingHandler); - } else { - copy.remove(song); - - if (songs.size() == 1) { - context.replyToMessage("No source found to play the given url"); - } - } - } - - try { - synchronized (sync) { - while (!(copy.size() == totalNumberOfTracks)) { - logger.debug("waiting for load; size={}, total={}, loaded={}", songs.size(), totalNumberOfTracks, numberOfTracksLoaded); - sync.wait(); - } - - //TODO: logic - if (copy.size() > 1 && source != null && !loadingDisabled) { - context.replyToMessage("Loaded %d of %d tracks from online source", numberOfTracksLoaded, totalNumberOfTracks); - } - } - } catch (InterruptedException exception) { - stopLoading(); - context.replyToMessage("Loading of tracks was interrupted due to an exception"); - LogHandler.log(exception); - } - - } -} diff --git a/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java b/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java index 01cd090..007a040 100644 --- a/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/me/bobert/netneutrality/music/TrackLoadingHandler.java @@ -17,16 +17,12 @@ import net.dv8tion.jda.api.entities.Guild; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.function.Consumer; - public class TrackLoadingHandler implements AudioLoadResultHandler { private final Logger logger = LogManager.getLogger(TrackLoadingHandler.class); private final String identifier; private final SourceFinder.AudioSourceType type; private final boolean silent; - private Consumer<Boolean> loadConsumer; - private boolean loadingDisabled = false; private final Guild guild; private final TrackScheduler scheduler; private final CommandContext context; @@ -40,24 +36,8 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { this.context = context; } - public synchronized void stopLoading() { - logger.debug("Guild {}: stopped loading of new tracks", guild.getId()); - loadingDisabled = true; - } - - public void useCallbackOnLoad(Consumer<Boolean> consumer) { - this.loadConsumer = consumer; - } - @Override public void trackLoaded(AudioTrack audioTrack) { - if (loadConsumer != null) { - loadConsumer.accept(true); - } - - if (loadingDisabled) - return; - context.deleteMessage(); logger.debug("Guild {}: track loaded: {}", guild.getId(), audioTrack.getIdentifier()); @@ -70,13 +50,6 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { @Override public void playlistLoaded(AudioPlaylist playlist) { - if (loadConsumer != null) { - loadConsumer.accept(true); - } - - if (loadingDisabled) - return; - logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); if (!playlist.getTracks().isEmpty()) { @@ -96,10 +69,6 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { } for (AudioTrack track : playlist.getTracks()) { - if (loadingDisabled) { - break; - } - scheduler.getQueueManager().queue(track, context.getGuildUser()); } } @@ -108,18 +77,12 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { @Override public void noMatches() { - if (loadConsumer != null) - loadConsumer.accept(false); - if (!silent) context.replyToMessage("No matches found"); } @Override public void loadFailed(FriendlyException e) { - if (loadConsumer != null) - loadConsumer.accept(false); - logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); LogHandler.log(e); diff --git a/src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java b/src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java deleted file mode 100644 index 7d21eef..0000000 --- a/src/main/java/me/bobert/netneutrality/music/loadable/AppleMostPlayed.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.bobert.netneutrality.music.loadable; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -public class AppleMostPlayed implements LoadableMusicSource { - @Override - public String url() { - return "https://rss.applemarketingtools.com/api/v2/ca/music/most-played/25/songs.json"; - } - - @Override - public List<LoadableSong> parse(JSONObject obj) { - List<LoadableSong> songs = new ArrayList<>(); - JSONArray results = obj.getJSONObject("feed").getJSONArray("results"); - - results.forEach(o -> { - JSONObject song = (JSONObject) o; - String artist = song.getString("artistName"); - String songName = song.getString("name"); - String artwork = song.getString("artworkUrl100"); - - songs.add(new LoadableSong(artist, songName, artwork)); - }); - - return songs; - } - - @Override - public String getIdentifier() { - return "apple"; - } -} diff --git a/src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java b/src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java deleted file mode 100644 index d04b000..0000000 --- a/src/main/java/me/bobert/netneutrality/music/loadable/CachedSource.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.bobert.netneutrality.music.loadable; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - - -import java.time.OffsetDateTime; -import java.util.List; - -public class CachedSource { - private final LoadableMusicSource source; - private OffsetDateTime lastAccess; - private final List<LoadableSong> songs; - - protected CachedSource(LoadableMusicSource source, List<LoadableSong> songs) { - this.source = source; - this.lastAccess = OffsetDateTime.now(); - this.songs = songs; - } - - public List<LoadableSong> getSongs() { - return songs; - } - - public OffsetDateTime getLastAccess() { - return lastAccess; - } - - public LoadableMusicSource getSource() { - return source; - } - - public void updateAccessTime() { - this.lastAccess = OffsetDateTime.now(); - } - -} diff --git a/src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java deleted file mode 100644 index 8e08cb6..0000000 --- a/src/main/java/me/bobert/netneutrality/music/loadable/LoadableMusicSource.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.bobert.netneutrality.music.loadable; - -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import org.json.JSONObject; - -import java.util.List; - -public interface LoadableMusicSource { - String url(); - - List<LoadableSong> parse(JSONObject obj); - - String getIdentifier(); -} diff --git a/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java deleted file mode 100644 index 1d476bc..0000000 --- a/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSong.java +++ /dev/null @@ -1,18 +0,0 @@ -package me.bobert.netneutrality.music.loadable; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -public record LoadableSong(String artist, String name, String artworkUrl) { - - @Override - public String toString() { - return "LoadableSong{" + - "artist='" + artist + '\'' + - ", name='" + name + '\'' + - ", artworkUrl='" + artworkUrl + '\'' + - '}'; - } -} diff --git a/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java deleted file mode 100644 index a3ed29c..0000000 --- a/src/main/java/me/bobert/netneutrality/music/loadable/LoadableSourceManager.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.bobert.netneutrality.music.loadable; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.http.WebModule; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.json.JSONObject; - -import java.time.OffsetDateTime; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class LoadableSourceManager { - - private final Logger logger = LogManager.getLogger(LoadableSourceManager.class); - private static final Map<String, CachedSource> cache = new HashMap<>(); - - public CachedSource get(LoadableMusicSource source) { - - if (cache.containsKey(source.getIdentifier())) { - CachedSource cachedSource = cache.get(source.getIdentifier()); - - if (OffsetDateTime.now().isAfter(cachedSource.getLastAccess().plusHours(4))) { - cachedSource.getSongs().clear(); - cachedSource.getSongs().addAll(loadFromUrl(source)); - cachedSource.updateAccessTime(); - } - - return cachedSource; - } - - List<LoadableSong> songs = loadFromUrl(source); - CachedSource newCachedSource = new CachedSource(source, songs); - - cache.put(source.getIdentifier(), newCachedSource); - return newCachedSource; - } - - private List<LoadableSong> loadFromUrl(LoadableMusicSource source) { - WebModule web = new WebModule(source.url()); - JSONObject obj = web.request().getAsObject(); - - if (obj == null) - return Collections.emptyList(); - - List<LoadableSong> songs = source.parse(obj); - Collections.shuffle(songs); - - return songs; - } -} diff --git a/src/test/java/netneutrality/music/LoadableSourceTest.java b/src/test/java/netneutrality/music/LoadableSourceTest.java deleted file mode 100644 index 1bf7da9..0000000 --- a/src/test/java/netneutrality/music/LoadableSourceTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package netneutrality.music; - -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.music.loadable.AppleMostPlayed; -import me.bobert.netneutrality.music.loadable.CachedSource; -import me.bobert.netneutrality.music.loadable.LoadableSourceManager; -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -public class LoadableSourceTest { - - @Test - public void cachedSourceAccess() { - LoadableSourceManager loadableSourceManager = new LoadableSourceManager(); - - CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed()); - CachedSource sameCachedSource = loadableSourceManager.get(new AppleMostPlayed()); - - assertTrue(cachedSource.getLastAccess().isEqual(sameCachedSource.getLastAccess())); - } -} \ No newline at end of file From 9f4b7187b90a6cdd030d3cacfe724e1f838cfd08 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 00:58:59 -0400 Subject: [PATCH 146/155] build: fix startup script for local execution --- startup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/startup.sh b/startup.sh index b8b0a25..7af7a26 100644 --- a/startup.sh +++ b/startup.sh @@ -29,11 +29,11 @@ if [ -z $API_PORT ]; then fi if [ -z $MYSQL_HOST ]; then - MYSQL_HOST="localhost" + MYSQL_HOST="$(prop 'MYSQL_HOST')" fi if [ -z $MYSQL_PORT ]; then - MYSQL_PORT=3306 + MYSQL_PORT=$(prop 'MYSQL_PORT') fi echo "Waiting 10 seconds for database to start.." From 7ad2740a2b31493cc021eeba6e9b99394019c1a2 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 01:35:08 -0400 Subject: [PATCH 147/155] refactor: add release to Sentry config --- src/main/java/me/bobert/netneutrality/NetNeutrality.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/bobert/netneutrality/NetNeutrality.java b/src/main/java/me/bobert/netneutrality/NetNeutrality.java index ea394f2..3f37905 100644 --- a/src/main/java/me/bobert/netneutrality/NetNeutrality.java +++ b/src/main/java/me/bobert/netneutrality/NetNeutrality.java @@ -49,6 +49,7 @@ public class NetNeutrality { options.setEnvironment(env); options.setTracesSampleRate(1.0); options.setDebug(false); + options.setRelease(VERSION); }); } From d298fc77eea9697a064c280e6a4203a9d08b9180 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 11:53:22 -0400 Subject: [PATCH 148/155] docs: Update LICENSE --- LICENSE | 811 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 642 insertions(+), 169 deletions(-) diff --git a/LICENSE b/LICENSE index 261eeb9..f288702 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,674 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. - 1. Definitions. + Preamble - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. + The GNU General Public License is a free, copyleft license for +software and other kinds of works. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. + The precise terms and conditions for copying, distribution and +modification follow. - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. + TERMS AND CONDITIONS - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. + 0. Definitions. - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: + "This License" refers to version 3 of the GNU General Public License. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. + A "covered work" means either the unmodified Program or a work based +on the Program. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. + 1. Source Code. - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. - END OF TERMS AND CONDITIONS + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. - APPENDIX: How to apply the Apache License to your work. + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. - Copyright [yyyy] [name of copyright owner] + The Corresponding Source for a work in source code form is that +same work. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + 2. Basic Permissions. - http://www.apache.org/licenses/LICENSE-2.0 + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. From ad00a6b542f5ba8f5d8997b3ade6e48659d771aa Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 12:16:29 -0400 Subject: [PATCH 149/155] refactor: Remove unused command --- .../command/warframe/JoinClanCommand.java | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 src/main/java/netneutrality/command/warframe/JoinClanCommand.java diff --git a/src/main/java/netneutrality/command/warframe/JoinClanCommand.java b/src/main/java/netneutrality/command/warframe/JoinClanCommand.java deleted file mode 100644 index 102ee32..0000000 --- a/src/main/java/netneutrality/command/warframe/JoinClanCommand.java +++ /dev/null @@ -1,64 +0,0 @@ -package netneutrality.command.warframe; - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import net.dv8tion.jda.core.events.message.MessageReceivedEvent; -import netneutrality.command.AbstractCommand; -import netneutrality.command.Visibility; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBLogging; - -public class JoinClanCommand extends AbstractCommand { - - String roleId = "458372887619829770"; - - @Override - public boolean needAdmin() { - return false; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getCommand() { - return "joinclan"; - } - - @Override - public String[] getAlias() { - return new String[0]; - } - - @Override - public String getUsage() { - return null; - } - - @Override - public Visibility getVisibility() { - return Visibility.CHANNEL; - } - - @Override - public String execute(MessageReceivedEvent event, String args) { - event.getMessage().delete().queue(); - - ((DBLogging) DBController.get("logging")).getLoggingChannel(event.getGuild().getId(), logging -> { - - if (logging != null) { - event.getGuild().getController().addRolesToMember(event.getMember(), event.getGuild().getRoleById(roleId)).queue(); - logging.sendMessage("Added user \"" + event.getMember().getEffectiveName() + "\" to the role \"Clan Member\"").queue(); - } - }); - - return null; - } -} From 719c55ee27d8c62c401bfc4ade8b038d89711fb0 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 12:20:35 -0400 Subject: [PATCH 150/155] build: Update JDA to v5 and use v2 for youtube-source --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0cea8e5..6f9d2f3 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ <dependency> <groupId>net.dv8tion</groupId> <artifactId>JDA</artifactId> - <version>5.0.0-beta.24</version> + <version>5.0.0</version> </dependency> <dependency> <groupId>dev.arbjerg</groupId> @@ -100,7 +100,7 @@ </dependency> <dependency> <groupId>dev.lavalink.youtube</groupId> - <artifactId>common</artifactId> + <artifactId>v2</artifactId> <version>1.4.0</version> </dependency> From 9d8b38d309e131c5e4f79d5f0005cfe0cc2a6ee0 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 13:05:00 -0400 Subject: [PATCH 151/155] ci: improve ci config for maven --- .gitlab-ci.yml | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 942e883..2afe48d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,13 +1,24 @@ image: eclipse-temurin:17-jdk-alpine variables: - MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode" - MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository" + MAVEN_OPTS: >- + -Dhttps.protocols=TLSv1.2 + -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository + -Dorg.slf4j.simpleLogger.showDateTime=true + -Djava.awt.headless=true + + MAVEN_CLI_OPTS: >- + --batch-mode + --errors + --fail-at-end + --show-version + --no-transfer-progress + -DinstallAtEnd=true + -DdeployAtEnd=true cache: paths: - - .m2/repository/ - - target/ + - .m2/repository stages: - compile @@ -18,19 +29,23 @@ compile: stage: compile script: - "chmod +x ./mvnw" - - "./mvnw --batch-mode compile" + - "./mvnw $MAVEN_CLI_OPTS compile" test: stage: test script: - "chmod +x ./mvnw" - - "./mvnw --batch-mode test" + - "./mvnw $MAVEN_CLI_OPTS test" package: stage: package script: - "chmod +x ./mvnw" - - "./mvnw --batch-mode package" + - "./mvnw $MAVEN_CLI_OPTS package -DskipTests=true" artifacts: + name: "Maven artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG" paths: - - target/netneutrality-jar-with-dependencies.jar \ No newline at end of file + - "**/target" + reports: + junit: + - "**/target/*-reports/TEST-*.xml" \ No newline at end of file From bb655d2a56eb339254738cd62907b7530a811415 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 13:16:04 -0400 Subject: [PATCH 152/155] ci: add cache key --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2afe48d..790d5d1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,6 +17,7 @@ variables: -DdeployAtEnd=true cache: + key: "maven-$CI_COMMIT_REF_SLUG" paths: - .m2/repository From f6ed32b090ab11963c340662c5c4e2b3434719bf Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 13:21:07 -0400 Subject: [PATCH 153/155] ci: add junit reports in test phase --- .gitlab-ci.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 790d5d1..ac04551 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,6 +37,11 @@ test: script: - "chmod +x ./mvnw" - "./mvnw $MAVEN_CLI_OPTS test" + artifacts: + when: always + reports: + junit: + - "**/target/*-reports/TEST-*.xml" package: stage: package @@ -46,7 +51,4 @@ package: artifacts: name: "Maven artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG" paths: - - "**/target" - reports: - junit: - - "**/target/*-reports/TEST-*.xml" \ No newline at end of file + - "**/target" \ No newline at end of file From 5775493b2c30cac2ea75efb2804ab740b8462dfe Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 13:59:38 -0400 Subject: [PATCH 154/155] refactor: fix inspection errors for deprecated calls and concatenation --- .../netneutrality/command/CommandManager.java | 2 +- .../netneutrality/core/GuildConfigManager.java | 8 ++++---- .../bobert/netneutrality/core/GuildManager.java | 17 +++-------------- .../db/controllers/DBBlacklist.java | 8 ++++---- .../netneutrality/db/controllers/DBMessage.java | 4 ++-- .../hooks/message/MessageReceivedHandler.java | 2 -- .../me/bobert/netneutrality/http/WebModule.java | 2 +- .../netneutrality/http/server/WebApi.java | 2 +- .../music/source/UdioAudioSourceManager.java | 4 ++-- .../me/bobert/netneutrality/utils/JpaUtils.java | 7 +++---- 10 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/main/java/me/bobert/netneutrality/command/CommandManager.java b/src/main/java/me/bobert/netneutrality/command/CommandManager.java index 99d7e23..c2b7e51 100644 --- a/src/main/java/me/bobert/netneutrality/command/CommandManager.java +++ b/src/main/java/me/bobert/netneutrality/command/CommandManager.java @@ -66,7 +66,7 @@ public class CommandManager { } } - logger.info("Loaded " + commands.size() + " commands!"); + logger.info("Loaded {} commands!", commands.size()); } private static void registerSlashCommands() { diff --git a/src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java b/src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java index d494b32..6e30312 100644 --- a/src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java +++ b/src/main/java/me/bobert/netneutrality/core/GuildConfigManager.java @@ -58,7 +58,7 @@ public class GuildConfigManager { session.beginTransaction(); if (value == null || setting.getDefaultValue().equals(value)) { if (oGuildSetting != null) { - session.delete(oGuildSetting); + session.remove(oGuildSetting); } } else { if (oGuildSetting == null) { @@ -67,11 +67,11 @@ public class GuildConfigManager { oGuildSetting.setName(setting.getName()); oGuildSetting.setValue(value); - session.save(oGuildSetting); + session.persist(oGuildSetting); } else { oGuildSetting.setValue(value); - session.update(oGuildSetting); + session.merge(oGuildSetting); } } @@ -82,7 +82,7 @@ public class GuildConfigManager { } public void reloadSettingsCache() { - logger.debug("Reloading settings cache for guild: " + guild.getId()); + logger.debug("Reloading settings cache for guild: {}", guild.getId()); settingsCache.clear(); JpaUtils.getWithSession(guildEntity, session -> { diff --git a/src/main/java/me/bobert/netneutrality/core/GuildManager.java b/src/main/java/me/bobert/netneutrality/core/GuildManager.java index 26aa6bf..8ed2587 100644 --- a/src/main/java/me/bobert/netneutrality/core/GuildManager.java +++ b/src/main/java/me/bobert/netneutrality/core/GuildManager.java @@ -12,7 +12,6 @@ import me.bobert.netneutrality.db.entities.OBlacklist; import me.bobert.netneutrality.db.entities.OGuild; import me.bobert.netneutrality.thread.ThreadManager; import me.bobert.netneutrality.utils.JpaUtils; -import me.bobert.netneutrality.utils.MessageFunction; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; @@ -113,7 +112,7 @@ public class GuildManager { } public void reloadBlacklistCache() { - logger.debug("Reloading blacklist cache for guild: " + guild.getId()); + logger.debug("Reloading blacklist cache for guild: {}", guild.getId()); blacklistCache.clear(); JpaUtils.getWithSession(guildEntity, session -> { @@ -127,16 +126,6 @@ public class GuildManager { }); } - public void checkAndLogMessage(Message message, Member member, MessageChannel channel) { - if (isLoggingEnabled()) { - ThreadManager.getExecutor().submit(() -> DBController.get(DBMessage.class).log(this, channel, member, message)); - } - } - - public void checkBlacklist(Message message, MessageChannel channel) { - MessageFunction.testMessageAgainstBlacklist(message, channel, blacklistCache); - } - private OGuild loadGuildFromDb(String guildId) { Session session = sessionFactory.openSession(); OGuild entity = session.get(OGuild.class, guildId); @@ -148,7 +137,7 @@ public class GuildManager { entity.setGuildId(guildId); - session.save(entity); + session.persist(entity); session.getTransaction().commit(); guild.getTextChannels() @@ -169,7 +158,7 @@ public class GuildManager { Session session = sessionFactory.openSession(); session.beginTransaction(); - session.delete(guildEntity); + session.remove(guildEntity); session.getTransaction().commit(); session.close(); diff --git a/src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java index 8f213fc..19dea2a 100644 --- a/src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/me/bobert/netneutrality/db/controllers/DBBlacklist.java @@ -35,7 +35,7 @@ public class DBBlacklist extends AbstractController { bl.setWord(word); bl.setEnabled(true); - session.save(bl); + session.persist(bl); session.getTransaction().commit(); session.close(); @@ -57,7 +57,7 @@ public class DBBlacklist extends AbstractController { Session session = getSessionFactory().openSession(); session.beginTransaction(); - session.delete(bl); + session.remove(bl); session.getTransaction().commit(); session.close(); @@ -79,7 +79,7 @@ public class DBBlacklist extends AbstractController { bl.setEnabled(true); - session.update(bl); + session.merge(bl); session.getTransaction().commit(); session.close(); @@ -103,7 +103,7 @@ public class DBBlacklist extends AbstractController { bl.setEnabled(false); - session.update(bl); + session.merge(bl); session.getTransaction().commit(); session.close(); diff --git a/src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java b/src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java index 50d8c21..81b1b38 100644 --- a/src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/me/bobert/netneutrality/db/controllers/DBMessage.java @@ -34,7 +34,7 @@ public class DBMessage extends AbstractController { logMessage.setUserId(author.getId()); logMessage.setDateSent(message.getTimeCreated().toInstant()); - session.save(logMessage); + session.persist(logMessage); session.getTransaction().commit(); session.close(); } @@ -49,7 +49,7 @@ public class DBMessage extends AbstractController { session.beginTransaction(); message.setEditedMessage(newMessage); - session.update(message); + session.merge(message); session.getTransaction().commit(); } diff --git a/src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java b/src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java index c143659..7defada 100644 --- a/src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/me/bobert/netneutrality/hooks/message/MessageReceivedHandler.java @@ -28,8 +28,6 @@ public class MessageReceivedHandler extends ListenerAdapter { MessageCommandContext context = MessageCommandContext.createContext(event); - GuildManager.getManager(context.getGuild()).checkAndLogMessage(message, context.getGuildUser(), context.getChannel()); - String rawMessage = message.getContentDisplay().trim(); String prefix = Settings.getInstance().get("NETNEUTRALITY_BOT_PREFIX", "$"); diff --git a/src/main/java/me/bobert/netneutrality/http/WebModule.java b/src/main/java/me/bobert/netneutrality/http/WebModule.java index 2eb19d4..03a2750 100644 --- a/src/main/java/me/bobert/netneutrality/http/WebModule.java +++ b/src/main/java/me/bobert/netneutrality/http/WebModule.java @@ -53,7 +53,7 @@ public class WebModule { return this; } - public WebModule request(Map<String, String> headers) throws IOException { + public WebModule request(Map<String, String> headers) { Sentry.addBreadcrumb(Breadcrumb.http(url, "get")); Request.Builder builder = new Request.Builder().url(this.url) .addHeader("User-Agent", userAgent); diff --git a/src/main/java/me/bobert/netneutrality/http/server/WebApi.java b/src/main/java/me/bobert/netneutrality/http/server/WebApi.java index 7828fce..216c7c1 100644 --- a/src/main/java/me/bobert/netneutrality/http/server/WebApi.java +++ b/src/main/java/me/bobert/netneutrality/http/server/WebApi.java @@ -38,7 +38,7 @@ public class WebApi { ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThreadFactory("web-api")); server.setExecutor(executor); server.start(); - logger.info("Web server started at [" + server.getAddress() + "]"); + logger.info("Web server started at [{}]", server.getAddress()); } diff --git a/src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java b/src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java index 9bf26e7..eaeaa79 100644 --- a/src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java +++ b/src/main/java/me/bobert/netneutrality/music/source/UdioAudioSourceManager.java @@ -75,12 +75,12 @@ public class UdioAudioSourceManager implements AudioSourceManager { } @Override - public void encodeTrack(AudioTrack track, DataOutput output) throws IOException { + public void encodeTrack(AudioTrack track, DataOutput output) { } @Override - public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException { + public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) { return new UdioAudioTrack(trackInfo, this); } diff --git a/src/main/java/me/bobert/netneutrality/utils/JpaUtils.java b/src/main/java/me/bobert/netneutrality/utils/JpaUtils.java index 3339ae6..2996950 100644 --- a/src/main/java/me/bobert/netneutrality/utils/JpaUtils.java +++ b/src/main/java/me/bobert/netneutrality/utils/JpaUtils.java @@ -23,10 +23,10 @@ public class JpaUtils { /** * Tries to read the persistent state into the object. - * + * <p> * If the object is not found in the database and is of type {@link OGuild}, tries to recreate entity and throws * an exception to block execution. - * + * <p> * The session is not closed * * @param session The session in which to load the persistent object @@ -62,7 +62,7 @@ public class JpaUtils { runnable.run(); - session.update(persistantEntity); + session.merge(persistantEntity); session.getTransaction().commit(); session.close(); } @@ -74,7 +74,6 @@ public class JpaUtils { /** * @param persistantEntity The entity to load * @param id The identifier for the entity - * @param close If the session should be closed after consumer is executed * @param consumer The comsumer, which exposes the session */ public static void getWithSession(Object persistantEntity, Serializable id, Consumer<Session> consumer) { From 75febb97ea53702cbd1dac58ab9d82eeb76db9e1 Mon Sep 17 00:00:00 2001 From: anthorob <tony@bobert.me> Date: Sun, 14 Jul 2024 22:13:31 -0400 Subject: [PATCH 155/155] =?UTF-8?q?bump:=20version=202.0.0=20=E2=86=92=202?= =?UTF-8?q?.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cz.toml | 6 +++--- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ ci-scripts/commit_java_version.sh | 2 +- ci-scripts/prepare_java_version.sh | 2 +- pom.xml | 2 +- 5 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.cz.toml b/.cz.toml index b390a9b..946a79f 100644 --- a/.cz.toml +++ b/.cz.toml @@ -2,12 +2,12 @@ name = "cz_conventional_commits" tag_format = "$version" version_scheme = "semver" -version = "2.0.0" +version = "2.0.1" update_changelog_on_bump = true major_version_zero = false pre_bump_hooks = [ - "ci-scripts/prepare_java_version.sh" + "bash ci-scripts/prepare_java_version.sh" ] post_bump_hooks = [ - "ci-scripts/commit_java_version.sh" + "bash ci-scripts/commit_java_version.sh" ] \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8a02ef4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,29 @@ +## 2.0.1 (2024-07-14) + +### Refactor + +- fix inspection errors for deprecated calls and concatenation + +## 2.0.0 (2024-07-14) + +### BREAKING CHANGE + +- removed TrackLoader amd LoadableSongs + +### Feat + +- **Settings**: add helpers to get version number of bot + +### Fix + +- fix relection package to new path +- fix wrongly named environment variables +- bump youtube-source to 1.4.0 + +### Refactor + +- Remove unused command +- add release to Sentry config +- remove convoluted TrackLoader and LoadableSongs abstraction +- **LogHandler**: use the exception itself instead of a string for buildSentryErrorMessage +- change package path to reflect group id of pom.xml diff --git a/ci-scripts/commit_java_version.sh b/ci-scripts/commit_java_version.sh index 469a776..fedd27e 100644 --- a/ci-scripts/commit_java_version.sh +++ b/ci-scripts/commit_java_version.sh @@ -1,2 +1,2 @@ #!/bin/bash -../mvnw versions:commit \ No newline at end of file +./mvnw versions:commit diff --git a/ci-scripts/prepare_java_version.sh b/ci-scripts/prepare_java_version.sh index 9cac26b..7e41dea 100644 --- a/ci-scripts/prepare_java_version.sh +++ b/ci-scripts/prepare_java_version.sh @@ -1,2 +1,2 @@ #!/bin/bash -../mvnw versions:set -DnewVersion=$CZ_PRE_NEW_VERSION +./mvnw versions:set -DnewVersion=$CZ_PRE_NEW_VERSION diff --git a/pom.xml b/pom.xml index 6f9d2f3..8a2db6d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ <groupId>me.bobert</groupId> <artifactId>netneutrality</artifactId> - <version>2.0.0</version> + <version>2.0.1</version> <name>netneutrality-discord-bot</name> <description>Discord bot</description> <packaging>jar</packaging>