Feature Major updates and bug fixes
Some checks failed
Locusworks Team/eight-track/pipeline/head There was a failure building this commit

#4 Added logic to disconnect the bot if no song is playing or no one is
listening

#10 Added functionality to play song from local source and ability to
upload songs

#10 No longer cashes songs in memory but queries the database for random
song

#10 Whatsnext will push a song on the queue if it doesn't exist

#10 Next will get a random song from the database
This commit is contained in:
Isaac Parenteau
2019-10-07 23:48:05 -05:00
parent fe4c25cc4c
commit 2ac25f64aa
6 changed files with 92 additions and 72 deletions

View File

@ -168,7 +168,7 @@
<dependency> <dependency>
<groupId>net.dv8tion</groupId> <groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId> <artifactId>JDA</artifactId>
<version>4.0.0_47</version> <version>4.0.0_50</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>

View File

@ -50,4 +50,7 @@ public interface GuildSongRepository extends CrudRepository<GuildSong, Long> {
@Query("SELECT gs FROM GuildSong gs WHERE gs.guild.guildId = ?1") @Query("SELECT gs FROM GuildSong gs WHERE gs.guild.guildId = ?1")
List<GuildSong> findByGuild(Long guildId); List<GuildSong> findByGuild(Long guildId);
@Query("SELECT gs FROM GuildSong gs WHERE gs.guild.guildId = ?1 ORDER BY RAND()")
List<GuildSong> findRandomSong(Long guildId);
} }

View File

