Fix various problems.
This commit is contained in:
parent
367f2b93de
commit
2f7bb13dc6
|
@ -24,9 +24,20 @@ target/
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
|
||||||
# Downloaded audio
|
# Downloaded audio/info
|
||||||
*.wav
|
*.wav
|
||||||
*.wav.tmp
|
*.wav.tmp
|
||||||
|
*.info.json
|
||||||
|
|
||||||
# Syncthing being weird
|
# Syncthing being weird
|
||||||
.syncthing.*
|
.syncthing.*
|
||||||
|
|
||||||
|
# Netbeans
|
||||||
|
**/nbproject/private/
|
||||||
|
**/nbproject/Makefile-*.mk
|
||||||
|
**/nbproject/Package-*.bash
|
||||||
|
build/
|
||||||
|
nbbuild/
|
||||||
|
dist/
|
||||||
|
nbdist/
|
||||||
|
.nb-gradle/
|
||||||
|
|
|
@ -5,26 +5,21 @@
|
||||||
*/
|
*/
|
||||||
package moe.nekojimi.chords;
|
package moe.nekojimi.chords;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.security.auth.login.LoginException;
|
import javax.security.auth.login.LoginException;
|
||||||
import javax.sound.sampled.*;
|
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
import net.dv8tion.jda.api.JDABuilder;
|
import net.dv8tion.jda.api.JDABuilder;
|
||||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
|
||||||
import net.dv8tion.jda.api.entities.*;
|
import net.dv8tion.jda.api.entities.*;
|
||||||
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;
|
||||||
|
@ -81,16 +76,32 @@ public class Main extends ListenerAdapter
|
||||||
if (author.isBot())
|
if (author.isBot())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (content.startsWith("!join "))
|
try
|
||||||
{
|
{
|
||||||
String arg = content.substring("!join ".length());
|
|
||||||
onJoinCommand(event, guild, arg);
|
String arg = "";
|
||||||
} else if (content.equals("!join"))
|
if (content.contains(" "))
|
||||||
onJoinCommand(event);
|
arg = content.split(" ", 2)[1];
|
||||||
else if (content.startsWith("!play "))
|
|
||||||
|
if (content.startsWith("!join "))
|
||||||
|
onJoinCommand(event, guild, arg);
|
||||||
|
else if (content.equals("!join"))
|
||||||
|
onJoinCommand(event);
|
||||||
|
else if (content.startsWith("!play "))
|
||||||
|
onPlayCommand(event, guild, arg);
|
||||||
|
else if (content.startsWith("!queue"))
|
||||||
|
onQueueCommand(event, guild);
|
||||||
|
else if (content.startsWith("!remove "))
|
||||||
|
onRemoveCommand(event, guild, arg);
|
||||||
|
else if (content.startsWith("!restart"))
|
||||||
|
onRestartCommand(event);
|
||||||
|
else if (content.startsWith("!skip"))
|
||||||
|
onSkipCommand(event);
|
||||||
|
else if (content.startsWith("!"))
|
||||||
|
onHelpCommand(event);
|
||||||
|
} catch (Exception ex)
|
||||||
{
|
{
|
||||||
String arg = content.substring("!join ".length());
|
event.getChannel().sendMessage("Error in command! " + ex.getMessage()).queue();
|
||||||
onPlayCommand(event, guild, arg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +140,6 @@ public class Main extends ListenerAdapter
|
||||||
boolean isNumber = arg.matches("\\d+"); // This is a regular expression that ensures the input consists of digits
|
boolean isNumber = arg.matches("\\d+"); // This is a regular expression that ensures the input consists of digits
|
||||||
VoiceChannel channel = null;
|
VoiceChannel channel = null;
|
||||||
if (isNumber) // The input is an id?
|
if (isNumber) // The input is an id?
|
||||||
|
|
||||||
channel = guild.getVoiceChannelById(arg);
|
channel = guild.getVoiceChannelById(arg);
|
||||||
if (channel == null) // Then the input must be a name?
|
if (channel == null) // Then the input must be a name?
|
||||||
{
|
{
|
||||||
|
@ -158,6 +168,8 @@ public class Main extends ListenerAdapter
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
musicHandler.addSong(song);
|
musicHandler.addSong(song);
|
||||||
|
if (musicHandler.isPlaying())
|
||||||
|
musicHandler.setPlaying(true);
|
||||||
event.getChannel().sendMessage("Downloaded and added to queue!").queue();
|
event.getChannel().sendMessage("Downloaded and added to queue!").queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,21 +183,85 @@ public class Main extends ListenerAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onRestartCommand(GuildMessageReceivedEvent event)
|
||||||
|
{
|
||||||
|
// TODO: this needs to clear the current data queue
|
||||||
|
boolean ok = musicHandler.restartSong();
|
||||||
|
if (ok)
|
||||||
|
event.getChannel().sendMessage("Restarted current song!").queue();
|
||||||
|
else
|
||||||
|
event.getChannel().sendMessage("Cannot restart!").queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSkipCommand(GuildMessageReceivedEvent event)
|
||||||
|
{
|
||||||
|
boolean ok = musicHandler.nextSong(true);
|
||||||
|
if (ok)
|
||||||
|
event.getChannel().sendMessage("Skipped to next song!").queue();
|
||||||
|
else
|
||||||
|
event.getChannel().sendMessage("There's no more songs!").queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onQueueCommand(GuildMessageReceivedEvent event, Guild guild)
|
||||||
|
{
|
||||||
|
Queue<Song> songQueue = musicHandler.getSongQueue();
|
||||||
|
String message = new String();
|
||||||
|
int i = 1;
|
||||||
|
message += "Now playing: " + musicHandler.getCurrentSong() + "\n";
|
||||||
|
message += "---\n";
|
||||||
|
for (Song song : songQueue)
|
||||||
|
message += (i) + ": " + song + "\n";
|
||||||
|
event.getChannel().sendMessage(message).queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRemoveCommand(GuildMessageReceivedEvent event, Guild guild, String arg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int i = Integer.parseInt(arg);
|
||||||
|
boolean removed = musicHandler.removeSong(i - 1);
|
||||||
|
final int size = musicHandler.getSongQueue().size();
|
||||||
|
if (removed)
|
||||||
|
event.getChannel().sendMessage("Song removed.").queue();
|
||||||
|
else if (size > 1)
|
||||||
|
event.getChannel().sendMessage("That's not a number between 1 and " + size + "!").queue();
|
||||||
|
else if (size == 1)
|
||||||
|
event.getChannel().sendMessage("There's only one song to remove and that's not one of them!").queue();
|
||||||
|
|
||||||
|
} catch (NumberFormatException ex)
|
||||||
|
{
|
||||||
|
event.getChannel().sendMessage(arg + " isn't a number!").queue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onHelpCommand(GuildMessageReceivedEvent event)
|
||||||
|
{
|
||||||
|
String help = "Commands available:\n"
|
||||||
|
+ "!join <Channel> - Joins a voice channel\n"
|
||||||
|
+ "!play <URL> - Downloads the track at that URL and adds it to the queue.\n"
|
||||||
|
+ "!queue - Show the songs currently playing and the current queue.\n"
|
||||||
|
+ "!remove <Index> - Remove the song at position <Index> from the queue.\n"
|
||||||
|
+ "!skip - Skip the current song and play the next one.\n"
|
||||||
|
+ "!restart - Try playing the current song again in case it goes wrong.\n";
|
||||||
|
event.getChannel().sendMessage(help).queue();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean downloadSong(Song song) throws IOException, RuntimeException, InterruptedException
|
private boolean downloadSong(Song song) throws IOException, RuntimeException, InterruptedException
|
||||||
{
|
{
|
||||||
String cmd = "/usr/bin/youtube-dl -x --audio-format=wav " + song.getUrl().toString();
|
String cmd = "/usr/bin/youtube-dl -x --audio-format=wav --no-playlist --write-info-json " + song.getUrl().toString();
|
||||||
System.out.println("Running command: " + cmd);
|
System.out.println("Running command: " + cmd);
|
||||||
// Process exec = Runtime.getRuntime().exec().split(" "));
|
// Process exec = Runtime.getRuntime().exec().split(" "));
|
||||||
Process exec = new ProcessBuilder(cmd.split(" ")).redirectOutput(ProcessBuilder.Redirect.PIPE).start();
|
Process exec = new ProcessBuilder(cmd.split(" ")).redirectOutput(ProcessBuilder.Redirect.PIPE).start();
|
||||||
exec.waitFor(10000, TimeUnit.MILLISECONDS);
|
exec.waitFor(10, TimeUnit.SECONDS);
|
||||||
InputStream in = exec.getInputStream();
|
InputStream in = exec.getInputStream();
|
||||||
String output = new String(in.readAllBytes(), Charset.defaultCharset());
|
String output = new String(in.readAllBytes(), Charset.defaultCharset());
|
||||||
System.out.println(output);
|
System.out.println(output);
|
||||||
if (exec.exitValue() != 0)
|
|
||||||
throw new RuntimeException("youtube-dl failed with error " + exec.exitValue());
|
|
||||||
Matcher matcher = Pattern.compile("Destination: (.*\\.wav)").matcher(output);
|
Matcher matcher = Pattern.compile("Destination: (.*\\.wav)").matcher(output);
|
||||||
matcher.find();
|
if (matcher.find())
|
||||||
song.setLocation(new File(matcher.group(0)));
|
song.setLocation(new File(matcher.group(1)));
|
||||||
|
else
|
||||||
|
if (exec.exitValue() != 0)
|
||||||
|
throw new RuntimeException("youtube-dl failed with error " + exec.exitValue());
|
||||||
return true;
|
return true;
|
||||||
// String destination = matcher.group(1);
|
// String destination = matcher.group(1);
|
||||||
// return destination;
|
// return destination;
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
package moe.nekojimi.chords;
|
package moe.nekojimi.chords;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
@ -26,12 +26,15 @@ import net.dv8tion.jda.api.audio.AudioSendHandler;
|
||||||
public class MusicHandler implements AudioSendHandler, Closeable
|
public class MusicHandler implements AudioSendHandler, Closeable
|
||||||
{
|
{
|
||||||
|
|
||||||
private final Queue<Song> songQueue = new ConcurrentLinkedQueue<>();
|
private final LinkedList<Song> songQueue = new LinkedList<>();
|
||||||
private Song currentSong;
|
private Song currentSong;
|
||||||
private AudioInputStream din = null;
|
private AudioInputStream din = null;
|
||||||
private final Queue<byte[]> queue = new ConcurrentLinkedQueue<>();
|
private final Queue<byte[]> queue = new ConcurrentLinkedQueue<>();
|
||||||
|
private boolean playing = true;
|
||||||
private int byteCount;
|
private int byteCount;
|
||||||
|
|
||||||
|
private boolean arrayErr = false;
|
||||||
|
|
||||||
public MusicHandler()
|
public MusicHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -40,12 +43,44 @@ public class MusicHandler implements AudioSendHandler, Closeable
|
||||||
{
|
{
|
||||||
System.out.println("Song added to queue: " + song.getLocation().getAbsolutePath());
|
System.out.println("Song added to queue: " + song.getLocation().getAbsolutePath());
|
||||||
songQueue.add(song);
|
songQueue.add(song);
|
||||||
if (!canProvide())
|
if (!canProvide() && playing)
|
||||||
nextSong();
|
nextSong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean removeSong(int i)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
songQueue.remove(i);
|
||||||
|
return true;
|
||||||
|
} catch (ArrayIndexOutOfBoundsException ex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeSong(Song song)
|
||||||
|
{
|
||||||
|
return songQueue.remove(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean restartSong()
|
||||||
|
{
|
||||||
|
songQueue.addFirst(currentSong);
|
||||||
|
currentSong = null;
|
||||||
|
return nextSong(true);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean nextSong()
|
private boolean nextSong()
|
||||||
{
|
{
|
||||||
|
return nextSong(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean nextSong(boolean immediate)
|
||||||
|
{
|
||||||
|
if (immediate)
|
||||||
|
queue.clear();
|
||||||
|
|
||||||
AudioInputStream in = null;
|
AudioInputStream in = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -63,6 +98,7 @@ public class MusicHandler implements AudioSendHandler, Closeable
|
||||||
if (currentSong == null)
|
if (currentSong == null)
|
||||||
return false;
|
return false;
|
||||||
System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath());
|
System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath());
|
||||||
|
arrayErr = false;
|
||||||
in = AudioSystem.getAudioInputStream(currentSong.getLocation());
|
in = AudioSystem.getAudioInputStream(currentSong.getLocation());
|
||||||
AudioFormat decodedFormat = AudioSendHandler.INPUT_FORMAT;
|
AudioFormat decodedFormat = AudioSendHandler.INPUT_FORMAT;
|
||||||
din = AudioSystem.getAudioInputStream(decodedFormat, in);
|
din = AudioSystem.getAudioInputStream(decodedFormat, in);
|
||||||
|
@ -81,11 +117,23 @@ public class MusicHandler implements AudioSendHandler, Closeable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPlaying()
|
||||||
|
{
|
||||||
|
return playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlaying(boolean playing)
|
||||||
|
{
|
||||||
|
if (!this.playing && playing)
|
||||||
|
nextSong();
|
||||||
|
this.playing = playing;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canProvide()
|
public boolean canProvide()
|
||||||
{
|
{
|
||||||
// If we have something in our buffer we can provide it to the send system
|
// If we have something in our buffer we can provide it to the send system
|
||||||
return !queue.isEmpty();
|
return !queue.isEmpty() && playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -121,10 +169,29 @@ public class MusicHandler implements AudioSendHandler, Closeable
|
||||||
{
|
{
|
||||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
return false;
|
return false;
|
||||||
|
} catch (ArrayIndexOutOfBoundsException ex)
|
||||||
|
{
|
||||||
|
if (!arrayErr)
|
||||||
|
arrayErr = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Queue<Song> getSongQueue()
|
||||||
|
{
|
||||||
|
return songQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Song getCurrentSong()
|
||||||
|
{
|
||||||
|
return currentSong;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOpus()
|
public boolean isOpus()
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,7 +61,17 @@ public class Song
|
||||||
|
|
||||||
void delete()
|
void delete()
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
if (location != null)
|
||||||
|
location.delete();
|
||||||
|
location = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
if (title != null && !title.isEmpty())
|
||||||
|
return title;
|
||||||
|
else
|
||||||
|
return url.toExternalForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue