Compare commits
No commits in common. "main" and "python" have entirely different histories.
|
@ -1,8 +1,3 @@
|
||||||
.idea
|
__pycache__
|
||||||
target
|
config.ini
|
||||||
/target
|
*.swp
|
||||||
/.idea
|
|
||||||
config.yml
|
|
||||||
dependency-reduced-pom.xml
|
|
||||||
out
|
|
||||||
/out/
|
|
||||||
|
|
16
LICENSE
16
LICENSE
|
@ -1,15 +1,15 @@
|
||||||
ISC License
|
ISC License
|
||||||
|
|
||||||
Copyright (c) 2022, oko
|
Copyright (c) 2022 oko
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
copyright notice and this permission notice appear in all copies.
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,19 @@
|
||||||
|
from discord.commands import slash_command
|
||||||
|
from discord.ext import commands
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
class Fun(commands.Cog, name="Fun"):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@slash_command(name='sdate', description='Returns the current Eternal September date')
|
||||||
|
async def sdate(self, ctx):
|
||||||
|
sdate = (date.today() - date(1993, 8, 30)).days
|
||||||
|
await ctx.respond(f"Today is September {sdate}, 1993.")
|
||||||
|
|
||||||
|
@slash_command(name='random', description='Random Functions!')
|
||||||
|
async def random(self, ctx):
|
||||||
|
await ctx.respond("4") ## pretty random lol
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Fun(bot))
|
|
@ -0,0 +1,35 @@
|
||||||
|
import discord.commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from configmanager import ConfigManager, LoggingManager
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
memberlogs = int(ConfigManager.get()['Channels']['MemberLogs'])
|
||||||
|
|
||||||
|
class Moderation(commands.Cog, name='Moderation'):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.Cog.listener() # Join log
|
||||||
|
async def on_member_join(self, member):
|
||||||
|
channel = self.bot.get_channel(memberlogs)
|
||||||
|
try:
|
||||||
|
embed = discord.Embed(color=discord.Color.green(), description=f'{member.mention} | **Joined Discord**: {member.created_at.date()}', timestamp=datetime.datetime.now())
|
||||||
|
embed.set_author(name=f'{member} ({member.id})', icon_url=f'{member.display_avatar.url}?128')
|
||||||
|
embed.set_footer(text='User Left')
|
||||||
|
await channel.send(embeds=[embed])
|
||||||
|
except:
|
||||||
|
LoggingManager.log.error(f'Failed to send joinlog for {member} ({member.id}) in {channel}.')
|
||||||
|
|
||||||
|
@commands.Cog.listener() # Leave log
|
||||||
|
async def on_member_remove(self, member):
|
||||||
|
channel = self.bot.get_channel(memberlogs)
|
||||||
|
try:
|
||||||
|
embed = discord.Embed(color=discord.Color.red(), description=f'{member.mention} | **Joined Server**: {member.joined_at.date()}', timestamp=datetime.datetime.now())
|
||||||
|
embed.set_author(name=f'{member} ({member.id})', icon_url=f'{member.display_avatar.url}?128')
|
||||||
|
embed.set_footer(text='User Left')
|
||||||
|
await channel.send(embeds=[embed])
|
||||||
|
except:
|
||||||
|
LoggingManager.log.error(f'Failed to send leavelog for {member} ({member.id}) in {channel}.')
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Moderation(bot))
|
|
@ -0,0 +1,15 @@
|
||||||
|
[Bot]
|
||||||
|
Token =
|
||||||
|
Status =
|
||||||
|
|
||||||
|
[Database]
|
||||||
|
Database =
|
||||||
|
User =
|
||||||
|
Password =
|
||||||
|
Host =
|
||||||
|
Port =
|
||||||
|
|
||||||
|
[Channels]
|
||||||
|
MemberLogs =
|
||||||
|
ModLogs =
|
||||||
|
Skynet =
|
|
@ -0,0 +1,17 @@
|
||||||
|
import configparser
|
||||||
|
import logging
|
||||||
|
|
||||||
|
class LoggingManager():
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
class ConfigManager():
|
||||||
|
def get():
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read('config.ini')
|
||||||
|
return config
|
||||||
|
|
||||||
|
def set():
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read('config.ini')
|
||||||
|
return config
|
|
@ -0,0 +1,18 @@
|
||||||
|
import discord
|
||||||
|
from configmanager import ConfigManager, LoggingManager
|
||||||
|
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.members = True
|
||||||
|
|
||||||
|
bot = discord.Bot(intents=intents)
|
||||||
|
token = ConfigManager.get()['Bot']['Token']
|
||||||
|
|
||||||
|
class Kiafumi(discord.Bot):
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
LoggingManager.log.info(f'Logged on as {bot.user}!')
|
||||||
|
|
||||||
|
for ext in ['commands.fun', 'commands.moderation']:
|
||||||
|
bot.load_extension(ext)
|
||||||
|
|
||||||
|
bot.run(token) # token
|
|
@ -0,0 +1,18 @@
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
|
class Database:
|
||||||
|
def __init__(self, db, user, password, host, port, init):
|
||||||
|
if host == 0:
|
||||||
|
host = "localhost"
|
||||||
|
|
||||||
|
if port == 0:
|
||||||
|
port = 5432
|
||||||
|
|
||||||
|
__conn = psycopg.connect(dbname=db, user=user, password=password, host=host, port=port)
|
||||||
|
cur = __conn.cursor
|
||||||
|
|
||||||
|
def write():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def read():
|
||||||
|
pass
|
143
pom.xml
143
pom.xml
|
@ -1,143 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
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>moe.oko</groupId>
|
|
||||||
<artifactId>Kiafumi</artifactId>
|
|
||||||
<name>Kiafumi</name>
|
|
||||||
<version>0.9.0</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<url>https://oko.moe/kiafumi.htm</url>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jdk.version>17</project.jdk.version>
|
|
||||||
<mainclass>moe.oko.Kiafumi.Kiafumi</mainclass>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<!-- JDA (https://mvnrepository.com/artifact/net.dv8tion/JDA) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.dv8tion</groupId>
|
|
||||||
<artifactId>JDA</artifactId>
|
|
||||||
<version>5.0.0-alpha.9</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
<type>jar</type>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.carleslc.Simple-YAML</groupId>
|
|
||||||
<artifactId>Simple-Yaml</artifactId>
|
|
||||||
<version>1.7.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-api</artifactId>
|
|
||||||
<version>2.19.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-core</artifactId>
|
|
||||||
<version>2.19.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-slf4j-impl</artifactId>
|
|
||||||
<version>2.19.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sedmelluq</groupId>
|
|
||||||
<artifactId>lavaplayer</artifactId>
|
|
||||||
<version>1.3.53</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<version>8.0.30</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.zaxxer</groupId>
|
|
||||||
<artifactId>HikariCP</artifactId>
|
|
||||||
<version>5.0.1</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- DDG api (https://github.com/nstrydom2/duckduckgo-api) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.nstrydom2</groupId>
|
|
||||||
<artifactId>duckduckgo-api</artifactId>
|
|
||||||
<version>v0.1.2</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- Class Loading API for Command Loading -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
<version>31.1-jre</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>jitpack.io</id>
|
|
||||||
<url>https://jitpack.io</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>jcenter</id>
|
|
||||||
<url>https://jcenter.bintray.com/</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>central</id>
|
|
||||||
<name>bintray</name>
|
|
||||||
<url>https://jcenter.bintray.com</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>maven_central</id>
|
|
||||||
<name>Maven Central</name>
|
|
||||||
<url>https://repo.maven.apache.org/maven2/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.jdk.version}</source>
|
|
||||||
<target>${project.jdk.version}</target>
|
|
||||||
<compilerVersion>${project.jdk.version}</compilerVersion>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.2.4</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<index>true</index>
|
|
||||||
<manifest>
|
|
||||||
<addClasspath>true</addClasspath>
|
|
||||||
<mainClass>${mainclass}</mainClass>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
33
readme.md
33
readme.md
|
@ -1,35 +1,12 @@
|
||||||
# Kiafumi
|
# Kiafumi
|
||||||
|
|
||||||
A kitchen-sink discord bot designed to replace [Skyra](https://skyra.pw) v7 for use in the [HC](https://discord.gg/utgAEV2) network.
|
A kitchen-sink discord bot designed to replace [Skyra](https://skyra.pw) v7 for use in the [HC](https://discord.gg/utgAEV2) network.
|
||||||
|
|
||||||
It's written in Java, using [JDA](https://github.com/DV8FromTheWorld/JDA).
|
It's written in [Pycord](https://pycord.dev) and is intended to be resource conscious where possible.
|
||||||
|
|
||||||
## Features
|
### Credits & Thanks
|
||||||
|
+ [oko](https://oko.moe) (Development)
|
||||||
+ The expected utility command suite.
|
+ [Tiddy](https://tiddy.oko.moe) (Development)
|
||||||
+ Music functionality using Lavaplayer.
|
|
||||||
+ Member Leave/Join logging.
|
|
||||||
+ Channel/Conversation archival and export.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. Download from the [Releases](https://fem.mint.lgbt/oko/kiafumi/releases), or compile with `maven clean package`.
|
|
||||||
2. Run `Kiafumi-x.x.jar` in an empty directory.
|
|
||||||
3. Create a new MariaDB(**Not** MySQL) database.
|
|
||||||
4. Open and configure the generated `config.yml`.
|
|
||||||
5. Run `Kiafumi-x.x.jar` again.
|
|
||||||
|
|
||||||
## Credits & Thanks
|
|
||||||
|
|
||||||
+ [oko](https://oko.moe)
|
|
||||||
+ [Tiddy](https://tiddy.38.fail)
|
|
||||||
+ [Laika](http://alpinia.link), for writing the groundwork of the Java fork.
|
|
||||||
+ [Favna](https://favware.tech), for maintaining [Ribbon](https://github.com/favna/ribbon) from 2017-2019, & Skyra to this day!
|
+ [Favna](https://favware.tech), for maintaining [Ribbon](https://github.com/favna/ribbon) from 2017-2019, & Skyra to this day!
|
||||||
|
|
||||||
### Feedback
|
### License
|
||||||
|
|
||||||
Feedback from anyone, from bug reports to feature requests, is greatly encouraged. You can contact us with the [Issues](https://fem.mint.lgbt/oko/kiafumi/issues) page, or reach `oko#0994` on discord.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Copyright © 2022 oko, under the [ISC License](./LICENSE)
|
Copyright © 2022 oko, under the [ISC License](./LICENSE)
|
|
@ -0,0 +1,2 @@
|
||||||
|
py-cord
|
||||||
|
psycopg2-binary
|
|
@ -1,252 +0,0 @@
|
||||||
package moe.oko.Kiafumi;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.command.CommandRegistrar;
|
|
||||||
import moe.oko.Kiafumi.listener.MainListener;
|
|
||||||
import moe.oko.Kiafumi.listener.SkynetListener;
|
|
||||||
import moe.oko.Kiafumi.model.db.KiafumiDB;
|
|
||||||
import moe.oko.Kiafumi.model.ServerManager;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.JDA;
|
|
||||||
import net.dv8tion.jda.api.JDABuilder;
|
|
||||||
import net.dv8tion.jda.api.OnlineStatus;
|
|
||||||
import net.dv8tion.jda.api.entities.Activity;
|
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
|
|
||||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
|
||||||
import net.dv8tion.jda.api.utils.ChunkingFilter;
|
|
||||||
import net.dv8tion.jda.api.utils.MemberCachePolicy;
|
|
||||||
import net.dv8tion.jda.api.utils.cache.CacheFlag;
|
|
||||||
import org.simpleyaml.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kiafumi Main Class
|
|
||||||
* @author Kay, oko, Tiddy
|
|
||||||
* @version 0.9.0-pre
|
|
||||||
* @apiNote Thanks to:
|
|
||||||
* | Maxopoly, Orinnari, ProgrammerDan, and more, for helping teach Kay how to code Java from scratch.
|
|
||||||
* | Favna, and the HC Development community for encouraging the development core of HC.
|
|
||||||
* | HC as a whole, for being a wonderful community and encouraging the creation of this bot
|
|
||||||
* | Civ, for encouraging us all to sort out how the hell programming works
|
|
||||||
* | Discord, for offering a platform to learn these skills on
|
|
||||||
* | The Java Development Team, for making a Language I personally love and adore - Kay
|
|
||||||
*/
|
|
||||||
public class Kiafumi {
|
|
||||||
|
|
||||||
private final File CONFIG_FILE = new File("config.yml");
|
|
||||||
|
|
||||||
public YamlConfiguration yamlConfiguration = new YamlConfiguration();
|
|
||||||
|
|
||||||
public String footer = EmbedUI.BRAND + " 0.9.0-pre";
|
|
||||||
|
|
||||||
public static Kiafumi instance;
|
|
||||||
|
|
||||||
public static JDA JDA;
|
|
||||||
|
|
||||||
public List<CommandClass> activeCommands;
|
|
||||||
|
|
||||||
public KiafumiConfig config;
|
|
||||||
|
|
||||||
public KiafumiDB database;
|
|
||||||
public ServerManager serverManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main Class function.
|
|
||||||
* @param args - Arguments for program start.
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
var kia = new Kiafumi();
|
|
||||||
kia.start();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.out.println("Failed to start Kiafumi, check your Java installation.");
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ran on program start. Anything in here can determine whether the program will start.
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
instance = this;
|
|
||||||
info("Starting Kiafumi.");
|
|
||||||
|
|
||||||
// All commands to be loaded on startup!
|
|
||||||
activeCommands = new CommandRegistrar().getCommandClasses();
|
|
||||||
|
|
||||||
// Ensuring the configuration file is generated and/or exists.
|
|
||||||
if (!CONFIG_FILE.exists()) {
|
|
||||||
try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("config.yml")) {
|
|
||||||
// Save the default config
|
|
||||||
Files.copy(is, CONFIG_FILE.toPath());
|
|
||||||
} catch (Exception ex) {
|
|
||||||
warn("Failed to create the configuration file. Stopping. (" + CONFIG_FILE.getAbsolutePath() + ")");
|
|
||||||
ex.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load configuration into the configuration API.
|
|
||||||
try {
|
|
||||||
yamlConfiguration.load("config.yml");
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
warn("File not found, must've failed to create...");
|
|
||||||
} catch (Exception e) {
|
|
||||||
warn("Ensure all values are inputted properly.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes our configuration helper & ensures it loads properly.
|
|
||||||
config = new KiafumiConfig(yamlConfiguration);
|
|
||||||
if(config.load()) {
|
|
||||||
info("Fetched Kiafumi config.");
|
|
||||||
} else {
|
|
||||||
error("Failed to load configuration. Stopping process.");
|
|
||||||
Runtime.getRuntime().exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registers the stop() function if the program is stopped.
|
|
||||||
info("Registering shutdown hook.");
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
|
|
||||||
|
|
||||||
// Initializes database and loads credentials.
|
|
||||||
database = config.createDb();
|
|
||||||
|
|
||||||
serverManager = new ServerManager();
|
|
||||||
|
|
||||||
// Makes our JDA instance.
|
|
||||||
startDiscord();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ran on program shutdown.
|
|
||||||
*/
|
|
||||||
public void stop() {
|
|
||||||
var build = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.FAILURE)
|
|
||||||
.setTitle("Offline")
|
|
||||||
.setFooter(footer)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
JDA.getTextChannelById(config.getLogChannel()).sendMessageEmbeds(build.build()).queue();
|
|
||||||
info("Shutting down Kiafumi.");
|
|
||||||
if(database.saveServerInformation()) {
|
|
||||||
info("Successfully saved server information. Shutting down peacefully.");
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < 15; i++) {
|
|
||||||
error("FAILED TO SAVE SERVER INFORMATION.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a JDA Instance.
|
|
||||||
*/
|
|
||||||
public void startDiscord() {
|
|
||||||
try {
|
|
||||||
JDA = JDABuilder.create(config.getToken(), GatewayIntent.GUILD_MEMBERS,
|
|
||||||
GatewayIntent.GUILD_MESSAGES,
|
|
||||||
GatewayIntent.DIRECT_MESSAGES, GatewayIntent.GUILD_PRESENCES, GatewayIntent.GUILD_VOICE_STATES)
|
|
||||||
.setChunkingFilter(ChunkingFilter.ALL)
|
|
||||||
.setMemberCachePolicy(MemberCachePolicy.ALL)
|
|
||||||
.disableCache(CacheFlag.EMOTE)
|
|
||||||
.setActivity(Activity.of(Activity.ActivityType.valueOf(config.getActivityType()), config.getActivityMsg()))
|
|
||||||
.setStatus(OnlineStatus.valueOf(config.getStatusType()))
|
|
||||||
.addEventListeners(
|
|
||||||
new MainListener(),
|
|
||||||
new SkynetListener()
|
|
||||||
).build().awaitReady();
|
|
||||||
} catch(Exception ex) {
|
|
||||||
error("Initialization broke...");
|
|
||||||
ex.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerAllCommands();
|
|
||||||
info("Finished registering commands.");
|
|
||||||
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setTitle("Online")
|
|
||||||
.setFooter(footer)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
JDA.getTextChannelById(config.getLogChannel()).sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quick method to register commands in all servers.
|
|
||||||
*/
|
|
||||||
private void registerAllCommands() {
|
|
||||||
// Registers slash commands.
|
|
||||||
info("Registering commands for guilds.");
|
|
||||||
int i = 0;
|
|
||||||
for(Guild guild : JDA.getGuilds()) {
|
|
||||||
registerForGuild(guild);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
info("Registered commands for " + i + " guilds.");
|
|
||||||
|
|
||||||
// Registers the event listeners for those commands.
|
|
||||||
for(CommandClass cmd : activeCommands) {
|
|
||||||
JDA.addEventListener(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers all bot commands with the guild provided
|
|
||||||
* @param guild - guild to have commands provided to
|
|
||||||
*/
|
|
||||||
public void registerForGuild(Guild guild) {
|
|
||||||
debug("Registering commands for guild [" + guild.getName() + ":" + guild.getId() + "]");
|
|
||||||
int i = 0;
|
|
||||||
int j = 0;
|
|
||||||
for(CommandClass cmd : activeCommands) {
|
|
||||||
for(CommandInfo ci : cmd.getSlashCommandInfo()) {
|
|
||||||
var cca = guild.upsertCommand(ci.getName(), ci.getDescription());
|
|
||||||
i++;
|
|
||||||
if(ci.hasSubCommands()) {
|
|
||||||
for (String name : ci.getSubCommands().keySet()) {
|
|
||||||
var si = ci.getSubCommands().get(name);
|
|
||||||
var sd = new SubcommandData(si.getName(), si.getDescription());
|
|
||||||
for (String option : si.getOptions().keySet()) {
|
|
||||||
sd.addOption(si.getOptions().get(option), option, si.getOptionDescriptions().get(option), si.getOptionRequirements().get(option));
|
|
||||||
}
|
|
||||||
cca.addSubcommands(sd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ci.hasOptions()) {
|
|
||||||
for(String name : ci.getOptions().keySet()) {
|
|
||||||
// Any intelligent IDE will rage about the option not being used, it's added to the action then executed later, don't edit without reason.
|
|
||||||
cca.addOption(ci.getOptions().get(name), name, ci.getOptionDescriptions().get(name), ci.getOptionRequirements().get(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Push w/ modifications.
|
|
||||||
//trace("Command: " + ci.getName() + " registration on " + guild.getId() + " completed.");
|
|
||||||
try {
|
|
||||||
cca.queue();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// Only time this should occur is when a server does not have the proper scope.
|
|
||||||
error("Failed to queue command for RestAction.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug("Registered " + i + " commands for guild [" + guild.getId() + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the active database.
|
|
||||||
public KiafumiDB getDatabase() { return database; }
|
|
||||||
|
|
||||||
// Gets active ServerManager
|
|
||||||
public ServerManager getServerManager() { return serverManager; }
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
package moe.oko.Kiafumi;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.model.db.DBCredentials;
|
|
||||||
import moe.oko.Kiafumi.model.db.KiafumiDB;
|
|
||||||
import org.simpleyaml.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.error;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.info;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KiafumiConfig class
|
|
||||||
* Helps out with loading things from config and fetching them in an easy manner.
|
|
||||||
*/
|
|
||||||
public class KiafumiConfig {
|
|
||||||
|
|
||||||
// Setup
|
|
||||||
public YamlConfiguration configuration;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Discord Variable Section
|
|
||||||
*/
|
|
||||||
private String token;
|
|
||||||
private String logChannel;
|
|
||||||
private String ownerId;
|
|
||||||
private String mainGuild;
|
|
||||||
private String clientId;
|
|
||||||
private int defaultInvitePermissionLevel;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Kia Variable Section
|
|
||||||
*/
|
|
||||||
private String activityType;
|
|
||||||
private String activityMsg;
|
|
||||||
private String statusType;
|
|
||||||
private List<String> pingResponses;
|
|
||||||
|
|
||||||
/*
|
|
||||||
SQL Variable Section
|
|
||||||
*/
|
|
||||||
private String host;
|
|
||||||
private int port;
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
private String database;
|
|
||||||
private int poolSize;
|
|
||||||
private long connTimeout;
|
|
||||||
private long idleTimeout;
|
|
||||||
private long maxLifetime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the config.
|
|
||||||
* @param configuration - the configuration file to be passed through in our friendly YamlConfiguration API :)
|
|
||||||
*/
|
|
||||||
public KiafumiConfig(YamlConfiguration configuration) {
|
|
||||||
//Load config on class creation...
|
|
||||||
this.configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all configuration values from config.yml
|
|
||||||
* @return - whether the values were loaded successfully.
|
|
||||||
* Note: this function will perpetually be a mess, there is definitely a better way to do this,
|
|
||||||
* but I refuse to do it a better way because it is EASY this way.
|
|
||||||
*/
|
|
||||||
public boolean load() {
|
|
||||||
try {
|
|
||||||
// Discord loaders
|
|
||||||
var discord = configuration.getConfigurationSection("discord");
|
|
||||||
token = discord.getString("token"); // This used to log the token into stdout ???
|
|
||||||
logChannel = discord.getString("logChannel");
|
|
||||||
ownerId = discord.getString("ownerId");
|
|
||||||
mainGuild = discord.getString("mainGuild");
|
|
||||||
clientId = discord.getString("clientId");
|
|
||||||
defaultInvitePermissionLevel = discord.getInt("invitePermissionLevel");
|
|
||||||
// Log discord settings in a neat table.
|
|
||||||
info("""
|
|
||||||
Printing loaded discord configuration.
|
|
||||||
DISCORD CONFIGURATION
|
|
||||||
--------------------------------
|
|
||||||
Log Channel: %s
|
|
||||||
Owner ID: %s
|
|
||||||
Primary Guild: %s
|
|
||||||
Invite URL: %s
|
|
||||||
--------------------------------""".formatted(logChannel, ownerId, mainGuild, assembleDefaultInvite()));
|
|
||||||
|
|
||||||
// Kiafumi loaders
|
|
||||||
var main = configuration.getConfigurationSection("main");
|
|
||||||
activityType = main.getString("activityType");
|
|
||||||
activityMsg = main.getString("activityMsg");
|
|
||||||
statusType = main.getString("statusType");
|
|
||||||
pingResponses = main.getStringList("pingResponses");
|
|
||||||
|
|
||||||
// SQL loaders
|
|
||||||
var sql = configuration.getConfigurationSection("sql");
|
|
||||||
host = sql.getString("host");
|
|
||||||
port = sql.getInt("port");
|
|
||||||
username = sql.getString("username");
|
|
||||||
password = sql.getString("password");
|
|
||||||
database = sql.getString("database");
|
|
||||||
poolSize = sql.getInt("poolSize");
|
|
||||||
connTimeout = sql.getLong("connectionTimeout");
|
|
||||||
idleTimeout = sql.getLong("idleTimeout");
|
|
||||||
maxLifetime = sql.getLong("maxLifetime");
|
|
||||||
|
|
||||||
} catch(Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
error("Failed to load configuration!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assembles the default invite that can be passed to a user requesting it.
|
|
||||||
* @return - the invite
|
|
||||||
*/
|
|
||||||
public String assembleDefaultInvite() {
|
|
||||||
return "https://discord.com/oauth2/authorize?client_id=" + clientId + "&scope=bot+applications.commands&permissions=" + defaultInvitePermissionLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getToken() { return token; }
|
|
||||||
|
|
||||||
public String getActivityType() { return activityType; }
|
|
||||||
|
|
||||||
public String getActivityMsg() { return activityMsg; }
|
|
||||||
|
|
||||||
public String getStatusType() { return statusType; }
|
|
||||||
|
|
||||||
public String getLogChannel() { return logChannel; }
|
|
||||||
|
|
||||||
public List<String> getPingResponses() { return pingResponses; }
|
|
||||||
|
|
||||||
public DBCredentials getCredentials () { return new DBCredentials(
|
|
||||||
username, password, host, port, database, poolSize, connTimeout, idleTimeout, maxLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KiafumiDB createDb() { return new KiafumiDB(getCredentials()); }
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CommandClass Abstract Class
|
|
||||||
* Use this for any commands you make, and ensure they go under the .command class.
|
|
||||||
*/
|
|
||||||
public abstract class CommandClass extends ListenerAdapter {
|
|
||||||
|
|
||||||
//Is the command enabled?
|
|
||||||
public abstract boolean isEnabled();
|
|
||||||
|
|
||||||
//Whats the name of the Command Package (Specify if multiple, like "Utility" or "Moderation")
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For new slash commands
|
|
||||||
* @param name - name of the command executed
|
|
||||||
* @param e - SlashCommandInteractionEvent, used for all references.
|
|
||||||
*/
|
|
||||||
public abstract void newCommand(String name, SlashCommandInteractionEvent e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overriding our SlashCommandInteractionEvent that way it can execute a cmd.
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
|
|
||||||
newCommand(event.getName(), event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Also for the sake of organization. To upsert slash commands.
|
|
||||||
* Follow as name, description. (for upsertCommand(name, description);
|
|
||||||
* @return - The name and description for the commands contained within the class.
|
|
||||||
*/
|
|
||||||
public abstract List<CommandInfo> getSlashCommandInfo();
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command;
|
|
||||||
|
|
||||||
import com.google.common.reflect.ClassPath;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.error;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.info;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.debug;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CommandRegistrar Class
|
|
||||||
* Used for easy command package loading, we use this to avoid having 20 lines of list.add() methods.
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class CommandRegistrar {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates all classes that contain the package name provided. Use CAREFULLY.
|
|
||||||
* @param packageName - the name of the package to look for
|
|
||||||
* @return - A set of classes that contain that package name.
|
|
||||||
*/
|
|
||||||
public Set<Class> findAllClassesContaining(String packageName) {
|
|
||||||
try {
|
|
||||||
return ClassPath.from(ClassLoader.getSystemClassLoader())
|
|
||||||
.getAllClasses()
|
|
||||||
.stream()
|
|
||||||
.filter(clazz -> clazz.getPackageName()
|
|
||||||
.contains(packageName))
|
|
||||||
.map(clazz -> clazz.load())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
} catch (Exception ex) {
|
|
||||||
error("Failed to load classes containing " + packageName + ", check stack.");
|
|
||||||
ex.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utilizes findAllClassesContaining() to find all command classes and return them in a simple manner.
|
|
||||||
* @return - The CommandClass's located.
|
|
||||||
*/
|
|
||||||
public List<CommandClass> getCommandClasses() {
|
|
||||||
try {
|
|
||||||
// TODO have this check the classpath that we're under and have it scan *that* instead of hard-coding it to only be moe.oko.Kiafumi path.
|
|
||||||
var classes = findAllClassesContaining("moe.oko.Kiafumi.command");
|
|
||||||
List<CommandClass> commands = new ArrayList<>();
|
|
||||||
debug("Discovered " + classes.size() + " classes containing moe.oko.Kiafumi.command in package class.");
|
|
||||||
for (Class clazz : classes) {
|
|
||||||
for (Constructor cnstr : clazz.getConstructors()) {
|
|
||||||
try {
|
|
||||||
var obj = cnstr.newInstance(); // making an attempt.
|
|
||||||
if (obj instanceof CommandClass) {
|
|
||||||
debug("Loading command class %green(" + cnstr.getName() + ").");
|
|
||||||
commands.add((CommandClass) obj);
|
|
||||||
}
|
|
||||||
} catch (InstantiationException ex) {
|
|
||||||
// Ignore, this is just us trying to load the CommandClass abstract class.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info("Loaded [" + commands.size() + "] command classes.");
|
|
||||||
return commands;
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException exception) {
|
|
||||||
// Now we don't ignore, this is a core issue.
|
|
||||||
exception.printStackTrace();
|
|
||||||
error("Failure in command class loading.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.fun;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dreidel Dreidel...
|
|
||||||
* @author Tiddy
|
|
||||||
*/
|
|
||||||
public class DreidelCommand extends CommandClass {
|
|
||||||
private final List<String> sides;
|
|
||||||
|
|
||||||
public DreidelCommand() {
|
|
||||||
List<String> sides = new ArrayList<>();
|
|
||||||
sides.add("Nun");
|
|
||||||
sides.add("Gimmel");
|
|
||||||
sides.add("Hay");
|
|
||||||
sides.add("Shin");
|
|
||||||
this.sides = sides;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() { return true; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() { return "Dreidel"; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("dreidel".equals(name)) {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("Spinning...")
|
|
||||||
.setDescription("*brrrrrrrrrrrrrr*")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
var rand = new Random();
|
|
||||||
var result = sides.get(rand.nextInt(sides.size()));
|
|
||||||
var eb1 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("You rolled...")
|
|
||||||
.setDescription(result + "!")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().editOriginalEmbeds(eb1.build()).completeAfter(3, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> si = new ArrayList<>();
|
|
||||||
si.add(new CommandInfo("dreidel", "Spins a dreidel!", CommandType.COMMAND));
|
|
||||||
return si;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.fun;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.entities.User;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Random User Choice Command
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class FightCommand extends CommandClass {
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Fight";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("fight".equals(name)) {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
List<User> usersForRng = new ArrayList<>();
|
|
||||||
List<String> userNames = new ArrayList<>();
|
|
||||||
for (OptionMapping option : e.getOptions()) {
|
|
||||||
usersForRng.add(option.getAsUser());
|
|
||||||
userNames.add(option.getAsUser().getName());
|
|
||||||
}
|
|
||||||
// Done, now roll
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("Match in progress...")
|
|
||||||
.setDescription("*POW! KABLAM! SCHNARF!*")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
var rng = new Random();
|
|
||||||
var pickedUser = usersForRng.get(rng.nextInt(usersForRng.size()));
|
|
||||||
var eb1 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("FATALITY!")
|
|
||||||
.setDescription(pickedUser.getName() + " wins!")
|
|
||||||
.setThumbnail(pickedUser.getAvatarUrl())
|
|
||||||
.setFooter(EmbedUI.BRAND) // TODO: Make this show the list of participants
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().editOriginalEmbeds(eb1.build()).completeAfter(3, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
var ci = new CommandInfo("fight", "MORTALLL KOMBATTTT", CommandType.COMMAND);
|
|
||||||
ci.addOption("value1", "first fighter", OptionType.USER, true);
|
|
||||||
ci.addOption("value2", "second fighter", OptionType.USER, true);
|
|
||||||
ci.addOption("value3", "third fighter", OptionType.USER, false);
|
|
||||||
ci.addOption("value4", "fourth fighter", OptionType.USER, false);
|
|
||||||
cil.add(ci);
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.fun;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.Month;
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the REAL date
|
|
||||||
* @author oko
|
|
||||||
*/
|
|
||||||
public class SeptemberDateCommand extends CommandClass {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() { return true; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() { return "SeptemberDate"; }
|
|
||||||
|
|
||||||
final LocalDate september = LocalDate.of(1993, Month.AUGUST, 31);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("sdate".equals(name)) {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
|
|
||||||
var now = LocalDate.now();
|
|
||||||
|
|
||||||
// Create the Eternal September date
|
|
||||||
var sdate = ChronoUnit.DAYS.between(september, now);
|
|
||||||
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("sdate")
|
|
||||||
.setDescription("Today is September, " + sdate + " 1993, the september that never ends")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
cil.add(new CommandInfo("sdate", "Returns the Eternal September date.", CommandType.COMMAND));
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.image;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helpful Avatar grabber command
|
|
||||||
* @author oko
|
|
||||||
*/
|
|
||||||
public class AvatarCommand extends CommandClass {
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() { return true; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() { return "Avatar"; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("avatar".equals(name)) {
|
|
||||||
e.deferReply().queue();
|
|
||||||
|
|
||||||
final var user = e.getOptions().size() == 0
|
|
||||||
? e.getUser()
|
|
||||||
: e.getOption("user").getAsUser();
|
|
||||||
slashLog(e, "for user [" + user.getName() + ":" + user.getId() + "]." );
|
|
||||||
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setAuthor(user.getName() + "#" + user.getDiscriminator())
|
|
||||||
.setImage(user.getEffectiveAvatarUrl() + "?size=2048")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
var ci = new CommandInfo("avatar", "Returns the avatar of the specified user.", CommandType.COMMAND);
|
|
||||||
ci.addOption("user", "User to fetch.", OptionType.USER, false);
|
|
||||||
cil.add(ci);
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,234 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.music;
|
|
||||||
|
|
||||||
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 moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.model.audio.AudioInfo;
|
|
||||||
import moe.oko.Kiafumi.model.audio.AudioPlayerSendHandler;
|
|
||||||
import moe.oko.Kiafumi.model.audio.TrackManager;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.Permission;
|
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.info;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Music Command
|
|
||||||
* Some code may be taken from SHIRO Project (ISC License still applies)
|
|
||||||
* @author Kay, oko
|
|
||||||
*/
|
|
||||||
public class MusicCommand extends CommandClass {
|
|
||||||
|
|
||||||
private final AudioPlayerManager audioPlayerManager = new DefaultAudioPlayerManager();
|
|
||||||
private final Map<String, Map.Entry<AudioPlayer, TrackManager>> players = new HashMap<>();
|
|
||||||
|
|
||||||
public MusicCommand() { AudioSourceManagers.registerRemoteSources(audioPlayerManager); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() { return true; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() { return "Music"; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
switch (name) {
|
|
||||||
case "play" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
var input = e.getOption("url").getAsString();
|
|
||||||
slashLog(e, "with search \"%s\".".formatted(input));
|
|
||||||
|
|
||||||
if(input.startsWith("https://"))
|
|
||||||
loadTrack(input, e.getMember(), e.getHook());
|
|
||||||
else
|
|
||||||
loadTrack("ytsearch: " + input, e.getMember(), e.getHook());
|
|
||||||
}
|
|
||||||
case "skip" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
slashLog(e);
|
|
||||||
if (isAdmin(e.getMember())) {
|
|
||||||
getPlayer(e.getGuild()).stopTrack();
|
|
||||||
e.getHook().sendMessage("Skipping the current track.").queue();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var info = getTrackManager(e.getGuild()).getTrackInfo(getPlayer(e.getGuild()).getPlayingTrack());
|
|
||||||
if (info.hasVoted(e.getUser()))
|
|
||||||
e.getHook().setEphemeral(true).sendMessage("You've already voted to skip this track.");
|
|
||||||
else {
|
|
||||||
int votes = info.getSkips();
|
|
||||||
int users = info.getAuthor().getVoiceState().getChannel().getMembers().size()-1;
|
|
||||||
int requiredVotes = users/2;
|
|
||||||
if (votes > requiredVotes) {
|
|
||||||
getPlayer(e.getGuild()).stopTrack();
|
|
||||||
e.getHook().sendMessage("Skipping the current track.").queue();
|
|
||||||
} else {
|
|
||||||
info.addSkip(e.getUser());
|
|
||||||
e.getHook().sendMessage("**%s** has voted to skip the track (%s/%s)"
|
|
||||||
.formatted(e.getUser().getName(), votes, requiredVotes)).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "nowplaying" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
slashLog(e);
|
|
||||||
if (!hasPlayer(e.getGuild()) || getPlayer(e.getGuild()).getPlayingTrack() == null)
|
|
||||||
e.getHook().sendMessage("No song is currently playing.").queue();
|
|
||||||
else {
|
|
||||||
var track = getPlayer(e.getGuild()).getPlayingTrack().getInfo();
|
|
||||||
e.getHook().sendMessageEmbeds(new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setAuthor("Now playing")
|
|
||||||
.setDescription("[%s](%s)".formatted(track.title, track.uri))
|
|
||||||
.addField("Info", "Channel: %s\nLength: %s".formatted(track.author, getTimestamp(track.length)), false)
|
|
||||||
.setFooter("Requested by: " + e.getUser().getName()).build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "queue" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
slashLog(e);
|
|
||||||
if (!hasPlayer(e.getGuild()) || getTrackManager(e.getGuild()).getQueuedTracks().isEmpty())
|
|
||||||
e.getHook().sendMessage("There is nothing queued.").queue();
|
|
||||||
else {
|
|
||||||
var trackList = new StringBuilder();
|
|
||||||
var queuedTracks = getTrackManager(e.getGuild()).getQueuedTracks();
|
|
||||||
final short[] trackSize = {-1};
|
|
||||||
queuedTracks.forEach(audioInfo -> {
|
|
||||||
trackList.append(buildQueueString(audioInfo));
|
|
||||||
trackSize[0]++;
|
|
||||||
});
|
|
||||||
var eb = new EmbedBuilder().setColor(EmbedUI.SUCCESS);
|
|
||||||
if (trackList.length() >= 990) {
|
|
||||||
eb.addField("Queue", "**>** " + trackList.toString(), false);
|
|
||||||
} else {
|
|
||||||
eb.addField("Queue", "**>** " + getPlayer(e.getGuild()).getPlayingTrack().getInfo().title
|
|
||||||
+ "\n" + trackSize[0] + " other tracks..", false).build();
|
|
||||||
}
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadTrack(String input, Member author, InteractionHook hook) {
|
|
||||||
if (author.getVoiceState().getChannel() == null) {
|
|
||||||
hook.setEphemeral(true).sendMessage("You are not in a voice channel.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var server = author.getGuild();
|
|
||||||
getPlayer(server);
|
|
||||||
audioPlayerManager.loadItemOrdered(server, input, new AudioLoadResultHandler() {
|
|
||||||
EmbedBuilder eb;
|
|
||||||
@Override
|
|
||||||
public void trackLoaded(AudioTrack audioTrack) {
|
|
||||||
var trackInfo = audioTrack.getInfo();
|
|
||||||
eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setAuthor("Playing")
|
|
||||||
.setDescription("[%s](%s)".formatted(trackInfo.title, trackInfo.uri))
|
|
||||||
.addField("Info", "Channel: %s\nLength: %s".formatted(trackInfo.author, getTimestamp(trackInfo.length)), false)
|
|
||||||
.setFooter("Requested by: " + author.getEffectiveName());
|
|
||||||
hook.sendMessageEmbeds(eb.build()).queue();
|
|
||||||
getTrackManager(server).queue(audioTrack, author);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playlistLoaded(AudioPlaylist audioPlaylist) {
|
|
||||||
if (input.startsWith("ytsearch:")) {
|
|
||||||
getTrackManager(server).queue(audioPlaylist.getTracks().get(0), author);
|
|
||||||
var trackInfo = audioPlaylist.getTracks().get(0).getInfo();
|
|
||||||
eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setAuthor("Playing")
|
|
||||||
.setDescription("[%s](%s)".formatted(trackInfo.title, trackInfo.uri))
|
|
||||||
.addField("Info", "Channel: %s\nLength: %s".formatted(trackInfo.author, getTimestamp(trackInfo.length)), false)
|
|
||||||
.setFooter("Requested by: " + author.getEffectiveName());
|
|
||||||
} else {
|
|
||||||
for (AudioTrack audioTrack : audioPlaylist.getTracks()) {
|
|
||||||
getTrackManager(server).queue(audioTrack, author);
|
|
||||||
eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setAuthor("Loaded tracks")
|
|
||||||
.setDescription("**%s** tracks added to the queue.".formatted(audioPlaylist.getTracks().size()))
|
|
||||||
.setFooter("Requested by: " + author.getEffectiveName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hook.sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void noMatches() {
|
|
||||||
eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.FAILURE)
|
|
||||||
.setAuthor("Error")
|
|
||||||
.setDescription("No matches were found.");
|
|
||||||
hook.sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadFailed(FriendlyException e) { hook.sendMessage("Unable to play track.").queue(); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private TrackManager getTrackManager(Guild server) { return players.get(server.getId()).getValue(); }
|
|
||||||
|
|
||||||
private AudioPlayer getPlayer(Guild server) {
|
|
||||||
var player = hasPlayer(server) ? players.get(server.getId()).getKey() : createPlayer(server);
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AudioPlayer createPlayer(Guild server) {
|
|
||||||
var newPlayer = audioPlayerManager.createPlayer();
|
|
||||||
var manager = new TrackManager(newPlayer);
|
|
||||||
newPlayer.addListener(manager);
|
|
||||||
server.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(newPlayer));
|
|
||||||
players.put(server.getId(), new AbstractMap.SimpleEntry<>(newPlayer, manager));
|
|
||||||
return newPlayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasPlayer(Guild server) { return players.containsKey(server.getId()); }
|
|
||||||
|
|
||||||
private boolean isAdmin(Member member) { return member.hasPermission(Permission.ADMINISTRATOR); }
|
|
||||||
|
|
||||||
private String getTimestamp(long ms) {
|
|
||||||
return String.format("%02d:%02d:%02d", ms/(3600*1000),
|
|
||||||
ms/(60*1000) % 60,
|
|
||||||
ms/1000 % 60);
|
|
||||||
}
|
|
||||||
private String buildQueueString(AudioInfo info) {
|
|
||||||
var trackInfo = info.getTrack().getInfo();
|
|
||||||
return "%s [%s]\n".formatted(trackInfo.title, getTimestamp(trackInfo.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
var playCommandList = new CommandInfo("play", "Adds a new track to the queue.", CommandType.COMMAND);
|
|
||||||
playCommandList.addOption("url", "The URL or title of the track you want to play.", OptionType.STRING, true);
|
|
||||||
cil.add(playCommandList);
|
|
||||||
cil.add(new CommandInfo("skip", "Votes to skip the current track.", CommandType.COMMAND));
|
|
||||||
cil.add(new CommandInfo("nowplaying", "Displays the currently played track." , CommandType.COMMAND));
|
|
||||||
cil.add(new CommandInfo("queue", "Displays the tracks currently queued.", CommandType.COMMAND));
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
import org.bitnick.net.duckduckgo.WebSearch;
|
|
||||||
import org.bitnick.net.duckduckgo.entity.SearchResult;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helpful Search Command (Uses DDG API)
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class DuckCommand extends CommandClass {
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Duck";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("search".equals(name)) {
|
|
||||||
e.deferReply().queue();
|
|
||||||
String option = e.getOption("query").getAsString();
|
|
||||||
slashLog(e, "with search \"" + option + "\".");
|
|
||||||
WebSearch ws = WebSearch.instanceOf();
|
|
||||||
SearchResult sr;
|
|
||||||
try {
|
|
||||||
sr = ws.instantAnswerSearch(option);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
EmbedBuilder eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.FAILURE)
|
|
||||||
.setTitle("Query Failed")
|
|
||||||
.setDescription("Couldn't find any results.")
|
|
||||||
.setFooter("Query: " + option)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EmbedBuilder eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle(sr.getTitle(), sr.getUrl().toString())
|
|
||||||
.setDescription(sr.getDescription())
|
|
||||||
.setFooter("Query: " + option)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
CommandInfo ci = new CommandInfo("search", "Looks up with DuckDuckGo your query!", CommandType.COMMAND);
|
|
||||||
ci.addOption("query", "The query to be searched", OptionType.STRING, true);
|
|
||||||
cil.add(ci);
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
public class HelpCommand extends CommandClass {
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Help";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("help".equalsIgnoreCase(name)) {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
// We assemble a help string, this is our description for our embed.
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
for(CommandClass cc : Kiafumi.instance.activeCommands) {
|
|
||||||
for(CommandInfo ci : cc.getSlashCommandInfo()) {
|
|
||||||
var cname = ci.getName();
|
|
||||||
var cdesc= ci.getDescription();
|
|
||||||
sb.append("**").append(cname).append("** - __").append(cdesc).append("__\n");
|
|
||||||
if(ci.hasOptions()) {
|
|
||||||
for (String opt : ci.getOptions().keySet()) {
|
|
||||||
sb.append("-> **").append(opt).append("** `").append(ci.getOptions().get(opt).name())
|
|
||||||
.append("` *").append(ci.getOptionDescriptions().get(opt)).append("*");
|
|
||||||
if (ci.getOptionRequirements().get(opt)) {
|
|
||||||
sb.append(" __***[REQUIRED]***__");
|
|
||||||
}
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ci.hasSubCommands()) {
|
|
||||||
for (String subc : ci.getSubCommands().keySet()) {
|
|
||||||
var subCommand = ci.getSubCommands().get(subc);
|
|
||||||
sb.append("-> **").append(subc).append("** *").append(subCommand.getDescription()).append("*\n");
|
|
||||||
if (subCommand.hasOptions()) {
|
|
||||||
for (String opt : subCommand.getOptions().keySet()) {
|
|
||||||
sb.append("--> **").append(opt).append("** `").append(subCommand.getOptions().get(opt).name())
|
|
||||||
.append("` *").append(subCommand.getOptionDescriptions().get(opt)).append("*");
|
|
||||||
if (subCommand.getOptionRequirements().get(opt)) {
|
|
||||||
sb.append(" __***[REQUIRED]***__");
|
|
||||||
}
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EmbedBuilder eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTimestamp(ZonedDateTime.now())
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTitle("Help Command")
|
|
||||||
.setDescription(sb.toString());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
var ci = new CommandInfo("help", "Displays all enabled commands this bot has.", CommandType.COMMAND);
|
|
||||||
cil.add(ci);
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.entities.Role;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helpful User Information Command
|
|
||||||
* @author oko
|
|
||||||
*/
|
|
||||||
public class InfoCommand extends CommandClass {
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() { return true; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() { return "Info"; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
switch (name){
|
|
||||||
case "userinfo":
|
|
||||||
e.deferReply().queue();
|
|
||||||
|
|
||||||
// Setup variables
|
|
||||||
final var member = e.getOptions().size() == 0
|
|
||||||
? e.getMember()
|
|
||||||
: e.getOption("user").getAsMember();
|
|
||||||
final var dTF = DateTimeFormatter.ofPattern("MM-dd-yyyy");
|
|
||||||
slashLog(e, "for user [" + member.getUser().getName() + ":" + member.getId() + "].");
|
|
||||||
// Build embed
|
|
||||||
EmbedBuilder eb1 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setAuthor(member.getEffectiveName() + "#" + member.getUser().getDiscriminator())
|
|
||||||
.addField("Joined Server", member.getTimeJoined().format(dTF), true)
|
|
||||||
.addField("Joined Discord", member.getTimeCreated().format(dTF), true)
|
|
||||||
.addField("Roles", member.getRoles().stream().map(Role::getName).reduce((a, b) -> a + ", " + b).orElse("None"), false)
|
|
||||||
.setThumbnail(member.getEffectiveAvatarUrl())
|
|
||||||
.setFooter("ID: " + member.getId())
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb1.build()).queue();
|
|
||||||
return;
|
|
||||||
case "serverinfo":
|
|
||||||
e.deferReply().queue();
|
|
||||||
// Setup variables
|
|
||||||
final var guild = e.getGuild();
|
|
||||||
final var dTF2 = DateTimeFormatter.ofPattern("MM-dd-yyyy");
|
|
||||||
slashLog(e, "for guild [" + guild.getId() + ":" + guild.getName() + "].");
|
|
||||||
// Build Embed
|
|
||||||
EmbedBuilder eb2 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setAuthor(guild.getName())
|
|
||||||
.addField("Members", "**" + guild.getMemberCount() + "** member(s) \n Owner: "
|
|
||||||
+ guild.getOwner().getEffectiveName() + "#" + guild.getOwner().getUser().getDiscriminator(), true)
|
|
||||||
.addField("Channels", "**" + guild.getTextChannels().size() + "** Text \n **"
|
|
||||||
+ guild.getVoiceChannels().size() + "** Voice", true)
|
|
||||||
.addField("Other", "Roles: **" + guild.getRoles().size() + "** \n"
|
|
||||||
+ "Created: " + guild.getTimeCreated().format(dTF2), true)
|
|
||||||
.setThumbnail(guild.getIconUrl())
|
|
||||||
.setFooter("ID: " + guild.getId());
|
|
||||||
e.getHook().sendMessageEmbeds(eb2.build()).queue();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
CommandInfo ci = new CommandInfo("userinfo", "Returns information about a user.", CommandType.COMMAND);
|
|
||||||
ci.addOption("user", "The user to get information about.", OptionType.USER, false);
|
|
||||||
|
|
||||||
CommandInfo ci2 = new CommandInfo("serverinfo", "Returns information about the server.", CommandType.COMMAND);
|
|
||||||
|
|
||||||
cil.add(ci);
|
|
||||||
cil.add(ci2);
|
|
||||||
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helpful Invite Command
|
|
||||||
* @author Kay, oko
|
|
||||||
*/
|
|
||||||
public class InviteCommand extends CommandClass {
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true; //Always enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Invite";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if(e.getGuild() == null) { return; }
|
|
||||||
if ("invite".equals(name)) {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
EmbedBuilder eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setAuthor("Kiafumi", "https://oko.moe/kiafumi.htm", Kiafumi.JDA.getSelfUser().getAvatarUrl())
|
|
||||||
.setTitle("Invite me to your server!", Kiafumi.instance.config.assembleDefaultInvite())
|
|
||||||
.setDescription("Alternatively, you can host me yourself!")
|
|
||||||
.appendDescription(" https://fem.mint.lgbt/oko/kiafumi")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> cil = new ArrayList<>();
|
|
||||||
CommandInfo ci = new CommandInfo("invite", "Returns an invite for Kiafumi.", CommandType.COMMAND);
|
|
||||||
cil.add(ci);
|
|
||||||
return cil;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helpful Ping Command
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class PingCommand extends CommandClass {
|
|
||||||
//Always true, ping cmd is EXISTENTIAL
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Ping";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if ("ping".equals(name.toLowerCase(Locale.ROOT))) {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
long sentMs = e.getTimeCreated().toInstant().toEpochMilli();
|
|
||||||
long recMs = System.currentTimeMillis();
|
|
||||||
long ping = recMs - sentMs;
|
|
||||||
EmbedBuilder eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle(getComedy())
|
|
||||||
.setDescription("Pong! " + ping + "ms")
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getComedy() {
|
|
||||||
Random r = new Random();
|
|
||||||
return Kiafumi.instance.config.getPingResponses().get(r.nextInt(Kiafumi.instance.config.getPingResponses().size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> si = new ArrayList<>();
|
|
||||||
CommandInfo ci = new CommandInfo("ping", "Returns bot latency with a twist!", CommandType.COMMAND);
|
|
||||||
si.add(ci);
|
|
||||||
return si;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.command.CommandClass;
|
|
||||||
import moe.oko.Kiafumi.model.Server;
|
|
||||||
import moe.oko.Kiafumi.util.CommandInfo;
|
|
||||||
import moe.oko.Kiafumi.util.CommandType;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.Permission;
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashLog;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.slashResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Permits modification of server settings, critical class to functionality.
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class SettingCommand extends CommandClass {
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true; // Another non-disable command
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Settings";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newCommand(String name, SlashCommandInteractionEvent e) {
|
|
||||||
if(e.getGuild() != null) {
|
|
||||||
Server server = Kiafumi.instance.getServerManager().getOrCreateServer(e.getGuild());
|
|
||||||
switch (name) {
|
|
||||||
case "settings" -> {
|
|
||||||
slashLog(e);
|
|
||||||
e.deferReply().queue();
|
|
||||||
// No options, just fire an embed off...
|
|
||||||
EmbedBuilder eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("Kiafumi Settings")
|
|
||||||
.setDescription(server.getOpts())
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
case "setting" -> {
|
|
||||||
// User is attempting a settings modification. Check if admin.
|
|
||||||
if(!e.getMember().hasPermission(Permission.ADMINISTRATOR) && !e.getMember().isOwner()) {
|
|
||||||
slashLog(e, EmbedUI.RESPONSE_PRIVILEGES);
|
|
||||||
e.deferReply(true).queue();
|
|
||||||
// Private reply, other people can't see this if ephemeral.
|
|
||||||
e.getHook().sendMessage("**You cannot run this command.**").queue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (e.getSubcommandName().toLowerCase()) {
|
|
||||||
case "view" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
String opt = e.getOption("name").getAsString();
|
|
||||||
slashLog(e, "with subcommand \"" + e.getSubcommandName().toLowerCase() + "\" for setting \"" + opt + "\".");
|
|
||||||
EmbedBuilder eb1 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle(opt)
|
|
||||||
.setDescription("Value: `" + server.getOptionByString(opt) + '`')
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb1.build()).queue();
|
|
||||||
}
|
|
||||||
case "set" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
String opt1 = e.getOption("name").getAsString();
|
|
||||||
String opt2 = e.getOption("value").getAsString();
|
|
||||||
slashLog(e, "with subcommand \"" + e.getSubcommandName().toLowerCase() + "\" for setting \"" + opt1 + "\" to \"" + opt2 + "\".");
|
|
||||||
String response = server.setOptionByString(opt1, opt2);
|
|
||||||
slashResponse(e, response);
|
|
||||||
EmbedBuilder eb2 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setTitle(opt1)
|
|
||||||
.setDescription(response)
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb2.build()).queue();
|
|
||||||
}
|
|
||||||
case "clear" -> {
|
|
||||||
e.deferReply().queue();
|
|
||||||
String opt3 = e.getOption("name").getAsString();
|
|
||||||
slashLog(e, "with subcommand \"" + e.getSubcommandName().toLowerCase() + "\" for setting \"" + opt3 + "\".");
|
|
||||||
String response1 = server.resetOptionByString(opt3);
|
|
||||||
slashResponse(e, response1);
|
|
||||||
EmbedBuilder eb3 = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setTitle(opt3)
|
|
||||||
.setDescription(response1)
|
|
||||||
.setFooter(EmbedUI.BRAND)
|
|
||||||
.setTimestamp(ZonedDateTime.now());
|
|
||||||
e.getHook().sendMessageEmbeds(eb3.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandInfo> getSlashCommandInfo() {
|
|
||||||
List<CommandInfo> si = new ArrayList<>();
|
|
||||||
|
|
||||||
CommandInfo ci2 = new CommandInfo("setting", "Permits modification, viewing, and clearing of settings.", CommandType.COMMAND);
|
|
||||||
// For those looking here for inspiration, you CANNOT mix options and subcommands. You can only have one or the other.
|
|
||||||
|
|
||||||
CommandInfo ci = new CommandInfo("view", "Shows the current value for the setting provided.", CommandType.SUBCOMMAND);
|
|
||||||
ci.addOption("name", "The name of the setting to display", OptionType.STRING, true);
|
|
||||||
ci2.addSubcommand(ci);
|
|
||||||
|
|
||||||
CommandInfo ci3 = new CommandInfo("set", "sets a setting for the guild you are in", CommandType.SUBCOMMAND);
|
|
||||||
ci3.addOption("name", "The name of the setting to modify", OptionType.STRING, true);
|
|
||||||
ci3.addOption("value", "The value to set the setting to", OptionType.STRING, true);
|
|
||||||
ci2.addSubcommand(ci3);
|
|
||||||
|
|
||||||
CommandInfo ci4 = new CommandInfo("clear", "reverts a setting back to its default value", CommandType.SUBCOMMAND);
|
|
||||||
ci4.addOption("name", "Name of the setting to clear", OptionType.STRING, true);
|
|
||||||
ci2.addSubcommand(ci4);
|
|
||||||
|
|
||||||
CommandInfo ci5 = new CommandInfo("settings", "displays all settings available for the guild.", CommandType.COMMAND);
|
|
||||||
si.add(ci5);
|
|
||||||
|
|
||||||
si.add(ci2);
|
|
||||||
return si;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
package moe.oko.Kiafumi.command.utility;
|
|
||||||
public class StatsCommand {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package moe.oko.Kiafumi.listener;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.events.ReadyEvent;
|
|
||||||
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
|
|
||||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.info;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main Listener
|
|
||||||
* Used for all essential utility listeners, such as guild handling and persistence.
|
|
||||||
* @author Kay, oko, Tiddy
|
|
||||||
*/
|
|
||||||
public class MainListener extends ListenerAdapter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GuildJoin event listener, that ensures that a discord has a profile created for it.
|
|
||||||
* @param event - event to be handled...
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onGuildJoin(@NotNull GuildJoinEvent event) {
|
|
||||||
// Automatically create our default information for the server if we don't have it already.
|
|
||||||
info("Joined a new guild, NAME: " + event.getGuild().getName() + " ID: " + event.getGuild().getId());
|
|
||||||
Kiafumi.instance.getServerManager().createNewDefaultServer(event.getGuild());
|
|
||||||
Kiafumi.instance.registerForGuild(event.getGuild());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shoots a message into console when the bot is defined as "Ready" by Discord.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onReady(@NotNull ReadyEvent event) {
|
|
||||||
info("""
|
|
||||||
Received READY signal from Discord, bot is now logged in.
|
|
||||||
--------------------------------
|
|
||||||
Active Guilds: [%s]
|
|
||||||
Guilds Unavailable: [%s]
|
|
||||||
--------------------------------""".formatted(event.getGuildAvailableCount(), event.getGuildUnavailableCount()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quick Response for if someone pings me.
|
|
||||||
*/
|
|
||||||
public void onMessageReceived(MessageReceivedEvent event) {
|
|
||||||
if(event.getMessage().getMentionedUsers().contains(Kiafumi.JDA.getSelfUser())) {
|
|
||||||
info("Sent about message in " + event.getGuild().getId());
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setTitle("Hi, i'm Kiafumi!")
|
|
||||||
.setDescription("I was summoned on October 6th 2017! My goal is to explore the metaverse and help people in it!")
|
|
||||||
.setThumbnail(Kiafumi.JDA.getSelfUser().getAvatarUrl())
|
|
||||||
.setTimestamp(ZonedDateTime.now())
|
|
||||||
.setFooter(EmbedUI.BRAND);
|
|
||||||
event.getChannel().sendMessageEmbeds(eb.build()).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
package moe.oko.Kiafumi.listener;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.KiafumiConfig;
|
|
||||||
import moe.oko.Kiafumi.util.EmbedUI;
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.entities.TextChannel;
|
|
||||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
|
|
||||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
|
|
||||||
import net.dv8tion.jda.api.events.user.update.UserUpdateNameEvent;
|
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.debug;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.info;
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.error;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skynet Listener
|
|
||||||
* Handles all event logging (Join/Leaves, Username Change, etc).
|
|
||||||
* @author oko
|
|
||||||
*/
|
|
||||||
public class SkynetListener extends ListenerAdapter {
|
|
||||||
|
|
||||||
KiafumiConfig config;
|
|
||||||
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("MM-dd-yyyy");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Join/Leave logging
|
|
||||||
* Requires the server to configure welcomeChannel (optionally joinRole).
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) {
|
|
||||||
var guild = event.getGuild();
|
|
||||||
var server = Kiafumi.instance.getServerManager().getOrCreateServer(guild);
|
|
||||||
var member = event.getMember();
|
|
||||||
info("User [" + event.getUser().getName() + ":" + event.getUser().getId() + "] joined guild [" + guild.getName() + ':' + guild.getId() + "].");
|
|
||||||
if(server.getJoinRole() != null) {
|
|
||||||
try {
|
|
||||||
guild.addRoleToMember(member, guild.getRoleById(server.getJoinRole())).queue();
|
|
||||||
} catch(Exception ex) {
|
|
||||||
error("Failed to apply welcome role to " + member.getEffectiveName() + ", as the role does not exist.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(server.getWelcomeChannel() != null) {
|
|
||||||
// Fetch the welcome channel from settings.
|
|
||||||
TextChannel textChannel;
|
|
||||||
try {
|
|
||||||
textChannel = guild.getTextChannelById(server.getWelcomeChannel());
|
|
||||||
} catch (Exception ex) {
|
|
||||||
error("Failed to send join message to guild " + guild.getId() + " as the welcome channel was not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Prepare embed.
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.SUCCESS)
|
|
||||||
.setAuthor(member.getEffectiveName() + "#" + member.getUser().getDiscriminator() + " ("
|
|
||||||
+ member.getId() + ")", null, event.getUser().getAvatarUrl()) // Url cannot be member.
|
|
||||||
.setDescription(member.getAsMention() + " | **Joined Discord**: " + member.getTimeCreated().format(dTF))
|
|
||||||
.setFooter("User Joined")
|
|
||||||
.setTimestamp(OffsetDateTime.now());
|
|
||||||
textChannel.sendMessageEmbeds(eb.build()).queue();
|
|
||||||
debug("Guild join message successfully sent.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) {
|
|
||||||
var guild = event.getGuild();
|
|
||||||
info("User [" + event.getUser().getName() + ":" + event.getUser().getId() + "] left guild [" + guild.getName() + ':' + guild.getId() + "].");
|
|
||||||
var server = Kiafumi.instance.getServerManager().getOrCreateServer(guild);
|
|
||||||
if(server.getWelcomeChannel() != null) {
|
|
||||||
// Fetch the welcome channel from settings.
|
|
||||||
TextChannel textChannel;
|
|
||||||
var member = event.getMember();
|
|
||||||
try {
|
|
||||||
textChannel = guild.getTextChannelById(server.getWelcomeChannel());
|
|
||||||
} catch (Exception ex) {
|
|
||||||
error("Failed to send leave message to guild " + guild.getId() + " as the welcome channel was not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Prepare embed.
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.FAILURE)
|
|
||||||
.setAuthor(member.getEffectiveName() + "#" + member.getUser().getDiscriminator() + " ("
|
|
||||||
+ member.getId() + ")", null, event.getUser().getAvatarUrl()) // Url cannot be member.
|
|
||||||
.setDescription(member.getAsMention() + " | **Joined Server**: " + member.getTimeJoined().format(dTF))
|
|
||||||
.setFooter("User Left")
|
|
||||||
.setTimestamp(OffsetDateTime.now());
|
|
||||||
textChannel.sendMessageEmbeds(eb.build()).queue();
|
|
||||||
debug("Guild leave message successfully sent.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name change logging
|
|
||||||
* Sent to the central logChannel.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onUserUpdateName(@NotNull UserUpdateNameEvent event) {
|
|
||||||
var user = event.getUser();
|
|
||||||
String name = event.getNewName(), oldName = event.getOldName();
|
|
||||||
info("User [" + name + ':' + user.getId() + "] changed name from \"" + oldName + "\".");
|
|
||||||
var logChannel = Kiafumi.JDA.getTextChannelById(config.getLogChannel());
|
|
||||||
|
|
||||||
var eb = new EmbedBuilder()
|
|
||||||
.setColor(EmbedUI.INFO)
|
|
||||||
.setAuthor(user.getName() + '#' + user.getDiscriminator() + " (" + user.getId() + ')', null, user.getAvatarUrl())
|
|
||||||
.setDescription('`' + oldName + "` → `" + name + '`')
|
|
||||||
.setFooter("Username Edited")
|
|
||||||
.setTimestamp(OffsetDateTime.now());
|
|
||||||
logChannel.sendMessageEmbeds(eb.build()).queue();
|
|
||||||
debug("Username edit message successfully sent.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server Class
|
|
||||||
* Used for in-memory data storage. Loaded from Database later.
|
|
||||||
* @author Kay
|
|
||||||
* @implNote This class is where all server info is stored per-server, so be liberal with additions.
|
|
||||||
*/
|
|
||||||
public class Server {
|
|
||||||
// Guild ID
|
|
||||||
private String id;
|
|
||||||
// The channel for welcome logs to be posted to.
|
|
||||||
private String welcomeChannel;
|
|
||||||
// The role to be assigned on join, if null ignored.
|
|
||||||
private String joinRole;
|
|
||||||
//Moderation role, used for /mod
|
|
||||||
private String modChannel;
|
|
||||||
//If the server has been modified in memory, for saving persistently.
|
|
||||||
private boolean modified;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor, used for new servers
|
|
||||||
* @param id - the guild id to have server constructed for.
|
|
||||||
*/
|
|
||||||
public Server(String id) {
|
|
||||||
this.id = id;
|
|
||||||
this.welcomeChannel = null;
|
|
||||||
this.modChannel = null;
|
|
||||||
this.joinRole = null;
|
|
||||||
this.modified = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Database Constructor
|
|
||||||
* @param id - id of the server
|
|
||||||
* @param welcomeChannel - channel for welcome messages, if enabled
|
|
||||||
*/
|
|
||||||
public Server(String id, @Nullable String welcomeChannel, @Nullable String joinRole, String modChannel) {
|
|
||||||
this.id = id;
|
|
||||||
this.welcomeChannel = welcomeChannel;
|
|
||||||
this.modChannel = modChannel;
|
|
||||||
this.joinRole = joinRole;
|
|
||||||
this.modified = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() { return id; }
|
|
||||||
|
|
||||||
public String getJoinRole() { return joinRole; }
|
|
||||||
|
|
||||||
public String getModChannel() { return modChannel; }
|
|
||||||
|
|
||||||
public String getWelcomeChannel() {
|
|
||||||
return welcomeChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJoinRole(String joinRole) {
|
|
||||||
this.modified = true;
|
|
||||||
this.joinRole = joinRole;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWelcomeChannel(String welcomeChannel) {
|
|
||||||
this.modified = true;
|
|
||||||
this.welcomeChannel = welcomeChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the modification of the server file in memory
|
|
||||||
* @return - whether the server settings have been modified
|
|
||||||
*/
|
|
||||||
public boolean isModified() {
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options in the server class that can be modified.
|
|
||||||
* @return - Options in a string that can be printed to discord.
|
|
||||||
*/
|
|
||||||
public String getOpts() {
|
|
||||||
return """
|
|
||||||
welcomeChannel - the channel to send welcome messages to
|
|
||||||
modChannel - the channel to send moderation logs to
|
|
||||||
joinRole - the role to apply to new members who join this guild""";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the option value by string for discord command.
|
|
||||||
* @param string - the string to assess
|
|
||||||
* @return - the value (if applicable) to return
|
|
||||||
*/
|
|
||||||
public String getOptionByString(String string) {
|
|
||||||
return switch (string.toLowerCase()) {
|
|
||||||
case "joinrole" -> joinRole;
|
|
||||||
case "welcomechannel" -> welcomeChannel;
|
|
||||||
case "modchannel" -> modChannel;
|
|
||||||
default -> "INVALID";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets an option based on the string provided
|
|
||||||
* @param name - name of the option to be reset
|
|
||||||
* @return - returns whether the function succeeded.
|
|
||||||
*/
|
|
||||||
public String resetOptionByString(String name) {
|
|
||||||
switch(name.toLowerCase()) {
|
|
||||||
case "joinrole":
|
|
||||||
joinRole = null;
|
|
||||||
return "Auto-role on join is now set to disabled (Default).";
|
|
||||||
case "welcomechannel":
|
|
||||||
welcomeChannel = null;
|
|
||||||
return "Welcome channel is now unset.";
|
|
||||||
case "modchannel":
|
|
||||||
modChannel = null;
|
|
||||||
return "Mod channel is now unset.";
|
|
||||||
default:
|
|
||||||
return "INVALID SETTING";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets an option by a string, if it can find one
|
|
||||||
* @param name - the name of the option
|
|
||||||
* @param value - the value to have the option set to
|
|
||||||
* @return - whether the name and value were valid and the option was set.
|
|
||||||
*/
|
|
||||||
public String setOptionByString(String name, String value) {
|
|
||||||
modified = true; // If this is being used set it to modified.
|
|
||||||
switch (name.toLowerCase()) {
|
|
||||||
case "joinrole":
|
|
||||||
try {
|
|
||||||
if (Kiafumi.JDA.getRoleById(value) == null) {
|
|
||||||
return "That role ID is invalid.";
|
|
||||||
} else {
|
|
||||||
joinRole = value;
|
|
||||||
return "Successfully set joinRole ID to " + value;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return "Bad Value";
|
|
||||||
}
|
|
||||||
case "welcomechannel":
|
|
||||||
try {
|
|
||||||
if (Kiafumi.JDA.getTextChannelById(value) == null) {
|
|
||||||
return "That channel ID is invalid.";
|
|
||||||
} else {
|
|
||||||
welcomeChannel = value;
|
|
||||||
return "Successfully set welcomeChannel ID to " + value;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return "Bad Value";
|
|
||||||
}
|
|
||||||
case "modchannel":
|
|
||||||
try {
|
|
||||||
if(Kiafumi.JDA.getRoleById(value) == null) {
|
|
||||||
return "That role ID is invalid.";
|
|
||||||
} else {
|
|
||||||
modChannel = value;
|
|
||||||
return "Successfully set modChannel ID to " + modChannel;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return "Bad Value";
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return "INVALID setting name.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Server [id=" + this.id + ",welcomeChannel="+welcomeChannel+
|
|
||||||
",joinrole=" + joinRole + ",modChannel=" + modChannel +"]";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model;
|
|
||||||
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ServerManager Class
|
|
||||||
* Permits the access of servers easily
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class ServerManager {
|
|
||||||
//Server Memory Storage Hashmap, <Server/Guild ID, Server Object>
|
|
||||||
private HashMap<String, Server> servers = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor, loads servers and initializes the hashmap.
|
|
||||||
*/
|
|
||||||
public ServerManager() {
|
|
||||||
List<Server> loadedServers = Kiafumi.instance.database.loadServerInformation();
|
|
||||||
if(loadedServers == null) {
|
|
||||||
error("Failed to load servers properly. Null val on database.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
HashMap<String, Server> serverHashMap = new HashMap<>();
|
|
||||||
for(Server s : loadedServers) {
|
|
||||||
serverHashMap.put(s.getId(), s);
|
|
||||||
}
|
|
||||||
info("Successfully loaded " + serverHashMap.size() + " servers.");
|
|
||||||
servers = serverHashMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the server via the guild id
|
|
||||||
* @param id - the id to find a server for
|
|
||||||
* @return - the server, if non-existent a default profile is created for it.
|
|
||||||
*/
|
|
||||||
public Server getOrCreateServer(String id) {
|
|
||||||
if(servers.get(id) == null) { createNewDefaultServer(Kiafumi.JDA.getGuildById(id)); }
|
|
||||||
return servers.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the server via the guild.
|
|
||||||
* @param guild - the guild to find the server for
|
|
||||||
* @return - the server, if non-existent a default profile is created for it.
|
|
||||||
*/
|
|
||||||
public Server getOrCreateServer(Guild guild) {
|
|
||||||
if(servers.get(guild.getId()) == null) { createNewDefaultServer(guild); }
|
|
||||||
return servers.get(guild.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a persistent profile for the server and creates a new one that is loaded into memory.
|
|
||||||
* @param guild - the guild to have a default profile created for it.
|
|
||||||
* @return - whether the function succeeded.
|
|
||||||
*/
|
|
||||||
public boolean createNewDefaultServer(Guild guild) {
|
|
||||||
var serverName = guild.getName() + ":" + guild.getId() + "].";
|
|
||||||
debug("Creating data for [" + serverName);
|
|
||||||
Server server = new Server(guild.getId());
|
|
||||||
if(!Kiafumi.instance.getDatabase().createServerInformation(guild)) {
|
|
||||||
error("Failed to create new defaults for " + guild.getId());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
servers.put(server.getId(), server);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all the servers loaded in memory. Used for database persistence.
|
|
||||||
* @return - the servers loaded in memory in a collection.
|
|
||||||
*/
|
|
||||||
public Collection<Server> getServers() { return servers.values(); }
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model.audio;
|
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
|
||||||
import net.dv8tion.jda.api.entities.User;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Imported from SHIRO project.
|
|
||||||
* License for Kiafumi still applies.
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class AudioInfo {
|
|
||||||
|
|
||||||
private final AudioTrack track;
|
|
||||||
private final Set<String> skips;
|
|
||||||
private final Member author;
|
|
||||||
|
|
||||||
AudioInfo(AudioTrack track, Member author) {
|
|
||||||
this.track = track;
|
|
||||||
this.skips = new HashSet<>();
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AudioTrack getTrack() {
|
|
||||||
return track;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSkips() {
|
|
||||||
return skips.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSkip(User u) {
|
|
||||||
skips.add(u.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasVoted(User u) {
|
|
||||||
return skips.contains(u.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Member getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model.audio;
|
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
|
|
||||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Imported from SHIRO project.
|
|
||||||
* License for Kiafumi still applies
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class AudioPlayerSendHandler implements AudioSendHandler {
|
|
||||||
private final AudioPlayer audioPlayer;
|
|
||||||
private AudioFrame lastFrame;
|
|
||||||
|
|
||||||
public AudioPlayerSendHandler(AudioPlayer audioPlayer) {
|
|
||||||
this.audioPlayer = audioPlayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canProvide() {
|
|
||||||
lastFrame = audioPlayer.provide();
|
|
||||||
return lastFrame != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ByteBuffer provide20MsAudio() {
|
|
||||||
return ByteBuffer.wrap(lastFrame.getData());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOpus() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model.audio;
|
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
|
||||||
import net.dv8tion.jda.api.entities.AudioChannel;
|
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import from SHIRO project.
|
|
||||||
* License for Kiafumi still applies
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class TrackManager extends AudioEventAdapter {
|
|
||||||
|
|
||||||
private final AudioPlayer player;
|
|
||||||
private final Queue<AudioInfo> queue;
|
|
||||||
|
|
||||||
public TrackManager(AudioPlayer player) {
|
|
||||||
this.player = player;
|
|
||||||
this.queue = new LinkedBlockingQueue<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues a new track to be played.
|
|
||||||
* @param track - the track to be played
|
|
||||||
* @param author - the person who queued the track
|
|
||||||
*/
|
|
||||||
public void queue(AudioTrack track, Member author) {
|
|
||||||
AudioInfo info = new AudioInfo(track, author);
|
|
||||||
queue.add(info);
|
|
||||||
|
|
||||||
if (player.getPlayingTrack() == null) {
|
|
||||||
player.playTrack(track);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTrackStart(AudioPlayer player, AudioTrack track) {
|
|
||||||
AudioInfo info = queue.element();
|
|
||||||
AudioChannel vChan = info.getAuthor().getVoiceState().getChannel();
|
|
||||||
if (vChan == null) { // User has left all voice channels
|
|
||||||
player.stopTrack();
|
|
||||||
} else {
|
|
||||||
info.getAuthor().getGuild().getAudioManager().openAudioConnection(vChan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
|
|
||||||
Guild g = queue.poll().getAuthor().getGuild();
|
|
||||||
if (queue.isEmpty()) {
|
|
||||||
g.getAudioManager().closeAudioConnection();
|
|
||||||
} else {
|
|
||||||
player.playTrack(queue.element().getTrack());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shuffleQueue() {
|
|
||||||
List<AudioInfo> tQueue = new ArrayList<>(getQueuedTracks());
|
|
||||||
AudioInfo current = tQueue.get(0);
|
|
||||||
tQueue.remove(0);
|
|
||||||
Collections.shuffle(tQueue);
|
|
||||||
tQueue.add(0, current);
|
|
||||||
purgeQueue();
|
|
||||||
queue.addAll(tQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<AudioInfo> getQueuedTracks() {
|
|
||||||
return new LinkedHashSet<>(queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void purgeQueue() {
|
|
||||||
queue.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(AudioInfo entry) {
|
|
||||||
queue.remove(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AudioInfo getTrackInfo(AudioTrack track) {
|
|
||||||
return queue.stream().filter(audioInfo -> audioInfo.getTrack().equals(track)).findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model.db;
|
|
||||||
|
|
||||||
public record DBCredentials(
|
|
||||||
String username,
|
|
||||||
String password,
|
|
||||||
String host,
|
|
||||||
int port,
|
|
||||||
String db,
|
|
||||||
int poolSize,
|
|
||||||
long connTimeout,
|
|
||||||
long idleTimeout,
|
|
||||||
long maxLifetime
|
|
||||||
) {}
|
|
|
@ -1,178 +0,0 @@
|
||||||
package moe.oko.Kiafumi.model.db;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
|
||||||
import moe.oko.Kiafumi.Kiafumi;
|
|
||||||
import moe.oko.Kiafumi.model.Server;
|
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
|
||||||
|
|
||||||
import java.sql.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static moe.oko.Kiafumi.util.LoggingManager.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kiafumi DB Class
|
|
||||||
* Basically our helpful MySQL functions that pertain to data persistence.
|
|
||||||
* @author Kay, with moral support from Yodabird
|
|
||||||
*/
|
|
||||||
public class KiafumiDB {
|
|
||||||
|
|
||||||
private HikariDataSource dataSource;
|
|
||||||
private Connection connection;
|
|
||||||
|
|
||||||
// The prepared statement strings
|
|
||||||
private final String CREATE_SERVERINFO_TABLE = "CREATE TABLE IF NOT EXISTS `serverInfo`" +
|
|
||||||
"(`id` LONGTEXT NOT NULL, `welcomeChannel` LONGTEXT NULL, `modChannel` LONGTEXT NULL, joinRole LONGTEXT NULL);";
|
|
||||||
private final String INSERT_SERVERINFO_DEFAULT = "INSERT INTO serverInfo(id, welcomeChannel, modChannel, joinRole) values (?,?,?,?)";
|
|
||||||
private final String SERVERINFO_EXISTS = "select * from serverInfo where id = ?";
|
|
||||||
private final String SERVER_INFO_LOAD = "select * from serverInfo";
|
|
||||||
// 1 = welcomeChannel, 2 = modChannel , 3 = joinRole, 4 = Guild_ID (immutable)
|
|
||||||
private final String SERVER_INFO_MODIFY = "UPDATE `serverInfo` SET welcomeChannel=?, modChannel=?, joinRole=? WHERE id = ?";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KiafumiDB Connection Constructor
|
|
||||||
*/
|
|
||||||
public KiafumiDB(DBCredentials credentials) {
|
|
||||||
var config = new HikariConfig();
|
|
||||||
config.setJdbcUrl("jdbc:mysql://%s:%s/%s".formatted(credentials.host(), credentials.port(), credentials.db()));
|
|
||||||
|
|
||||||
config.setConnectionTimeout(credentials.connTimeout());
|
|
||||||
config.setIdleTimeout(credentials.idleTimeout());
|
|
||||||
config.setMaxLifetime(credentials.maxLifetime());
|
|
||||||
config.setMaximumPoolSize(credentials.poolSize());
|
|
||||||
config.setUsername(credentials.username());
|
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(credentials.password()))
|
|
||||||
config.setPassword(credentials.password());
|
|
||||||
this.dataSource = new HikariDataSource(config);
|
|
||||||
|
|
||||||
try {
|
|
||||||
connection = dataSource.getConnection();
|
|
||||||
info("Connected to database.");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
error("Unable to connect to database.");
|
|
||||||
e.printStackTrace();
|
|
||||||
this.dataSource = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeTables();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Table initialization function, ran on every startup.
|
|
||||||
*/
|
|
||||||
private void initializeTables() {
|
|
||||||
try {
|
|
||||||
connection.prepareStatement(CREATE_SERVERINFO_TABLE).execute();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
error("Failed to initialize SQL tables. They may need to be created manually.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the default server information when the bot joins a discord.
|
|
||||||
* @param guild - the guild that the bot joined
|
|
||||||
* @return whether the function succeeded.
|
|
||||||
*/
|
|
||||||
public boolean createServerInformation(Guild guild) {
|
|
||||||
try {
|
|
||||||
PreparedStatement prep = connection.prepareStatement(SERVERINFO_EXISTS);
|
|
||||||
prep.setInt(1, (int) guild.getIdLong());
|
|
||||||
ResultSet rsCheck = prep.executeQuery();
|
|
||||||
while (rsCheck.next()) {
|
|
||||||
//Server already exists, no need to initialize a section for it.
|
|
||||||
if(rsCheck.getInt(1) != 0) {
|
|
||||||
info("Server already existed. Skipping initialization.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Proceed with making defaults.
|
|
||||||
PreparedStatement ps = connection.prepareStatement(INSERT_SERVERINFO_DEFAULT);
|
|
||||||
ps.setString(1, guild.getId());
|
|
||||||
ps.setNull(2, Types.LONGVARCHAR);
|
|
||||||
ps.setNull(3, Types.LONGVARCHAR);
|
|
||||||
ps.setNull(4, Types.LONGVARCHAR);
|
|
||||||
ps.execute();
|
|
||||||
return true;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
error("Failed to create default server info for guild " + guild.getId());
|
|
||||||
ex.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all the server information from MySQL into memory.
|
|
||||||
* @return - a list of all servers loaded from MySQL.
|
|
||||||
*/
|
|
||||||
public List<Server> loadServerInformation() {
|
|
||||||
List<Server> servers = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
PreparedStatement ps = connection.prepareStatement(SERVER_INFO_LOAD);
|
|
||||||
ResultSet rs = ps.executeQuery();
|
|
||||||
while(rs.next()) {
|
|
||||||
info("Starting new load for server: " + rs.getString(1));
|
|
||||||
String id = rs.getString(1);
|
|
||||||
String welcomeChannel = rs.getString(2);
|
|
||||||
String modChannel = rs.getString(3);
|
|
||||||
String joinRole = rs.getString(4);
|
|
||||||
Server server = new Server(id, welcomeChannel, modChannel, joinRole);
|
|
||||||
debug("Loaded " + server + "from database.");
|
|
||||||
servers.add(server);
|
|
||||||
}
|
|
||||||
return servers;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
error("Failed to load server information, check stack.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves modified servers into persistent MySQL server.
|
|
||||||
* @return - whether the method succeeded.
|
|
||||||
*/
|
|
||||||
public boolean saveServerInformation() {
|
|
||||||
Collection<Server> servers = Kiafumi.instance.getServerManager().getServers();
|
|
||||||
info("Starting save on " + servers.size() + " servers.");
|
|
||||||
try {
|
|
||||||
// 1 = welcomeChannel, 2 = modChannel, 3 = joinRole, 4 = Guild_ID (immutable)
|
|
||||||
PreparedStatement ps = connection.prepareStatement(SERVER_INFO_MODIFY);
|
|
||||||
int i = 0;
|
|
||||||
for (Server server : servers) {
|
|
||||||
if(!server.isModified()) { continue; } // Skip, unmodified server.
|
|
||||||
info("Starting save on modified " + server);
|
|
||||||
if(server.getWelcomeChannel() != null) {
|
|
||||||
ps.setString(1, server.getWelcomeChannel());
|
|
||||||
} else {
|
|
||||||
ps.setNull(1, Types.LONGVARCHAR);
|
|
||||||
}
|
|
||||||
if(server.getModChannel() != null) {
|
|
||||||
ps.setString(2, server.getModChannel());
|
|
||||||
} else {
|
|
||||||
ps.setNull(2, Types.LONGVARCHAR);
|
|
||||||
}
|
|
||||||
if(server.getJoinRole() != null) {
|
|
||||||
ps.setString(3, server.getJoinRole());
|
|
||||||
} else {
|
|
||||||
ps.setNull(3, Types.LONGVARCHAR);
|
|
||||||
}
|
|
||||||
ps.setString(4, server.getId());
|
|
||||||
ps.addBatch();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
info("Total Batches: " + i + ". Starting SQL save.");
|
|
||||||
ps.executeBatch();
|
|
||||||
return true;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
error("Failed to persist server data. Check stack.");
|
|
||||||
ex.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
package moe.oko.Kiafumi.util;
|
|
||||||
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helpful CommandInfo class to easily make slash commands.
|
|
||||||
* @author Kay
|
|
||||||
*/
|
|
||||||
public class CommandInfo {
|
|
||||||
private String name;
|
|
||||||
private String description;
|
|
||||||
private CommandType type;
|
|
||||||
private HashMap<String, OptionType> options;
|
|
||||||
private HashMap<String, String> optionDescriptions;
|
|
||||||
private HashMap<String, Boolean> optionRequirements;
|
|
||||||
private HashMap<String, CommandInfo> subCommands;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor to build CommandInfo with.
|
|
||||||
* @param name - Name of the slash command (MUST BE ALL LOWERCASE)
|
|
||||||
* @param description - Description of the slash command
|
|
||||||
*/
|
|
||||||
public CommandInfo(String name, String description, CommandType type) {
|
|
||||||
this.name = name;
|
|
||||||
this.description = description;
|
|
||||||
this.type = type;
|
|
||||||
this.options = new HashMap<>();
|
|
||||||
this.optionDescriptions = new HashMap<>();
|
|
||||||
this.optionRequirements = new HashMap<>();
|
|
||||||
this.subCommands = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the command has options/input.
|
|
||||||
* @return - boolean
|
|
||||||
*/
|
|
||||||
public boolean hasOptions() {
|
|
||||||
return options.size() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSubCommands() { return subCommands.size() != 0; }
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, OptionType> getOptions() {
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, Boolean> getOptionRequirements() {
|
|
||||||
return optionRequirements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, String> getOptionDescriptions() {
|
|
||||||
return optionDescriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, CommandInfo> getSubCommands() { return subCommands; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The way you add options to a command. Use this function for EACH argument.
|
|
||||||
* @param name - name of the field
|
|
||||||
* @param description - description for the field
|
|
||||||
* @param type - the OptionType of the field (e.x. OptionType.STRING, OptionType.CHANNEL, etc.)
|
|
||||||
* @param required - whether the command can be run without the field or not.
|
|
||||||
*/
|
|
||||||
public void addOption(String name, String description, OptionType type, boolean required) {
|
|
||||||
options.put(name, type);
|
|
||||||
optionDescriptions.put(name, description);
|
|
||||||
optionRequirements.put(name, required);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The way you add subcommands to a command. NOTE you cannot have options for the command if you use this.
|
|
||||||
* @param cmdInfo - The CommandInfo for the subcommand (including options).
|
|
||||||
*/
|
|
||||||
public void addSubcommand(CommandInfo cmdInfo) {
|
|
||||||
subCommands.put(cmdInfo.name, cmdInfo);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package moe.oko.Kiafumi.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to identify what type of Command is being used.
|
|
||||||
* This is intended to prevent JDA errors.
|
|
||||||
*/
|
|
||||||
public enum CommandType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commands that are registered using the upsertCommand method.
|
|
||||||
*/
|
|
||||||
COMMAND,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commands that fall under above commands using the addSubcommand function.
|
|
||||||
*/
|
|
||||||
SUBCOMMAND
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package moe.oko.Kiafumi.util;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EmbedUI Class
|
|
||||||
* @author oko
|
|
||||||
*/
|
|
||||||
public abstract class EmbedUI {
|
|
||||||
// TODO: restructure & rename class - it has surpassed its scope.
|
|
||||||
/**
|
|
||||||
* Shorthand reference for common EmbedBuilder colors & strings.
|
|
||||||
* I chose these colors based on the Pantone Color of the year.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Strings
|
|
||||||
public static final String BRAND = "Kiafumi - oko.moe";
|
|
||||||
public static final String RESPONSE_PRIVILEGES = " Insufficient privileges.";
|
|
||||||
|
|
||||||
// Colors
|
|
||||||
public static final Color SUCCESS = new Color(136,176,75);
|
|
||||||
public static final Color FAILURE = new Color(255,111,97);
|
|
||||||
public static final Color INFO = new Color(123,196,196);
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package moe.oko.Kiafumi.util;
|
|
||||||
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logging Class
|
|
||||||
* Provides static logging & extensible template messages.
|
|
||||||
* @author oko
|
|
||||||
*/
|
|
||||||
public class LoggingManager {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger("Kiafumi");
|
|
||||||
|
|
||||||
// Static logging reference
|
|
||||||
public static void debug(String str) { logger.debug(str); }
|
|
||||||
public static void info(String str) { logger.info(str); }
|
|
||||||
public static void warn(String str) { logger.warn(str); }
|
|
||||||
public static void error(String str) { logger.error(str); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for logging commands with ease to console via a static method.
|
|
||||||
* @param event - the event ran
|
|
||||||
* @param msg - Any message to append with this.
|
|
||||||
*/
|
|
||||||
public static void slashLog(SlashCommandInteractionEvent event, @Nullable String msg) {
|
|
||||||
var user = event.getUser();
|
|
||||||
info("""
|
|
||||||
User [%s:%s] ran command: "%s" %s"""
|
|
||||||
.formatted(user.getName(), user.getId(), event.getName(), msg == null ? "" : msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void slashLog(SlashCommandInteractionEvent event) {
|
|
||||||
var user = event.getUser();
|
|
||||||
info("""
|
|
||||||
User [%s:%s] ran command: "%s"."""
|
|
||||||
.formatted(user.getName(), user.getId(), event.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void slashResponse(SlashCommandInteractionEvent event, String msg) {
|
|
||||||
var user = event.getUser();
|
|
||||||
info("""
|
|
||||||
User [%s:%s] was provided response: "%s\"""".formatted(user.getName(), user.getId(), msg));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package moe.oko.Kiafumi.util;
|
|
||||||
|
|
||||||
import org.apache.http.HttpEntity;
|
|
||||||
import org.apache.http.client.ClientProtocolException;
|
|
||||||
import org.apache.http.client.ResponseHandler;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic ResponseHandler Class
|
|
||||||
* Intended for GET requests from online API's
|
|
||||||
* Such as, Steam, DDG, ProtonDB, CatApi, etc.
|
|
||||||
*/
|
|
||||||
public class ResponseHandlers {
|
|
||||||
/**
|
|
||||||
* @apiNote Returns GET response in a uniformed string. Use JSONArray to convert it into JSON.
|
|
||||||
**/
|
|
||||||
public static final ResponseHandler<String> STRING_RESPONSE_HANDLER = response -> {
|
|
||||||
int status = response.getStatusLine().getStatusCode();
|
|
||||||
if (status >= 200 && status < 300) {
|
|
||||||
HttpEntity entity = response.getEntity();
|
|
||||||
return entity != null ? EntityUtils.toString(entity) : null;
|
|
||||||
} else {
|
|
||||||
throw new ClientProtocolException("Unexpected response status: " + status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
# ██╗ ██╗██╗ █████╗ ███████╗██╗ ██╗███╗ ███╗██╗
|
|
||||||
# ██║ ██╔╝██║██╔══██╗██╔════╝██║ ██║████╗ ████║██║
|
|
||||||
# █████╔╝ ██║███████║█████╗ ██║ ██║██╔████╔██║██║
|
|
||||||
# ██╔═██╗ ██║██╔══██║██╔══╝ ██║ ██║██║╚██╔╝██║██║
|
|
||||||
# ██║ ██╗██║██║ ██║██║ ╚██████╔╝██║ ╚═╝ ██║██║
|
|
||||||
# ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
# KIAFUMI Default Configuration File (With Comments)
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
# DISCORD CONFIG STACK
|
|
||||||
discord:
|
|
||||||
# Paste in your bot token here.
|
|
||||||
token: "DO NOT SHARE"
|
|
||||||
# The main guild the bot will recognize and do protection actions on.
|
|
||||||
mainGuild: ""
|
|
||||||
# The channel ID the bot will send important logging messages to.
|
|
||||||
logChannel: ""
|
|
||||||
# The user ID of the owner of the bot.
|
|
||||||
ownerId: ""
|
|
||||||
# The client ID of the bot (for invite generation)
|
|
||||||
clientId: ""
|
|
||||||
# Level of permissions for the invite (If you don't know this, use https://discordapi.com/permissions.html)
|
|
||||||
# If problems occur, you can use 8 (Administrator)
|
|
||||||
invitePermissionLevel: 139855252544
|
|
||||||
# MAIN CONFIG STACK
|
|
||||||
main:
|
|
||||||
# Activity Type (STREAMING|PLAYING|WATCHING|COMPETING|DEFAULT)
|
|
||||||
activityType: "PLAYING"
|
|
||||||
# Activity Message
|
|
||||||
activityMsg: "https://oko.moe"
|
|
||||||
# Status type (ONLINE|IDLE|DO_NOT_DISTURB|INVISIBLE)
|
|
||||||
statusType: "IDLE"
|
|
||||||
# Responses for the default ping command
|
|
||||||
pingResponses:
|
|
||||||
- "Pinged the pentagon"
|
|
||||||
- "Pinged oko's basement"
|
|
||||||
- "Pinged oko.moe"
|
|
||||||
- "Pinged you're mother"
|
|
||||||
- "Pinged 142.250.189.238"
|
|
||||||
- "Pinged cuomo.zone"
|
|
||||||
- "Pinged my brain"
|
|
||||||
- "Pinged 38.fail"
|
|
||||||
- "Pinged pong"
|
|
||||||
- "Pinged the admins"
|
|
||||||
sql:
|
|
||||||
host: "localhost"
|
|
||||||
port: 3306
|
|
||||||
database: "kiafumi"
|
|
||||||
username: "alpine"
|
|
||||||
password: "squidlover42069"
|
|
||||||
poolSize: 2
|
|
||||||
connectionTimeout: 10000
|
|
||||||
idleTimeout: 600000
|
|
||||||
maxLifetime: 7200000
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Configuration status="WARN" monitorInterval="30">
|
|
||||||
<Properties>
|
|
||||||
<Property name="LOG_PATTERN">%d{HH:mm} %highlight{%-5level} %cyan{%logger{11}} - %m%n</Property>
|
|
||||||
</Properties>
|
|
||||||
|
|
||||||
<Appenders>
|
|
||||||
<Console name="console" target="SYSTEM_OUT" follow="true">
|
|
||||||
<PatternLayout pattern="${LOG_PATTERN}"/>
|
|
||||||
</Console>
|
|
||||||
</Appenders>
|
|
||||||
|
|
||||||
<Loggers>
|
|
||||||
<Root level="info">
|
|
||||||
<AppenderRef ref="console"/>
|
|
||||||
</Root>
|
|
||||||
</Loggers>
|
|
||||||
</Configuration>
|
|
Loading…
Reference in New Issue