@ -40,7 +40,6 @@ import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.locusworks.discord.eighttrack.database.entities.DiscordGuild; import net.locusworks.discord.eighttrack.database.entities.DiscordGuild;
import net.locusworks.discord.eighttrack.database.repos.GuildRepository;
import net.locusworks.discord.eighttrack.services.ConfigurationService; import net.locusworks.discord.eighttrack.services.ConfigurationService;
import net.locusworks.discord.eighttrack.services.GuildMusicService; import net.locusworks.discord.eighttrack.services.GuildMusicService;
import net.locusworks.discord.eighttrack.services.GuildSongRepoService; import net.locusworks.discord.eighttrack.services.GuildSongRepoService;
@ -57,12 +56,6 @@ public class DiscordEventHandler extends ListenerAdapter {
@Autowired @Autowired
private ConfigurationService confService; private ConfigurationService confService;
@Autowired
private GuildRepository guildRepo;
@Autowired
private GuildMusicService musicService;
@Autowired @Autowired
private Mp3UploadHandler uploadHandler; private Mp3UploadHandler uploadHandler;
@ -81,7 +74,7 @@ public class DiscordEventHandler extends ListenerAdapter {
public void onGuildJoin(GuildJoinEvent event) { public void onGuildJoin(GuildJoinEvent event) {
try { try {
long guildId = event.getGuild().getIdLong(); long guildId = event.getGuild().getIdLong();
DiscordGuild discordGuild = guildRepo.findByGuildId(guildId); DiscordGuild discordGuild = guildSongRepoService.getGuildRepo().findByGuildId(guildId);
if (discordGuild != null) return; if (discordGuild != null) return;
logger.debug("Joining Server: " + event.getGuild().getName()); logger.debug("Joining Server: " + event.getGuild().getName());
@ -91,7 +84,7 @@ public class DiscordEventHandler extends ListenerAdapter {
discordGuild.setGuildName(event.getGuild().getName()); discordGuild.setGuildName(event.getGuild().getName());
discordGuild.setDateJoined(new Date()); discordGuild.setDateJoined(new Date());
guildRepo.save(discordGuild); guildSongRepoService.getGuildRepo().save(discordGuild);
} catch (Exception ex) { } catch (Exception ex) {
logger.error("Unable to persist server information to database: " + ex.getMessage(), ex); logger.error("Unable to persist server information to database: " + ex.getMessage(), ex);
} }
@ -107,14 +100,15 @@ public class DiscordEventHandler extends ListenerAdapter {
} }
} }
private void onGuildMessageReceivedHelper(GuildMessageReceivedEvent event) throws IOException { private void onGuildMessageReceivedHelper(GuildMessageReceivedEvent event) throws Exception {
if (!musicService.containsKey(event.getGuild().getIdLong())) { if (!GuildMusicService.getMap().containsKey(event.getGuild().getIdLong())) {
musicService.put(event.getGuild().getIdLong(), GuildMusicService.getMap().put(event.getGuild().getIdLong(),
new GuildMusicHandler(musicDir, event.getGuild().getIdLong(), uploadHandler, guildSongRepoService)); new GuildMusicHandler(musicDir, event.getGuild().getIdLong(), uploadHandler, guildSongRepoService));
} }
GuildMusicHandler gmh = musicService.get(event.getGuild().getIdLong());
gmh.accept((id) -> musicService.remove(id)); GuildMusicHandler gmh = GuildMusicService.getMap().get(event.getGuild().getIdLong());
gmh.accept((id) -> GuildMusicService.getMap().remove(id));
String command = event.getMessage().getContentRaw().trim().toLowerCase(); String command = event.getMessage().getContentRaw().trim().toLowerCase();
@ -129,6 +123,7 @@ public class DiscordEventHandler extends ListenerAdapter {
case "-stop": case "-stop":
gmh.isPlaying(false); gmh.isPlaying(false);
gmh.stop(event); gmh.stop(event);
event.getGuild().getAudioManager().closeAudioConnection();
return; return;
case "-next": case "-next":
gmh.next(event); gmh.next(event);
@ -140,9 +135,6 @@ public class DiscordEventHandler extends ListenerAdapter {
case "-whatsnext": case "-whatsnext":
gmh.whatsNext(event); gmh.whatsNext(event);
break; break;
case "-index":
gmh.index(event);
break;
default: default:
return; return;
} }

View File

@ -35,6 +35,7 @@ import java.nio.file.Path;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -94,7 +95,10 @@ public class GuildMusicHandler {
this.ts = new TrackScheduler(); this.ts = new TrackScheduler();
player.addListener(ts); player.addListener(ts);
indexFiles(); }
public Long getCurrentVoiceChannelId() {
return voiceChannelId;
} }
public OffsetDateTime getLastPlayed() { public OffsetDateTime getLastPlayed() {
@ -109,34 +113,10 @@ public class GuildMusicHandler {
this.playing.set(playing); this.playing.set(playing);
} }
public void indexFiles() throws IOException { public void whatsNext(GuildMessageReceivedEvent event) throws Exception {
List<GuildSong> songs = guildSongRepoService.getGuildSongRepo().findByGuild(guildId); if (ts.peek() == null) {
loadRandomSong();
logger.info("Adding %d songs from directory %s", songs.size(), musicDir);
for (GuildSong song : songs) {
logger.debug("Loading song: %s", song.getSong().getFilePath());
try {
apm.loadItem(song.getSong().getFilePath(), ts);
} catch (IllegalStateException ex) {
logger.warn("Unable to load song :%s -> %s", song.getSong().getFilePath(), ex.getMessage());
} }
}
}
public void index(GuildMessageReceivedEvent event) {
event.getChannel().sendMessage(String.format("<@%s>, Please wait as i reindex the music files", event.getAuthor().getId())).queue();
try {
indexFiles();
} catch (IOException e) {
event.getChannel().sendMessage(String.format("<@%s>, Unable to reindex the music files: %s", event.getAuthor().getId(), e.getMessage())).queue();
return;
}
event.getChannel().sendMessage(String.format("<@%s>, Reindexing complete", event.getAuthor().getId())).queue();
}
public void whatsNext(GuildMessageReceivedEvent event) {
AudioTrack track = ts.peek(); AudioTrack track = ts.peek();
MessageEmbed embed = new EmbedBuilder() MessageEmbed embed = new EmbedBuilder()
.setAuthor(event.getMember().getEffectiveName(), null, event.getAuthor().getAvatarUrl()) .setAuthor(event.getMember().getEffectiveName(), null, event.getAuthor().getAvatarUrl())
@ -147,15 +127,19 @@ public class GuildMusicHandler {
event.getChannel().sendMessage(embed).queue(); event.getChannel().sendMessage(embed).queue();
} }
public void repeat(GuildMessageReceivedEvent event) { public void repeat(GuildMessageReceivedEvent event) throws Exception {
next(event); next(event);
ts.setFinishedCallback((ater) -> { ts.setFinishedCallback((ater) -> {
if (!playing.get()) return; if (!playing.get()) return;
try {
next(event); next(event);
} catch (Exception e) {
logger.error(e);
}
}); });
} }
public void next(GuildMessageReceivedEvent event) { public void next(GuildMessageReceivedEvent event) throws Exception {
GuildChannel gc = event.getGuild().getGuildChannelById(ChannelType.VOICE, voiceChannelId); GuildChannel gc = event.getGuild().getGuildChannelById(ChannelType.VOICE, voiceChannelId);
if (gc != null && gc.getMembers().size() == 1) { if (gc != null && gc.getMembers().size() == 1) {
@ -173,9 +157,10 @@ public class GuildMusicHandler {
public void stop(GuildMessageReceivedEvent event) { public void stop(GuildMessageReceivedEvent event) {
player.stopTrack(); player.stopTrack();
voiceChannelId = null;
} }
public void play(GuildMessageReceivedEvent event) { public void play(GuildMessageReceivedEvent event) throws Exception {
VoiceChannel vc = event.getMember().getVoiceState().getChannel(); VoiceChannel vc = event.getMember().getVoiceState().getChannel();
if (vc == null) { if (vc == null) {
event.getChannel().sendMessage(String.format("<@%s> you are not in a voice channel to play music", event.getMember().getId())).queue(); event.getChannel().sendMessage(String.format("<@%s> you are not in a voice channel to play music", event.getMember().getId())).queue();
@ -188,13 +173,25 @@ public class GuildMusicHandler {
return; return;
} }
voiceChannelId = vc.getIdLong(); Long tmpId = vc.getIdLong();
if (voiceChannelId != null && voiceChannelId != tmpId) {
String channelName = event.getGuild().getVoiceChannelById(voiceChannelId).getName();
event.getChannel().sendMessage(String.format("<@%s> I am currently playing in channel %s. Cannot switch channels until I am stopped.",
event.getMember().getId(), channelName)).queue();
return;
}
voiceChannelId = tmpId;
AudioManager manager = event.getGuild().getAudioManager(); AudioManager manager = event.getGuild().getAudioManager();
manager.openAudioConnection(vc); manager.openAudioConnection(vc);
manager.setSendingHandler(new EightTrackAudioSendHandler(player)); manager.setSendingHandler(new EightTrackAudioSendHandler(player));
if (!ts.hasTracks()) {
loadRandomSong();
}
if (ts.hasTracks()) { if (ts.hasTracks()) {
lastPlayed = OffsetDateTime.now(); lastPlayed = OffsetDateTime.now();
@ -209,7 +206,6 @@ public class GuildMusicHandler {
event.getChannel().sendMessage(embed).queue(); event.getChannel().sendMessage(embed).queue();
player.playTrack(track); player.playTrack(track);
ts.trackLoaded(track);
} }
} }
@ -329,6 +325,19 @@ public class GuildMusicHandler {
.build(); .build();
return embed; return embed;
} }
private void loadRandomSong() throws Exception {
List<GuildSong> gsList = guildSongRepoService.getGuildSongRepo().findByGuild(guildId);
if (gsList == null || gsList.isEmpty()) return;
Random random = new Random(System.currentTimeMillis());
int item = random.nextInt(gsList.size());
GuildSong song = gsList.get(item);
apm.loadItem(song.getSong().getFilePath(), ts).get();
}
} }

View File

@ -42,6 +42,7 @@ import org.springframework.stereotype.Service;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.locusworks.discord.eighttrack.database.repos.GuildRepository; import net.locusworks.discord.eighttrack.database.repos.GuildRepository;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler; import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
@ -58,15 +59,15 @@ public class DatabaseCleanupService {
@Autowired @Autowired
private GuildRepository guildRepo; private GuildRepository guildRepo;
@Autowired
private GuildMusicService musicService;
private JDA client; private JDA client;
public void setClient(JDA client) { public void setClient(JDA client) {
this.client = client; this.client = client;
} }
/**
* Close out connections that are no long being played. clean up resources
*/
@Scheduled(fixedRate = 5 * MINUTE) @Scheduled(fixedRate = 5 * MINUTE)
private void checkPlayers() { private void checkPlayers() {
if (client == null) { if (client == null) {
@ -76,22 +77,35 @@ public class DatabaseCleanupService {
logger.debug("Checking players to see if anyone is listening"); logger.debug("Checking players to see if anyone is listening");
OffsetDateTime now = OffsetDateTime.now(); OffsetDateTime now = OffsetDateTime.now();
for(Iterator<Entry<Long, GuildMusicHandler>> iterator = musicService.entrySet().iterator(); iterator.hasNext();) { for(Iterator<Entry<Long, GuildMusicHandler>> iterator = GuildMusicService.getMap().entrySet().iterator(); iterator.hasNext();) {
Entry<Long, GuildMusicHandler> entry = iterator.next(); Entry<Long, GuildMusicHandler> entry = iterator.next();
GuildMusicHandler gmh = entry.getValue(); GuildMusicHandler gmh = entry.getValue();
long guildId = entry.getKey(); long guildId = entry.getKey();
OffsetDateTime lastPlayed = gmh.getLastPlayed();
Duration duration = Duration.between(lastPlayed, now);
if (duration.getSeconds() > 300) {
Guild guild = client.getGuildById(guildId); Guild guild = client.getGuildById(guildId);
if (guild == null) { if (guild == null) {
iterator.remove(); iterator.remove();
continue; continue;
} }
OffsetDateTime lastPlayed = gmh.getLastPlayed();
Duration duration = Duration.between(lastPlayed, now);
if (duration.toMillis() > 5 * MINUTE) {
guild.getAudioManager().closeAudioConnection(); guild.getAudioManager().closeAudioConnection();
iterator.remove(); iterator.remove();
} }
Long voiceChannelId = gmh.getCurrentVoiceChannelId();
if (voiceChannelId == null) {
guild.getAudioManager().closeAudioConnection();
iterator.remove();
} else {
VoiceChannel vc = guild.getVoiceChannelById(voiceChannelId);
if (vc != null && vc.getMembers().size() == 1) {
guild.getAudioManager().closeAudioConnection();
iterator.remove();
}
}
} }
} }

View File

@ -27,15 +27,17 @@
*/ */
package net.locusworks.discord.eighttrack.services; package net.locusworks.discord.eighttrack.services;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Service;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler; import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
@Service public class GuildMusicService {
public class GuildMusicService extends ConcurrentHashMap<Long, GuildMusicHandler> {
private static final long serialVersionUID = -120204711554552975L; private static Map<Long, GuildMusicHandler> handlerMap = new ConcurrentHashMap<>();
public static Map<Long, GuildMusicHandler> getMap() {
return handlerMap;
}
} }