Initial Commit

This commit is contained in:
Isaac Parenteau
2019-10-03 00:13:27 -05:00
commit 62d19faa40
8 changed files with 647 additions and 0 deletions

View File

@ -0,0 +1,32 @@
package net.locusworks.discord.eighttrack.handlers;
import java.nio.ByteBuffer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
import net.dv8tion.jda.api.audio.AudioSendHandler;
public class EightTrackAudioSendHandler implements AudioSendHandler {
private final AudioPlayer audioPlayer;
private AudioFrame lastFrame;
public EightTrackAudioSendHandler(AudioPlayer audioPlayer) {
this.audioPlayer = audioPlayer;
}
public boolean canProvide() {
lastFrame = audioPlayer.provide();
return lastFrame != null;
}
public ByteBuffer provide20MsAudio() {
return ByteBuffer.wrap(lastFrame.getData());
}
public boolean isOpus() {
return true;
}
}

View File

@ -0,0 +1,154 @@
package net.locusworks.discord.eighttrack.main;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.OffsetDateTime;
import java.util.Iterator;
import javax.security.auth.login.LoginException;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.managers.AudioManager;
import net.locusworks.discord.eighttrack.handlers.EightTrackAudioSendHandler;
import net.locusworks.discord.eighttrack.scheduler.TrackScheduler;
import net.locusworks.logger.ApplicationLogger;
import net.locusworks.logger.ApplicationLoggerFactory;
public class Entry {
public static void main(String[] args) throws LoginException, IOException {
if (args.length < 1) throw new RuntimeException("no token provided");
ApplicationLogger logger = ApplicationLoggerFactory.getLogger(Entry.class);
logger.info("Starting Eight-Track");
JDA client = new JDABuilder(AccountType.BOT).setToken(args[0]).build();
AudioPlayerManager apm = new DefaultAudioPlayerManager();
AudioSourceManagers.registerLocalSource(apm);
final AudioPlayer player = apm.createPlayer();
TrackScheduler ts = new TrackScheduler();
player.addListener(ts);
for (Iterator<Path> iter = Files.list(Paths.get(args[1])).iterator(); iter.hasNext();) {
Path song = iter.next();
if (!song.getFileName().toString().toLowerCase().endsWith(".mp3")) continue;
logger.info("Loading song: %s", song);
try {
apm.loadItem(song.toAbsolutePath().toString(), ts);
} catch (IllegalStateException ex) {
logger.warn("Unable to load song :%s -> %s", song.toAbsolutePath().toString(), ex.getMessage());
}
}
client.addEventListener(new ListenerAdapter() {
@Override
public void onMessageReceived(final MessageReceivedEvent event) {
if (event.getAuthor().isBot()) return;
String command = event.getMessage().getContentRaw().trim().toLowerCase();
switch (command) {
case "-play":
play(event, ts, player);
return;
case "-stop":
stop(event, ts, player);
return;
case "-next":
next(event, ts, player);
return;
case "-repeat":
repeat(event, ts, player);
return;
case "-whatsnext":
whatsNext(event, ts, player);
default:
return;
}
}
});
}
protected static void whatsNext(MessageReceivedEvent event, TrackScheduler ts, AudioPlayer player) {
AudioTrack track = ts.peek();
MessageEmbed embed = new EmbedBuilder()
.setAuthor(event.getMember().getEffectiveName(), null, event.getAuthor().getAvatarUrl())
.setTitle("Next Up:")
.setDescription(String.format("**%s** by __%s__", track.getInfo().title, track.getInfo().author))
.setTimestamp(OffsetDateTime.now())
.build();
event.getTextChannel().sendMessage(embed).queue();
}
protected static void repeat(MessageReceivedEvent event, TrackScheduler ts, AudioPlayer player) {
next(event, ts, player);
ts.setFinishedCallback((ater) -> {
next(event, ts, player);
});
}
protected static void next(MessageReceivedEvent event, TrackScheduler ts, AudioPlayer player) {
stop(event, ts, player);
play(event, ts, player);
}
private static void stop(MessageReceivedEvent event, TrackScheduler ts, AudioPlayer player) {
player.stopTrack();
}
private static void play(MessageReceivedEvent event, TrackScheduler ts, AudioPlayer player) {
VoiceChannel vc = event.getMember().getVoiceState().getChannel();
if (vc == null) {
event.getTextChannel().sendMessage(String.format("<@%s you are not in a voice channel to play music", event.getMember().getId())).queue();
return;
}
if (!event.getGuild().getSelfMember().hasPermission(vc, Permission.VOICE_CONNECT, Permission.VOICE_SPEAK)) {
event.getTextChannel().sendMessage(String.format("<@%s, I cannot play my music in channel %s as I dont have permission to",
event.getMember().getId(), vc.getName())).queue();
return;
}
AudioManager manager = event.getGuild().getAudioManager();
manager.openAudioConnection(vc);
manager.setSendingHandler(new EightTrackAudioSendHandler(player));
if (ts.hasTracks()) {
AudioTrack track = ts.getNextTrack();
MessageEmbed embed = new EmbedBuilder()
.setAuthor(event.getMember().getEffectiveName(), null, event.getAuthor().getAvatarUrl())
.setTitle("Now Playing:")
.setDescription(String.format("**%s** by __%s__", track.getInfo().title, track.getInfo().author))
.setTimestamp(OffsetDateTime.now())
.build();
event.getTextChannel().sendMessage(embed).queue();
player.playTrack(track);
ts.trackLoaded(track);
}
}
}

View File

@ -0,0 +1,80 @@
package net.locusworks.discord.eighttrack.scheduler;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventListener;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
public class TrackScheduler extends AudioEventAdapter implements AudioEventListener, AudioLoadResultHandler {
private Queue<AudioTrack> trackQueue;
private boolean started;
private Consumer<AudioTrackEndReason> finished;
public TrackScheduler() {
trackQueue = new LinkedBlockingQueue<AudioTrack>();
}
@Override
public void onTrackStart(AudioPlayer player, AudioTrack track) {
this.started = true;
super.onTrackStart(player, track);
}
@Override
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
this.started = false;
super.onTrackEnd(player, track, endReason);
if (finished != null) finished.accept(endReason);
}
public void setFinishedCallback(Consumer<AudioTrackEndReason> callback) {
if (this.finished == null) this.finished = callback;
}
public void trackLoaded(AudioTrack track) {
trackQueue.add(track);
}
public void playlistLoaded(AudioPlaylist playlist) {
for (AudioTrack at : playlist.getTracks()) {
trackQueue.add(at);
}
}
public void noMatches() {
// TODO Auto-generated method stub
}
public void loadFailed(FriendlyException exception) {
// TODO Auto-generated method stub
}
public AudioTrack peek() {
return trackQueue.peek();
}
public boolean hasTracks() {
return !trackQueue.isEmpty();
}
public AudioTrack getNextTrack() {
return trackQueue.poll();
}
public boolean playing() {
return started;
}
}

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Configuration status="WARN" shutdownHook="disable"
packages="net.locusworks.discord.eighttrack">
<Properties>
<property name="logLevel">${sys:LOG_LEVEL:-INFO}</property>
<Property name="logFormat">%d{dd-MMM-yyyy HH:mm:ss.SSS} [%-5p] [%c{1}] %m%n</Property>
</Properties>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="${logFormat}" />
</Console>
<RollingFile name="eighttrack"
fileName="eighttrack.log"
filePattern="eighttrackLO-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="${logFormat}" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="ConsoleAppender" level="${logLevel}" />
<AppenderRef ref="eighttrack" level="${logLevel}" />
</Root>
</Loggers>
</Configuration>