From 2f7bb13dc645c97a59a5517ffd363c9fc67a5745 Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Mon, 27 Sep 2021 22:13:51 +0100 Subject: [PATCH] Fix various problems. --- .gitignore | 15 ++- src/main/java/moe/nekojimi/chords/Main.java | 116 +++++++++++++++--- .../moe/nekojimi/chords/MusicHandler.java | 75 ++++++++++- src/main/java/moe/nekojimi/chords/Song.java | 12 +- .../nekojimi/chords/Main$EchoHandler.class | Bin 1775 -> 0 bytes .../nekojimi/chords/Main$MusicHandler.class | Bin 4372 -> 0 bytes 6 files changed, 191 insertions(+), 27 deletions(-) delete mode 100644 target/classes/moe/nekojimi/chords/Main$EchoHandler.class delete mode 100644 target/classes/moe/nekojimi/chords/Main$MusicHandler.class diff --git a/.gitignore b/.gitignore index 6b28229..f141e2b 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,20 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* -# Downloaded audio +# Downloaded audio/info *.wav *.wav.tmp +*.info.json # Syncthing being weird -.syncthing.* \ No newline at end of file +.syncthing.* + +# Netbeans +**/nbproject/private/ +**/nbproject/Makefile-*.mk +**/nbproject/Package-*.bash +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ diff --git a/src/main/java/moe/nekojimi/chords/Main.java b/src/main/java/moe/nekojimi/chords/Main.java index da95c82..97682fd 100644 --- a/src/main/java/moe/nekojimi/chords/Main.java +++ b/src/main/java/moe/nekojimi/chords/Main.java @@ -5,26 +5,21 @@ */ package moe.nekojimi.chords; -import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.security.auth.login.LoginException; -import javax.sound.sampled.*; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; -import net.dv8tion.jda.api.audio.AudioSendHandler; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; @@ -81,16 +76,32 @@ public class Main extends ListenerAdapter if (author.isBot()) return; - if (content.startsWith("!join ")) + try { - String arg = content.substring("!join ".length()); - onJoinCommand(event, guild, arg); - } else if (content.equals("!join")) - onJoinCommand(event); - else if (content.startsWith("!play ")) + + String arg = ""; + if (content.contains(" ")) + arg = content.split(" ", 2)[1]; + + 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()); - onPlayCommand(event, guild, arg); + event.getChannel().sendMessage("Error in command! " + ex.getMessage()).queue(); } } @@ -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 VoiceChannel channel = null; if (isNumber) // The input is an id? - channel = guild.getVoiceChannelById(arg); if (channel == null) // Then the input must be a name? { @@ -158,6 +168,8 @@ public class Main extends ListenerAdapter if (ok) { musicHandler.addSong(song); + if (musicHandler.isPlaying()) + musicHandler.setPlaying(true); 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 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 - Joins a voice channel\n" + + "!play - 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 - Remove the song at position 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 { - 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); // Process exec = Runtime.getRuntime().exec().split(" ")); 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(); String output = new String(in.readAllBytes(), Charset.defaultCharset()); 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.find(); - song.setLocation(new File(matcher.group(0))); + if (matcher.find()) + song.setLocation(new File(matcher.group(1))); + else + if (exec.exitValue() != 0) + throw new RuntimeException("youtube-dl failed with error " + exec.exitValue()); return true; // String destination = matcher.group(1); // return destination; diff --git a/src/main/java/moe/nekojimi/chords/MusicHandler.java b/src/main/java/moe/nekojimi/chords/MusicHandler.java index 0a5e2e7..9287a73 100644 --- a/src/main/java/moe/nekojimi/chords/MusicHandler.java +++ b/src/main/java/moe/nekojimi/chords/MusicHandler.java @@ -6,9 +6,9 @@ package moe.nekojimi.chords; import java.io.Closeable; -import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; @@ -26,12 +26,15 @@ import net.dv8tion.jda.api.audio.AudioSendHandler; public class MusicHandler implements AudioSendHandler, Closeable { - private final Queue songQueue = new ConcurrentLinkedQueue<>(); + private final LinkedList songQueue = new LinkedList<>(); private Song currentSong; private AudioInputStream din = null; private final Queue queue = new ConcurrentLinkedQueue<>(); + private boolean playing = true; private int byteCount; + private boolean arrayErr = false; + public MusicHandler() { } @@ -40,12 +43,44 @@ public class MusicHandler implements AudioSendHandler, Closeable { System.out.println("Song added to queue: " + song.getLocation().getAbsolutePath()); songQueue.add(song); - if (!canProvide()) + if (!canProvide() && playing) 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() { + return nextSong(false); + } + + public boolean nextSong(boolean immediate) + { + if (immediate) + queue.clear(); + AudioInputStream in = null; try { @@ -63,6 +98,7 @@ public class MusicHandler implements AudioSendHandler, Closeable if (currentSong == null) return false; System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath()); + arrayErr = false; in = AudioSystem.getAudioInputStream(currentSong.getLocation()); AudioFormat decodedFormat = AudioSendHandler.INPUT_FORMAT; din = AudioSystem.getAudioInputStream(decodedFormat, in); @@ -81,11 +117,23 @@ public class MusicHandler implements AudioSendHandler, Closeable return false; } + public boolean isPlaying() + { + return playing; + } + + public void setPlaying(boolean playing) + { + if (!this.playing && playing) + nextSong(); + this.playing = playing; + } + @Override public boolean canProvide() { // If we have something in our buffer we can provide it to the send system - return !queue.isEmpty(); + return !queue.isEmpty() && playing; } @Override @@ -121,10 +169,29 @@ public class MusicHandler implements AudioSendHandler, Closeable { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); return false; + } catch (ArrayIndexOutOfBoundsException ex) + { + if (!arrayErr) + arrayErr = true; + else + { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + return false; + } } return true; } + public Queue getSongQueue() + { + return songQueue; + } + + public Song getCurrentSong() + { + return currentSong; + } + @Override public boolean isOpus() { diff --git a/src/main/java/moe/nekojimi/chords/Song.java b/src/main/java/moe/nekojimi/chords/Song.java index 6971d4c..0608ccf 100644 --- a/src/main/java/moe/nekojimi/chords/Song.java +++ b/src/main/java/moe/nekojimi/chords/Song.java @@ -61,7 +61,17 @@ public class Song 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(); + } } diff --git a/target/classes/moe/nekojimi/chords/Main$EchoHandler.class b/target/classes/moe/nekojimi/chords/Main$EchoHandler.class deleted file mode 100644 index bc0bf05cc989010108ba6feb65b9845234618398..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1775 zcma)6TW=dh6#i!IWNT-gxOS3WfLi#LJJNdwUd&7olD&Y(L7Cdr^zJtuGvda z`6uwmOJ8`P60{9Sh&Lqu4{xaA%5^0z+#+`@w_G^BK- z4GdwJA-~J_x!L8;wz;~sE3ANFcvdoZsOz{*l|MOsk*1Dt?4*D?K4F;tAOCy85^`T0)jZRY+YS#xkE%B@ zkn^bSvzv{%Ix%g!Hf@hlmx-0Iw--3{(ZwN8GfgB?jFyxMw`rX%!% z#hrxJVM8$FIsv!#+Pt5D7I&g1J#evZtq$Ucp{=V(;V7w`|#c!|%*GGc$s;|{GD z8Wbo;3V8a7g;|W%ic88!9<{7~(V3FVy z#eF)MqWNO=872?#HpBNwKdp{E!@F%2sdj*?8opAD;|P<40+xfpMv-HA6d7Gv=~;~Mkx z3gk<)XjB?)nl+lw$Dmb)KVi12e?ezYpjThu{hw(!mKPO-)kxZO6kswwnFPoo7YSjJ z5Chu3n9yN1b$X&0+D9^Kv{Ev(s5II@X>JbC))LedR+KMRu@=qi=+K-cgb}RcJ~ICS D&J=%v diff --git a/target/classes/moe/nekojimi/chords/Main$MusicHandler.class b/target/classes/moe/nekojimi/chords/Main$MusicHandler.class deleted file mode 100644 index 5d1cace4782ba2ffc0fd8f0d16964fa971536d72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4372 zcma)A>vt4q9e&>3O(xk4BrHj|Ly#1bO<)Tmmuv`-5K4461QLQJRyx@ol1Vl*+nw1! zs9Ni#t=9XcR;;Z8HD02&2;ows^#)q?tAB#u{N_2HqbNS_%xu_=fqHV7_x`&+zsvIO ze{S3YuoHg{BY>cSkcu*t3)GBhlUgjJnIo~o!()2N5h!mrOvC9A2sSkjDyR^Mx|i~f zk%^@&GnLQfbkm7-%}o=AIj*OVqrkEWZCsbu)STmnGs>CmXr^OR!>0dzxd5>+n$WBus-gw0 z0!s@L6-h0iWTg%n+O2LOs)JS7f|!CwRcysJ>M_s$w278Z&wK1aCf$*DX@6XW6~RO>8b-Nx+UlGw4Tu&U8?z*ibLoT2xYBIX1;@bog$!6VI+`L z(5vDw`UKWJP{;yqmP+r>1E9bT-{3w-;+_lNOIrf>DEbu)s5pi}Mxm)YvGn9F$FR)U zSXzr|StF)NW*+AIbu&E|OKMMV-?4#{2M-@j?jI0X@7iTSjt8yWgyzsx34B=U`M7}P z$@{SD52jZfdjGegRTxt75j?>pFg)cj81g3LPxMG{omBB8G|Dw1SVR_&7enoU;HEeNtyMl=pWJb|38)Sg{Z> zd52hW@JSWV;!_N8@)79rg(>CiUiPRI=f0wyfzh0GS{r7lHoFPvGb%nSovIji_e9p2 zQt-S$V5l>U&*Ae5UR3b~e6ipRlgRHRS~~NmPD$&8PUo~N0~^KHK|Vrou4$GI0-F;{W7 zP_=vN6=J<3K37MI?hJLx{ZN-Bb7VE^r{0^N7}j$G9)n22N@rm<<_f3{f?FzPik48OHERDMy+(8mLoD9Jx7j<(t3)5 zroBu-f9OQ1UmIP&&IJUS1`Ni_j~)@w>#pXcr<01pnbMaV_Tg-vI)~?Ul8b&TpG)apfv=RE z%NB_WR7YOv)U?){Dd`Pt@XHSSP}Gg}bUp3*W`7TnW5}@9~x7 z<8Tac+;j=cT4u541~ve**c82taLaXU4&Zon7VkfY3JyDuOLoEg?1XH?Yp_y8uwE=> z%USEPtM^Fy>_{BnrwIhkyRXGYT;QZka90Y?_Kjy0M*M}sOC@fJ1o_w8MztJf(dKD= z8GCP2c@DGaIxhG2Mx~tBaZunLtd(mX-hmR_vwDUKc~_~^2Mapwy@n4ZF5yTr+S+mr z$E7WoRO1Rx@M`UKe3YmXe?N~!RCf5>y}wN(=#lZxZa{Ylg*w*EBqNzwnAc!m!jx#8 z#WT~WXbY_fy&asPD+AQ`0!ICD3 z#41#ZHK-A5Q76{(r^N;|ibgbxP1r4(uunAOfQYh}YoQ9Q7#5q^S!_X0#PF=xiWkH- zyePKgHL(L1#7r(J z@?4^YND?{JZlk{Yy`$GH!G|EtO2W7z-PENGT)hxdBD(d~&s`IGwr|qk5RwU(| z`1)$cnpgZswXI%YPNP0ij6%lmGr^hA4B1v<58LiB{siiAM-NXOObiewsPz!>^duGw z4I9KTT0{ylp<|agg?2H54l&AKF%w7#14%K??m2^#!gST&PWvyWci&{v5{MC@m#BUK zyRd|v&J)ZINv62h@e7_(*&@HKMp@-u=81nJLi>n&v>YK)B|l^GN73bisnE)md>wEx z;iWeZ6HXB(0zPdaf9O#H2?S|u`Le>ZVB7ulDF1r`;w*K4x`;-FPvZ*TNSu!GJ1aRe q3a`0ih7k!S(;#l}{2llEYxnzG+~$e=aZrT}?$GAH$Gi9wR{R%FQBJu4