Compare commits
No commits in common. "8f29ee87e3af1cd0708e5a5e8511fe8c025971b5" and "536ea6ca2fd3207dfb828b33a52d9f2d8350a02d" have entirely different histories.
8f29ee87e3
...
536ea6ca2f
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<actions>
|
||||
<action>
|
||||
<actionName>run</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:1.5.0:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-classpath %classpath moe.nekojimi.chords.Main ODkwNjU5MjI2NDE2OTg0MDY0.YUzBCw.jHZWpIZSYeaYA7Sc7h93W_jV-rk</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
<action>
|
||||
<actionName>debug</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:1.5.0:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath moe.nekojimi.chords.Main ODkwNjU5MjI2NDE2OTg0MDY0.YUzBCw.jHZWpIZSYeaYA7Sc7h93W_jV-rk</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
<jpda.listen>true</jpda.listen>
|
||||
</properties>
|
||||
</action>
|
||||
<action>
|
||||
<actionName>profile</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:1.5.0:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-classpath %classpath ${packageClassName} ODkwNjU5MjI2NDE2OTg0MDY0.YUzBCw.jHZWpIZSYeaYA7Sc7h93W_jV-rk</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
</actions>
|
27
pom.xml
27
pom.xml
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>moe.nekojimi</groupId>
|
||||
<artifactId>Chords</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>dv8tion</id>
|
||||
<name>m2-dv8tion</name>
|
||||
<url>https://m2.dv8tion.net/releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.dv8tion</groupId>
|
||||
<artifactId>JDA</artifactId>
|
||||
<version>4.3.0_277</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
</project>
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.chords;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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.AudioReceiveHandler;
|
||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
||||
import net.dv8tion.jda.api.audio.CombinedAudio;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.managers.AudioManager;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import net.dv8tion.jda.api.utils.Compression;
|
||||
import net.dv8tion.jda.api.utils.cache.CacheFlag;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public class Main extends ListenerAdapter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) throws LoginException
|
||||
{
|
||||
// We only need 2 gateway intents enabled for this example:
|
||||
EnumSet<GatewayIntent> intents = EnumSet.of(
|
||||
// We need messages in guilds to accept commands from users
|
||||
GatewayIntent.GUILD_MESSAGES,
|
||||
// We need voice states to connect to the voice channel
|
||||
GatewayIntent.GUILD_VOICE_STATES
|
||||
);
|
||||
|
||||
JDABuilder builder = JDABuilder.createDefault(args[0], intents);
|
||||
|
||||
// Disable parts of the cache
|
||||
builder.disableCache(CacheFlag.MEMBER_OVERRIDES, CacheFlag.VOICE_STATE);
|
||||
// Enable the bulk delete event
|
||||
builder.setBulkDeleteSplittingEnabled(false);
|
||||
// Disable compression (not recommended)
|
||||
builder.setCompression(Compression.NONE);
|
||||
// Set activity (like "playing Something")
|
||||
builder.setActivity(Activity.playing("music!"));
|
||||
|
||||
builder.addEventListeners(new Main());
|
||||
|
||||
JDA jda = builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageReceived(GuildMessageReceivedEvent event)
|
||||
{
|
||||
Message message = event.getMessage();
|
||||
User author = message.getAuthor();
|
||||
String content = message.getContentRaw();
|
||||
Guild guild = event.getGuild();
|
||||
|
||||
// Ignore message if bot
|
||||
if (author.isBot())
|
||||
return;
|
||||
|
||||
if (content.startsWith("!join "))
|
||||
{
|
||||
String arg = content.substring("!join ".length());
|
||||
onJoinCommand(event, guild, arg);
|
||||
}
|
||||
else if (content.equals("!join"))
|
||||
{
|
||||
onJoinCommand(event);
|
||||
}
|
||||
else if (content.startsWith("!play "))
|
||||
{
|
||||
String arg = content.substring("!join ".length());
|
||||
onPlayCommand(event, guild, arg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command without arguments.
|
||||
*
|
||||
* @param event
|
||||
* The event for this command
|
||||
*/
|
||||
private void onJoinCommand(GuildMessageReceivedEvent event)
|
||||
{
|
||||
// Note: None of these can be null due to our configuration with the JDABuilder!
|
||||
Member member = event.getMember(); // Member is the context of the user for the specific guild, containing voice state and roles
|
||||
GuildVoiceState voiceState = member.getVoiceState(); // Check the current voice state of the user
|
||||
VoiceChannel channel = voiceState.getChannel(); // Use the channel the user is currently connected to
|
||||
if (channel != null)
|
||||
{
|
||||
connectTo(channel); // Join the channel of the user
|
||||
onConnecting(channel, event.getChannel()); // Tell the user about our success
|
||||
}
|
||||
else
|
||||
{
|
||||
onUnknownChannel(event.getChannel(), "your voice channel"); // Tell the user about our failure
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command with arguments.
|
||||
*
|
||||
* @param event
|
||||
* The event for this command
|
||||
* @param guild
|
||||
* The guild where its happening
|
||||
* @param arg
|
||||
* The input argument
|
||||
*/
|
||||
private void onJoinCommand(GuildMessageReceivedEvent event, Guild guild, String arg)
|
||||
{
|
||||
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?
|
||||
{
|
||||
List<VoiceChannel> channels = guild.getVoiceChannelsByName(arg, true);
|
||||
if (!channels.isEmpty()) // Make sure we found at least one exact match
|
||||
channel = channels.get(0); // We found a channel! This cannot be null.
|
||||
}
|
||||
|
||||
TextChannel textChannel = event.getChannel();
|
||||
if (channel == null) // I have no idea what you want mr user
|
||||
{
|
||||
onUnknownChannel(textChannel, arg); // Let the user know about our failure
|
||||
return;
|
||||
}
|
||||
connectTo(channel); // We found a channel to connect to!
|
||||
onConnecting(channel, textChannel); // Let the user know, we were successful!
|
||||
}
|
||||
|
||||
private void onPlayCommand(GuildMessageReceivedEvent event, Guild guild, String arg)
|
||||
{
|
||||
try
|
||||
{
|
||||
event.getChannel().sendMessage("Downloading ...").queue();
|
||||
String destination = downloadSong(arg);
|
||||
musicHandler.addSong(new File(destination));
|
||||
event.getChannel().sendMessage("Downloaded and added to queue!").queue();
|
||||
|
||||
} catch (IOException | InterruptedException | RuntimeException ex)
|
||||
{
|
||||
event.getChannel().sendMessage("Failed to download! Reason: " + ex.getMessage()).queue();
|
||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String downloadSong(String arg) throws IOException, RuntimeException, InterruptedException
|
||||
{
|
||||
String cmd = "/usr/bin/youtube-dl -x --audio-format=wav "+arg;
|
||||
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);
|
||||
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();
|
||||
String destination = matcher.group(1);
|
||||
return destination;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inform user about successful connection.
|
||||
*
|
||||
* @param channel
|
||||
* The voice channel we connected to
|
||||
* @param textChannel
|
||||
* The text channel to send the message in
|
||||
*/
|
||||
private void onConnecting(VoiceChannel channel, TextChannel textChannel)
|
||||
{
|
||||
textChannel.sendMessage("Connecting to " + channel.getName()).queue(); // never forget to queue()!
|
||||
}
|
||||
|
||||
/**
|
||||
* The channel to connect to is not known to us.
|
||||
*
|
||||
* @param channel
|
||||
* The message channel (text channel abstraction) to send failure information to
|
||||
* @param comment
|
||||
* The information of this channel
|
||||
*/
|
||||
private void onUnknownChannel(MessageChannel channel, String comment)
|
||||
{
|
||||
channel.sendMessage("Unable to connect to ``" + comment + "``, no such channel!").queue(); // never forget to queue()!
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to requested channel and start echo handler
|
||||
*
|
||||
* @param channel
|
||||
* The channel to connect to
|
||||
*/
|
||||
private void connectTo(VoiceChannel channel)
|
||||
{
|
||||
Guild guild = channel.getGuild();
|
||||
// Get an audio manager for this guild, this will be created upon first use for each guild
|
||||
AudioManager audioManager = guild.getAudioManager();
|
||||
musicHandler = new MusicHandler();
|
||||
// Create our Send/Receive handler for the audio connection
|
||||
// EchoHandler handler = new EchoHandler();
|
||||
|
||||
// The order of the following instructions does not matter!
|
||||
|
||||
// Set the sending handler to our echo system
|
||||
audioManager.setSendingHandler(musicHandler);
|
||||
// Set the receiving handler to the same echo system, otherwise we can't echo anything
|
||||
// audioManager.setReceivingHandler(handler);
|
||||
// Connect to the voice channel
|
||||
audioManager.openAudioConnection(channel);
|
||||
}
|
||||
private MusicHandler musicHandler;
|
||||
|
||||
public static class MusicHandler implements AudioSendHandler, Closeable
|
||||
{
|
||||
private final Queue<File> songQueue = new ConcurrentLinkedQueue<>();
|
||||
private File currentSong;
|
||||
|
||||
private AudioInputStream din = null;
|
||||
private final Queue<byte[]> queue = new ConcurrentLinkedQueue<>();
|
||||
private int byteCount;
|
||||
|
||||
public MusicHandler()
|
||||
{
|
||||
// load whatever songs we have in WAV format
|
||||
// File folder = new File("/home/jimj316/Music/");
|
||||
// List<File> wavs = Arrays.asList(folder.listFiles((file, string) ->
|
||||
// {
|
||||
// return string.endsWith(".wav");
|
||||
// }));
|
||||
// Collections.shuffle(wavs);
|
||||
// songQueue.addAll(wavs);
|
||||
|
||||
// nextSong();
|
||||
}
|
||||
|
||||
public void addSong(File file)
|
||||
{
|
||||
System.out.println("Song added to queue: " + file.getAbsolutePath());
|
||||
|
||||
songQueue.add(file);
|
||||
|
||||
if (!canProvide())
|
||||
nextSong();
|
||||
}
|
||||
|
||||
private boolean nextSong()
|
||||
{
|
||||
AudioInputStream in = null;
|
||||
try
|
||||
{
|
||||
if (din != null)
|
||||
{
|
||||
din.close();
|
||||
din = null;
|
||||
}
|
||||
|
||||
if (currentSong != null)
|
||||
{
|
||||
currentSong.delete();
|
||||
currentSong = null;
|
||||
}
|
||||
|
||||
currentSong = songQueue.poll();
|
||||
if (currentSong == null)
|
||||
return false;
|
||||
System.out.println("Playing song " + currentSong.getAbsolutePath());
|
||||
in = AudioSystem.getAudioInputStream(currentSong);
|
||||
AudioFormat decodedFormat = AudioSendHandler.INPUT_FORMAT;
|
||||
din = AudioSystem.getAudioInputStream(decodedFormat, in);
|
||||
byteCount = 3840;
|
||||
while (queue.size() < 500)
|
||||
{
|
||||
if (!readData())
|
||||
break;
|
||||
}
|
||||
System.out.println("Queue filled to " + queue.size());
|
||||
|
||||
return true;
|
||||
} catch (UnsupportedAudioFileException | IOException ex)
|
||||
{
|
||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally
|
||||
{
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProvide()
|
||||
{
|
||||
// If we have something in our buffer we can provide it to the send system
|
||||
return !queue.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer provide20MsAudio()
|
||||
{
|
||||
// use what we have in our buffer to send audio as PCM
|
||||
while (queue.size() < 500)
|
||||
{
|
||||
if (!readData())
|
||||
{
|
||||
if (!nextSong())
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte[] data = queue.poll();
|
||||
return data == null ? null : ByteBuffer.wrap(data); // Wrap this in a java.nio.ByteBuffer
|
||||
}
|
||||
|
||||
private boolean readData()
|
||||
{
|
||||
if (din == null)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
// if (din.available() == 0)
|
||||
// return false;
|
||||
int bytesToRead = byteCount;
|
||||
if (din.available() > 0 && din.available() < bytesToRead)
|
||||
bytesToRead = din.available();
|
||||
byte[] bytes = new byte[bytesToRead];
|
||||
// byte[] bytes = din.readNBytes(bytesToRead);
|
||||
int read = din.read(bytes);
|
||||
if (read < 0)
|
||||
return false;
|
||||
queue.add(bytes);
|
||||
} catch (IOException ex)
|
||||
{
|
||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpus()
|
||||
{
|
||||
return false; //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
din.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,5 +0,0 @@
|
|||
#Generated by Maven
|
||||
#Thu Sep 23 22:35:54 BST 2021
|
||||
groupId=moe.nekojimi
|
||||
artifactId=Chords
|
||||
version=1.0
|
|
@ -1,4 +0,0 @@
|
|||
moe/nekojimi/chords/Main$MusicHandler.class
|
||||
moe/nekojimi/chords/Main.class
|
||||
moe/nekojimi/chords/Main$EchoHandler.class
|
||||
.netbeans_automatic_build
|
|
@ -1 +0,0 @@
|
|||
/home/jimj316/ownCloud/Programming/Chords/src/main/java/moe/nekojimi/chords/Main.java
|
Loading…
Reference in New Issue