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>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>4.0.0_47</version>
<version>4.0.0_50</version>
<exclusions>
<exclusion>
<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")
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.hooks.ListenerAdapter;
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.GuildMusicService;
import net.locusworks.discord.eighttrack.services.GuildSongRepoService;
@ -57,18 +56,12 @@ public class DiscordEventHandler extends ListenerAdapter {
@Autowired
private ConfigurationService confService;
@Autowired
private GuildRepository guildRepo;
@Autowired
private GuildMusicService musicService;
@Autowired
private Mp3UploadHandler uploadHandler;
@Autowired
private GuildSongRepoService guildSongRepoService;
@PostConstruct
private void init() throws IOException {
this.musicDir = confService.getMusicDirectory();
@ -81,7 +74,7 @@ public class DiscordEventHandler extends ListenerAdapter {
public void onGuildJoin(GuildJoinEvent event) {
try {
long guildId = event.getGuild().getIdLong();
DiscordGuild discordGuild = guildRepo.findByGuildId(guildId);
DiscordGuild discordGuild = guildSongRepoService.getGuildRepo().findByGuildId(guildId);
if (discordGuild != null) return;
logger.debug("Joining Server: " + event.getGuild().getName());
@ -91,7 +84,7 @@ public class DiscordEventHandler extends ListenerAdapter {
discordGuild.setGuildName(event.getGuild().getName());
discordGuild.setDateJoined(new Date());
guildRepo.save(discordGuild);
guildSongRepoService.getGuildRepo().save(discordGuild);
} catch (Exception 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())) {
musicService.put(event.getGuild().getIdLong(),
if (!GuildMusicService.getMap().containsKey(event.getGuild().getIdLong())) {
GuildMusicService.getMap().put(event.getGuild().getIdLong(),
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();
@ -129,6 +123,7 @@ public class DiscordEventHandler extends ListenerAdapter {
case "-stop":
gmh.isPlaying(false);
gmh.stop(event);
event.getGuild().getAudioManager().closeAudioConnection();
return;
case "-next":
gmh.next(event);
@ -140,9 +135,6 @@ public class DiscordEventHandler extends ListenerAdapter {
case "-whatsnext":
gmh.whatsNext(event);
break;
case "-index":
gmh.index(event);
break;
default:
return;
}

View File

@ -35,6 +35,7 @@ import java.nio.file.Path;
import java.time.OffsetDateTime;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
@ -94,9 +95,12 @@ public class GuildMusicHandler {
this.ts = new TrackScheduler();
player.addListener(ts);
indexFiles();
}
public Long getCurrentVoiceChannelId() {
return voiceChannelId;
}
public OffsetDateTime getLastPlayed() {
return lastPlayed;
}
@ -109,34 +113,10 @@ public class GuildMusicHandler {
this.playing.set(playing);
}
public void indexFiles() throws IOException {
List<GuildSong> songs = guildSongRepoService.getGuildSongRepo().findByGuild(guildId);
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 whatsNext(GuildMessageReceivedEvent event) throws Exception {
if (ts.peek() == null) {
loadRandomSong();
}
}
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();
MessageEmbed embed = new EmbedBuilder()
.setAuthor(event.getMember().getEffectiveName(), null, event.getAuthor().getAvatarUrl())
@ -147,15 +127,19 @@ public class GuildMusicHandler {
event.getChannel().sendMessage(embed).queue();
}
public void repeat(GuildMessageReceivedEvent event) {
public void repeat(GuildMessageReceivedEvent event) throws Exception {
next(event);
ts.setFinishedCallback((ater) -> {
if (!playing.get()) return;
next(event);
try {
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);
if (gc != null && gc.getMembers().size() == 1) {
@ -173,9 +157,10 @@ public class GuildMusicHandler {
public void stop(GuildMessageReceivedEvent event) {
player.stopTrack();
voiceChannelId = null;
}
public void play(GuildMessageReceivedEvent event) {
public void play(GuildMessageReceivedEvent event) throws Exception {
VoiceChannel vc = event.getMember().getVoiceState().getChannel();
if (vc == null) {
event.getChannel().sendMessage(String.format("<@%s> you are not in a voice channel to play music", event.getMember().getId())).queue();
@ -187,13 +172,25 @@ public class GuildMusicHandler {
event.getMember().getId(), vc.getName())).queue();
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();
manager.openAudioConnection(vc);
manager.setSendingHandler(new EightTrackAudioSendHandler(player));
if (!ts.hasTracks()) {
loadRandomSong();
}
if (ts.hasTracks()) {
lastPlayed = OffsetDateTime.now();
@ -209,7 +206,6 @@ public class GuildMusicHandler {
event.getChannel().sendMessage(embed).queue();
player.playTrack(track);
ts.trackLoaded(track);
}
}
@ -329,6 +325,19 @@ public class GuildMusicHandler {
.build();
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.entities.Guild;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.locusworks.discord.eighttrack.database.repos.GuildRepository;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
@ -58,15 +59,15 @@ public class DatabaseCleanupService {
@Autowired
private GuildRepository guildRepo;
@Autowired
private GuildMusicService musicService;
private JDA client;
public void setClient(JDA client) {
this.client = client;
}
/**
* Close out connections that are no long being played. clean up resources
*/
@Scheduled(fixedRate = 5 * MINUTE)
private void checkPlayers() {
if (client == null) {
@ -76,22 +77,35 @@ public class DatabaseCleanupService {
logger.debug("Checking players to see if anyone is listening");
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();
GuildMusicHandler gmh = entry.getValue();
long guildId = entry.getKey();
Guild guild = client.getGuildById(guildId);
if (guild == null) {
iterator.remove();
continue;
}
OffsetDateTime lastPlayed = gmh.getLastPlayed();
Duration duration = Duration.between(lastPlayed, now);
if (duration.getSeconds() > 300) {
Guild guild = client.getGuildById(guildId);
if (guild == null) {
iterator.remove();
continue;
}
if (duration.toMillis() > 5 * MINUTE) {
guild.getAudioManager().closeAudioConnection();
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;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Service;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
@Service
public class GuildMusicService extends ConcurrentHashMap<Long, GuildMusicHandler> {
private static final long serialVersionUID = -120204711554552975L;
public class GuildMusicService {
private static Map<Long, GuildMusicHandler> handlerMap = new ConcurrentHashMap<>();
public static Map<Long, GuildMusicHandler> getMap() {
return handlerMap;
}
}