Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
skidunion committed Aug 12, 2021
0 parents commit 190c1b6
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Maven
target/

### Auto-import
.idea/modules/
.idea/compiler.xml
.idea/jarRepositories.xml
.idea/modules.xml

# IntelliJ
out/
.idea/.name
*.iml

### User-specific stuff
.idea/dictionaries/
.idea/inspectionProfiles/
.idea/shelf/
.idea/tasks.xml
.idea/uiDesigner.xml
.idea/workspace.xml
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions .idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?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>com.novoline</groupId>
<artifactId>auto-delete</artifactId>
<version>1.0</version>

<properties>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
</properties>

<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>com.mewna</groupId>
<artifactId>catnip</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-impl</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
196 changes: 196 additions & 0 deletions src/main/java/com/novoline/autodelete/AutoDeleteBot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package com.novoline.autodelete;

import com.mewna.catnip.Catnip;
import com.mewna.catnip.CatnipOptions;
import com.mewna.catnip.entity.channel.Channel;
import com.mewna.catnip.entity.channel.GuildChannel;
import com.mewna.catnip.entity.guild.PermissionOverride;
import com.mewna.catnip.entity.message.Message;
import com.mewna.catnip.rest.guild.ChannelData;
import com.mewna.catnip.shard.DiscordEvent;
import org.tinylog.Logger;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static com.mewna.catnip.shard.GatewayIntent.GUILDS;
import static com.mewna.catnip.shard.GatewayIntent.GUILD_MESSAGES;
import static com.novoline.autodelete.Configuration.PREFIX;

public class AutoDeleteBot {

private final Catnip catnip;

private final ScheduledExecutorService scheduler;
private final Map<String, Future<?>> channelFutureMap;

/* package */ AutoDeleteBot(String token) {
Logger.info("Starting AutoDeleteBot (token = {})", token);

catnip = configureCatnip(token);
catnip.connect();

scheduler = Executors.newScheduledThreadPool(2);
channelFutureMap = new HashMap<>();
}

private Catnip configureCatnip(String token) {
CatnipOptions options = new CatnipOptions(token)
.intents(Set.of(GUILDS, GUILD_MESSAGES));

Catnip catnip = Catnip.catnip(options);

catnip
.observable(DiscordEvent.READY)
.subscribe((e) -> Logger.debug("Connected to Discord ({})", e.user().discordTag()));

catnip
.observable(DiscordEvent.MESSAGE_CREATE)
.filter(message -> Configuration.ALLOWED_USERS.contains(message.author().id()))
.filter(message -> message.content().startsWith(PREFIX)
&& !message.guild().isEmpty().blockingGet())
.map(this::processCommand)
.subscribe(this::handleCommand,
error -> Logger.error(error, "Uncaught exception"));

return catnip;
}

private CommandContext processCommand(Message message) {
String content = message.content().substring(PREFIX.length());
String[] parts = content.split(" ");

String commandName = parts[0];
String[] args = content.substring(commandName.length()).trim().split(" ");

return new CommandContext(message, commandName, args);
}

private void handleCommand(CommandContext ctx) {
switch(ctx.commandName()) {
case "set" -> {
String duration = ctx.args()[0];
String channelId = ctx.message().channelId();

if(duration.equals("0")) {
var future = channelFutureMap.get(channelId);

if(future == null) {
ctx.message().respond("This channel is not set up for purging yet");
} else {
future.cancel(false);
ctx.message().respond("Ok, this channel will no longer be purged");
}
} else {
long durationMillis = parseDuration(duration).toMillis();

// Cancel future for this channel if the user tried to re-set purge time
if(channelFutureMap.containsKey(channelId)) {
channelFutureMap.get(channelId).cancel(false);
}

ctx.message().channel()
.map(Channel::asGuildChannel)
.subscribe(channel -> {
var future = scheduler.scheduleAtFixedRate(
new AutoDeleteTask(catnip, channel),
durationMillis, durationMillis, TimeUnit.MILLISECONDS);

channelFutureMap.put(channelId, future);
ctx.message().respond("Ok, purging this channel every " + duration);
});
}
}
case "purge" ->
ctx.message().channel()
.map(Channel::asGuildChannel)
.subscribe(channel -> {
ChannelData currentData = ChannelData.of(channel);
channel.guild().blockingGet()
.createChannel(currentData)
.subscribe(newChannel -> {
cloneOverrides(channel, newChannel);
channel.delete();
});
});
case "help" -> ctx.message().respond(
"""
🗑️ auto-delete bot
```
a!set <duration> - enables purging for the current channel
a!set 0 - disables purging for the current channel
a!purge - purge this channel now
a!help - prints this message
```
"""
);
default -> ctx.message().respond("Unknown command, type `a!help` for help");
}
}

private static void cloneOverrides(GuildChannel from, GuildChannel to) {
for (PermissionOverride override : from.overrides()) {
from.catnip().rest().channel()
.editPermissionOverride(
to.id(), override.id(),
override.allow(), override.deny(),
override.type() == PermissionOverride.OverrideType.MEMBER)
.blockingAwait();
}
}

private static Duration parseDuration(String durationStr) {
durationStr = durationStr.toLowerCase(Locale.ROOT);
String designator = durationStr.endsWith("d") ? "P" : "PT";
return Duration.parse(designator + durationStr);
}

private record CommandContext(
Message message,
String commandName,
String[] args
) {}

private final class AutoDeleteTask implements Runnable {

private final Catnip catnip;
private GuildChannel channel;

public AutoDeleteTask(Catnip catnip, GuildChannel channel) {
this.catnip = catnip;
this.channel = channel;
}

@Override
public void run() {
String channelId = channel.id();
ChannelData currentData = ChannelData.of(channel);

var map = Collections.synchronizedMap(channelFutureMap);
var thisFuture = map.get(channel.id());

channel.guild().blockingGet()
.createChannel(currentData)
.subscribe(newChannel -> {
// Catnip's caching is weird and 'newChannel' lacks the 'allow' or 'deny' properties
// in newly created channels, thus we have to retrieve the correct overrides from the previous channel.
GuildChannel channelFromRest = catnip.rest().channel()
.getChannelById(channelId).blockingGet().asGuildChannel();

cloneOverrides(channelFromRest, newChannel);

channel.delete("Auto-purged");
channel = newChannel;

synchronized (map) {
map.remove(channelId);
map.put(newChannel.id(), thisFuture);
}
});
}
}
}
9 changes: 9 additions & 0 deletions src/main/java/com/novoline/autodelete/AutoDeleteMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.novoline.autodelete;

public class AutoDeleteMain {

public static void main(String[] args) {
String token = System.getenv("TOKEN");
new AutoDeleteBot(token);
}
}
Loading

0 comments on commit 190c1b6

Please sign in to comment.