Complete bot question mark?
This commit is contained in:
commit
7c00dba873
7 changed files with 389 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.gradle/
|
||||||
|
.idea/
|
||||||
|
build/
|
||||||
|
gradle/
|
||||||
|
gradlew
|
||||||
|
gradlew.bat
|
||||||
|
icon.ai
|
||||||
|
ServerData.bin
|
||||||
|
TimeData.txt
|
||||||
|
|
18
build.gradle
Normal file
18
build.gradle
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'application'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'com.gnarly'
|
||||||
|
version = '1.0.0'
|
||||||
|
mainClassName = 'com.gnarly.ld.Main'
|
||||||
|
|
||||||
|
sourceCompatibility = 1.12
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile group: 'net.dv8tion', name: 'JDA', version: '3.8.3_464'
|
||||||
|
}
|
BIN
icon.png
Normal file
BIN
icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
2
settings.gradle
Normal file
2
settings.gradle
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
rootProject.name = 'Ludum Dare Timer'
|
||||||
|
|
322
src/main/java/com/gnarly/ld/LDTimerEventListener.java
Normal file
322
src/main/java/com/gnarly/ld/LDTimerEventListener.java
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
package com.gnarly.ld;
|
||||||
|
|
||||||
|
import net.dv8tion.jda.core.Permission;
|
||||||
|
import net.dv8tion.jda.core.entities.Guild;
|
||||||
|
import net.dv8tion.jda.core.entities.Message;
|
||||||
|
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
|
||||||
|
import net.dv8tion.jda.core.events.message.MessageUpdateEvent;
|
||||||
|
import net.dv8tion.jda.core.hooks.ListenerAdapter;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class LDTimerEventListener extends ListenerAdapter {
|
||||||
|
|
||||||
|
private static final long SECOND = 1000;
|
||||||
|
private static final long MINUTE = 60 * SECOND;
|
||||||
|
private static final long HOUR = 60 * MINUTE;
|
||||||
|
private static final long DAY = 24 * HOUR;
|
||||||
|
|
||||||
|
private static final long REFRESH_INTERVAL = 1 * DAY + 0 * HOUR + 0 * MINUTE + 0 * SECOND;
|
||||||
|
|
||||||
|
private Map<String, ServerInfo> servers;
|
||||||
|
|
||||||
|
private long nextRefresh;
|
||||||
|
|
||||||
|
private long start;
|
||||||
|
private long compoEnd;
|
||||||
|
private long compoSubmissionHour;
|
||||||
|
private long jamEnd;
|
||||||
|
private long jamSubmissionHour;
|
||||||
|
private long rate;
|
||||||
|
private long results;
|
||||||
|
|
||||||
|
public LDTimerEventListener() {
|
||||||
|
servers = new HashMap<>();
|
||||||
|
loadServerInfo();
|
||||||
|
|
||||||
|
var file = (FileInputStream) null;
|
||||||
|
try {
|
||||||
|
file = new FileInputStream("TimeData.txt");
|
||||||
|
} catch (IOException e) {}
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
var scanner = new Scanner(file);
|
||||||
|
try {
|
||||||
|
nextRefresh = scanner.nextLong(); scanner.nextLine();
|
||||||
|
start = scanner.nextLong(); scanner.nextLine();
|
||||||
|
compoEnd = scanner.nextLong(); scanner.nextLine();
|
||||||
|
compoSubmissionHour = scanner.nextLong(); scanner.nextLine();
|
||||||
|
jamEnd = scanner.nextLong(); scanner.nextLine();
|
||||||
|
jamSubmissionHour = scanner.nextLong(); scanner.nextLine();
|
||||||
|
rate = scanner.nextLong(); scanner.nextLine();
|
||||||
|
results = scanner.nextLong(); scanner.nextLine();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nextRefresh = 0;
|
||||||
|
start = 0;
|
||||||
|
compoEnd = 0;
|
||||||
|
compoSubmissionHour = 0;
|
||||||
|
jamEnd = 0;
|
||||||
|
jamSubmissionHour = 0;
|
||||||
|
rate = 0;
|
||||||
|
results = 0;
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessageReceived(MessageReceivedEvent event) {
|
||||||
|
handleMessage(event.getGuild().getId(), event.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessageUpdate(MessageUpdateEvent event) {
|
||||||
|
handleMessage(event.getGuild().getId(), event.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMessage(String id, Message message) {
|
||||||
|
if (message.getAuthor().getId().equals("677349303672373271")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!servers.containsKey(id)) {
|
||||||
|
servers.put(id, new ServerInfo());
|
||||||
|
}
|
||||||
|
var info = servers.get(id);
|
||||||
|
|
||||||
|
var server = message.getGuild();
|
||||||
|
var channel = message.getChannel();
|
||||||
|
|
||||||
|
var admin = false;
|
||||||
|
var roles = message.getAuthor().getJDA().getRoles();
|
||||||
|
for (var i = 0; i < roles.size() && !admin; ++i) {
|
||||||
|
if (roles.get(i).hasPermission(Permission.ADMINISTRATOR)) {
|
||||||
|
admin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (admin) {
|
||||||
|
if (message.getContentDisplay().equals(info.prefix + "blacklist")) {
|
||||||
|
info.blacklist.add(channel.getId());
|
||||||
|
channel.sendMessage("Channel has been blacklisted").queue();
|
||||||
|
} else if (message.getContentDisplay().equals(info.prefix + "whitelist")) {
|
||||||
|
info.blacklist.remove(channel.getId());
|
||||||
|
channel.sendMessage("Channel has been whitelisted").queue();
|
||||||
|
} else if (message.getContentDisplay().equals(info.prefix + "blacklist all")) {
|
||||||
|
var channels = server.getChannels();
|
||||||
|
for (var c : channels) {
|
||||||
|
info.blacklist.add(c.getId());
|
||||||
|
}
|
||||||
|
channel.sendMessage("Blacklisted all channels").queue();
|
||||||
|
} else if (message.getContentDisplay().equals(info.prefix + "whitelist all")) {
|
||||||
|
info.blacklist.clear();
|
||||||
|
channel.sendMessage("Whitelisted all channels").queue();
|
||||||
|
}
|
||||||
|
saveServerInfo();
|
||||||
|
|
||||||
|
if (info.blacklist.contains(channel.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.getContentDisplay().startsWith(info.prefix + "prefix ")) {
|
||||||
|
info.prefix = message.getContentDisplay().substring((info.prefix + "prefix ").length());
|
||||||
|
channel.sendMessage("Updated prefix to: " + info.prefix).queue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.blacklist.contains(channel.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.getContentDisplay().startsWith(info.prefix + "timeleft")) {
|
||||||
|
refresh();
|
||||||
|
var timeleftMessage = new StringBuilder("**Time Left**\n");
|
||||||
|
var current = System.currentTimeMillis();
|
||||||
|
if (current < start) {
|
||||||
|
timeleftMessage.append("Ludum Dare starts in ").append(toDurationString(start - current));
|
||||||
|
} else if (current < jamSubmissionHour) {
|
||||||
|
if (current < compoEnd) {
|
||||||
|
timeleftMessage.append("Compo ends in ").append(toDurationString(compoEnd - current)).append('\n');
|
||||||
|
} else if (current < compoSubmissionHour) {
|
||||||
|
timeleftMessage.append("Compo submission hour ends in ").append(toDurationString(compoSubmissionHour - current)).append('\n');
|
||||||
|
} else {
|
||||||
|
timeleftMessage.append("Compo rating ends in ").append(toDurationString(rate - current)).append('\n');
|
||||||
|
}
|
||||||
|
if (current < jamEnd) {
|
||||||
|
timeleftMessage.append("Jam ends in ").append(toDurationString(jamEnd - current));
|
||||||
|
} else {
|
||||||
|
timeleftMessage.append("Jam submission hour ends in ").append(toDurationString(jamSubmissionHour - current));
|
||||||
|
}
|
||||||
|
} else if (current < rate) {
|
||||||
|
timeleftMessage.append("Rating ends in ").append(toDurationString(rate - current));
|
||||||
|
} else if (current < results) {
|
||||||
|
timeleftMessage.append("Results are available in ").append(toDurationString(results - current));
|
||||||
|
} else {
|
||||||
|
timeleftMessage = new StringBuilder("Sorry I don't have any time data at the moment :(");
|
||||||
|
}
|
||||||
|
channel.sendMessage(timeleftMessage).queue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveServerInfo() {
|
||||||
|
try {
|
||||||
|
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("ServerData.bin"));
|
||||||
|
output.writeInt(servers.size());
|
||||||
|
for (Map.Entry<String, ServerInfo> entry : servers.entrySet()) {
|
||||||
|
output.writeObject(entry.getKey());
|
||||||
|
output.writeObject(entry.getValue());
|
||||||
|
}
|
||||||
|
output.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadServerInfo() {
|
||||||
|
try {
|
||||||
|
if (new File("ServerData.bin").exists()) {
|
||||||
|
ObjectInputStream input = new ObjectInputStream(new FileInputStream("ServerData.bin"));
|
||||||
|
int numObjects = input.readInt();
|
||||||
|
servers.clear();
|
||||||
|
for (int i = 0; i < numObjects; ++i) {
|
||||||
|
servers.put((String) input.readObject(), (ServerInfo) input.readObject());
|
||||||
|
}
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toDurationString(long millis) {
|
||||||
|
var days = (millis ) / DAY;
|
||||||
|
var hours = (millis % DAY ) / HOUR;
|
||||||
|
var minutes = (millis % HOUR ) / MINUTE;
|
||||||
|
var seconds = (millis % MINUTE) / SECOND;
|
||||||
|
return new StringBuilder()
|
||||||
|
.append(days ).append(" day" ).append(days == 1 ? ", " : "s, ")
|
||||||
|
.append(hours ).append(" hour" ).append(hours == 1 ? ", " : "s, ")
|
||||||
|
.append(minutes).append(" minute").append(minutes == 1 ? ", " : "s, ")
|
||||||
|
.append(seconds).append(" second").append(seconds == 1 ? "" : "s" )
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh() {
|
||||||
|
if (nextRefresh - System.currentTimeMillis() <= 0) {
|
||||||
|
nextRefresh = System.currentTimeMillis() + REFRESH_INTERVAL;
|
||||||
|
String[] dates = getDates();
|
||||||
|
if (dates != null) {
|
||||||
|
start = getSinceEpoch(dates[0]);
|
||||||
|
compoEnd = getSinceEpoch(dates[1]);
|
||||||
|
compoSubmissionHour = getSinceEpoch(dates[2]);
|
||||||
|
jamEnd = getSinceEpoch(dates[3]);
|
||||||
|
jamSubmissionHour = getSinceEpoch(dates[4]);
|
||||||
|
rate = getSinceEpoch(dates[5]);
|
||||||
|
results = getSinceEpoch(dates[6]);
|
||||||
|
saveTimes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveTimes() {
|
||||||
|
try {
|
||||||
|
PrintWriter writer = new PrintWriter(new FileOutputStream("TimeData.txt"));
|
||||||
|
writer.println(nextRefresh );
|
||||||
|
writer.println(start );
|
||||||
|
writer.println(compoEnd );
|
||||||
|
writer.println(compoSubmissionHour);
|
||||||
|
writer.println(jamEnd );
|
||||||
|
writer.println(jamSubmissionHour );
|
||||||
|
writer.println(rate );
|
||||||
|
writer.println(results );
|
||||||
|
writer.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getSinceEpoch(String date) {
|
||||||
|
var timeStrings = date.split(",");
|
||||||
|
var times = new int[6];
|
||||||
|
for (var i = 0; i < times.length; ++i) {
|
||||||
|
times[i] = Integer.parseInt(timeStrings[i]);
|
||||||
|
}
|
||||||
|
return LocalDateTime.of(times[0], times[1] + 1, times[2] + times[3] / 24, times[3] % 24, times[4], times[5]).toEpochSecond(ZoneOffset.UTC) * 1000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] getDates() {
|
||||||
|
final var JAVASCRIPT_URL_REGEX = Pattern.compile("<(/-/all\\.min\\.js\\?v=[a-zA-Z0-9\\-]+)>");
|
||||||
|
final var DATE_UTC_REGEX = Pattern.compile("new Date\\(Date\\.UTC\\((\\d+,\\d+,\\d+,\\d+,\\d+,\\d+)\\)\\)");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final var url = new URL("https://ldjam.com");
|
||||||
|
var connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(5000);
|
||||||
|
connection.setInstanceFollowRedirects(true);
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
var jsUrl = (URL) null;
|
||||||
|
for (var valueLists : connection.getHeaderFields().values()) {
|
||||||
|
for (var value : valueLists) {
|
||||||
|
var matcher = JAVASCRIPT_URL_REGEX.matcher(value);
|
||||||
|
if (matcher.find()) {
|
||||||
|
var group = matcher.group(1);
|
||||||
|
jsUrl = new URL("https://ldjam.com" + group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connection.disconnect();
|
||||||
|
|
||||||
|
if (jsUrl != null) {
|
||||||
|
connection = (HttpURLConnection) jsUrl.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setRequestProperty("Accept", "*/*");
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(5000);
|
||||||
|
connection.setInstanceFollowRedirects(true);
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
var in = connection.getInputStream();
|
||||||
|
var reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
var line = (String) null;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
builder.append(line).append('\n');
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
var matcher = DATE_UTC_REGEX.matcher(builder);
|
||||||
|
var dates = new String[7];
|
||||||
|
for (var i = 0; i < dates.length; ++i) {
|
||||||
|
if (matcher.find()) {
|
||||||
|
dates[i] = matcher.group(1);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dates;
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
16
src/main/java/com/gnarly/ld/Main.java
Normal file
16
src/main/java/com/gnarly/ld/Main.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package com.gnarly.ld;
|
||||||
|
|
||||||
|
import net.dv8tion.jda.core.AccountType;
|
||||||
|
import net.dv8tion.jda.core.JDA;
|
||||||
|
import net.dv8tion.jda.core.JDABuilder;
|
||||||
|
|
||||||
|
import javax.security.auth.login.LoginException;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws LoginException {
|
||||||
|
LDTimerEventListener events = new LDTimerEventListener();
|
||||||
|
JDA jda = new JDABuilder(AccountType.BOT).setToken(args[0]).build();
|
||||||
|
jda.addEventListener(events);
|
||||||
|
}
|
||||||
|
}
|
21
src/main/java/com/gnarly/ld/ServerInfo.java
Normal file
21
src/main/java/com/gnarly/ld/ServerInfo.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package com.gnarly.ld;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ServerInfo implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1098398424L;
|
||||||
|
|
||||||
|
private static final String DEFAULT_PREFIX = "!";
|
||||||
|
|
||||||
|
public String prefix;
|
||||||
|
public Set<String> blacklist;
|
||||||
|
|
||||||
|
public ServerInfo() {
|
||||||
|
prefix = DEFAULT_PREFIX;
|
||||||
|
blacklist = new HashSet<>();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue