Skip to content

Commit

Permalink
wip: create dynamic voice channel system
Browse files Browse the repository at this point in the history
  • Loading branch information
christolis committed May 14, 2024
1 parent 34e42d5 commit 51f997f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 3 deletions.
6 changes: 5 additions & 1 deletion application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,9 @@
"fallbackChannelPattern": "java-news-and-changes",
"pollIntervalInMinutes": 10
},
"memberCountCategoryPattern": "Info"
"memberCountCategoryPattern": "Info",
"dynamicVoiceChannelPattern": [
"Gaming",
"Chit Chat"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new PinnedNotificationRemover(config));

// Voice receivers
features.add(new DynamicVoiceListener());
features.add(new DynamicVoiceListener(config));

// Event receivers
features.add(new RejoinModerationRoleListener(actionsStore, config));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,141 @@
package org.togetherjava.tjbot.features.dynamicvc;

import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;

import org.togetherjava.tjbot.config.Config;
import org.togetherjava.tjbot.features.VoiceReceiverAdapter;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class DynamicVoiceListener extends VoiceReceiverAdapter {

private final Map<String, Predicate<String>> patterns = new HashMap<>();
private static final Pattern channelTopicPattern = Pattern.compile("(\\s+\\d+)$");

public DynamicVoiceListener(Config config) {
config.getDynamicVoiceChannelPatterns()
.forEach(pattern -> patterns.put(pattern, Pattern.compile(pattern).asMatchPredicate()));
}

@Override
public void onVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) {
// TODO: Complete
AudioChannelUnion joinChannel = event.getChannelJoined();
AudioChannelUnion leftChannel = event.getChannelLeft();

if (joinChannel != null && leftChannel != null) {
if (!getChannelTopic(joinChannel.getName())
.equals(getChannelTopic(leftChannel.getName()))) {
handleTopicUpdate(event, joinChannel);
handleTopicUpdate(event, leftChannel);
return;
}
}

if (joinChannel != null) {
handleTopicUpdate(event, joinChannel);
} else if (leftChannel != null) {
handleTopicUpdate(event, leftChannel);
}
}

private void handleTopicUpdate(GuildVoiceUpdateEvent event, AudioChannelUnion channel) {
if (channel == null) {
return;
}

Guild guild = event.getGuild();
String channelTopic = getChannelTopic(channel.getName());

if (patterns.get(channelTopic) == null) {
return;
}

long emptyChannelsCount = getEmptyChannelsCountFromTopic(guild, channelTopic);

if (emptyChannelsCount == 0) {
createVoiceChannelFromTopic(channel, getChannelCountFromTopic(guild, channelTopic));
} else if (emptyChannelsCount != 1) {
removeDuplicateEmptyChannels(guild, channelTopic);
}
}

private static void createVoiceChannelFromTopic(AudioChannelUnion originalChannel,
long topicChannelsCount) {
String channelTopic = getChannelTopic(originalChannel.getName());

originalChannel.createCopy()
.setName(getNumberedChannelTopic(channelTopic, topicChannelsCount + 1))
.setPosition(originalChannel.getPositionRaw())
.queue();

}

private void removeDuplicateEmptyChannels(Guild guild, String channelTopic) {
List<VoiceChannel> channelsToRemove = getVoiceChannelsFromTopic(guild, channelTopic)
.filter(channel -> channel.getMembers().isEmpty())
.toList();

channelsToRemove.subList(1, channelsToRemove.size())
.forEach(channel -> channel.delete().queue(success -> {
List<VoiceChannel> channels =
getVoiceChannelsFromTopic(guild, channelTopic).toList();

IntStream.range(0, channels.size())
.asLongStream()
.mapToObj(number -> Pair.of(number + 1, channels.get((int) number)))
.filter(pair -> pair.getLeft() != 1)
.forEach(pair -> {
long number = pair.getLeft();
VoiceChannel voiceChannel = pair.getRight();
String voiceChannelNameTopic = getChannelTopic(voiceChannel.getName());

voiceChannel.getManager()
.setName(getNumberedChannelTopic(voiceChannelNameTopic, number))
.queue();
});
}));
}

private long getChannelCountFromTopic(Guild guild, String channelTopic) {
return getVoiceChannelsFromTopic(guild, channelTopic).count();
}

private Stream<VoiceChannel> getVoiceChannelsFromTopic(Guild guild, String channelTopic) {
return guild.getVoiceChannels()
.stream()
.filter(channel -> patterns.get(channelTopic).test(getChannelTopic(channel.getName())));
}

private long getEmptyChannelsCountFromTopic(Guild guild, String channelTopic) {
return getVoiceChannelsFromTopic(guild, channelTopic)
.map(channel -> channel.getMembers().size())
.filter(number -> number == 0)
.count();
}

private static String getChannelTopic(String channelName) {
Matcher matcher = channelTopicPattern.matcher(channelName);

if (matcher.find()) {
return matcher.replaceAll("");
}

return channelName;
}

private static String getNumberedChannelTopic(String channelTopic, long id) {
return String.format("%s %d", channelTopic, id);
}
}

0 comments on commit 51f997f

Please sign in to comment.