You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
11 KiB
356 lines
11 KiB
/*
|
|
* 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.File;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.time.LocalDateTime;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.util.*;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.Consumer;
|
|
import javax.security.auth.login.LoginException;
|
|
import moe.nekojimi.chords.commands.*;
|
|
import moe.nekojimi.musicsearcher.Result;
|
|
import moe.nekojimi.musicsearcher.providers.MetaSearcher;
|
|
import moe.nekojimi.musicsearcher.providers.Searcher;
|
|
import net.dv8tion.jda.api.JDA;
|
|
import net.dv8tion.jda.api.JDABuilder;
|
|
import net.dv8tion.jda.api.MessageBuilder;
|
|
import net.dv8tion.jda.api.entities.*;
|
|
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent;
|
|
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
|
|
{
|
|
|
|
private MusicHandler musicHandler;
|
|
private final Downloader downloader;
|
|
private final Searcher searcher;
|
|
private JDA jda;
|
|
|
|
private final Map<String, Command> commands = new HashMap<>();
|
|
private final Command helpCommand;
|
|
private PlayCommand playCommand;
|
|
|
|
private VoiceChannel currentVoiceChannel = null;
|
|
|
|
private int trackNumber = 1;
|
|
|
|
/**
|
|
* @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,
|
|
GatewayIntent.GUILD_MEMBERS
|
|
);
|
|
|
|
JDABuilder builder = JDABuilder.createDefault(args[0], intents);
|
|
|
|
// Disable parts of the cache
|
|
builder.disableCache(CacheFlag.MEMBER_OVERRIDES);
|
|
// 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!"));
|
|
|
|
final Main listener = new Main();
|
|
|
|
builder.addEventListeners(listener);
|
|
builder.setAutoReconnect(true);
|
|
|
|
JDA jda = builder.build();
|
|
listener.setJda(jda);
|
|
}
|
|
private final Consumer<Song> nowPlayingConsumer = (Song song) ->
|
|
{
|
|
if (song != null)
|
|
jda.getPresence().setActivity(Activity.of(Activity.ActivityType.LISTENING, song.toString()));
|
|
else
|
|
jda.getPresence().setActivity(null);
|
|
};
|
|
|
|
private final BiConsumer<SongRequest, Exception> downloaderMessageHandler = (SongRequest request, Exception ex) ->
|
|
{
|
|
Song song = request.getSong();
|
|
// TextChannel channel = jda.getTextChannelById(song.getRequestedIn());
|
|
// String bracketNo = "[" + song.getNumber() + "] ";
|
|
if (ex == null)
|
|
if (song.getLocation() != null)
|
|
{
|
|
request.respond("Finished downloading " + song + ", added to queue!");
|
|
log("DOWN", "Downloaded " + song);
|
|
} else
|
|
{
|
|
Format format = song.getBestFormat();
|
|
String formatDetails = "";
|
|
if (format != null)
|
|
{
|
|
final int bitrate = format.getBitrate() / 1000;
|
|
final long size = format.getSize();
|
|
String sizeFmt = (size <= 0 ? "?.??" : String.format("%.2f", size / (1024.0 * 1024.0))) + "MiB";
|
|
String bitFmt = (bitrate <= 0 ? "??" : bitrate) + "k";
|
|
formatDetails = " (" + bitFmt + ", " + sizeFmt + ")";
|
|
}
|
|
request.respond("Now downloading " + song + formatDetails + " ...");
|
|
log("DOWN", "Downloading " + song + "...");
|
|
}
|
|
else
|
|
{
|
|
request.respond("Failed to download " + song + "! Reason: " + ex.getMessage());
|
|
log("DOWN", "Failed to download " + song + "! Reason: " + ex.getMessage());
|
|
}
|
|
|
|
};
|
|
|
|
public Main()
|
|
{
|
|
log("INFO", "Starting up...");
|
|
downloader = new Downloader();
|
|
downloader.setMessageHandler(downloaderMessageHandler);
|
|
searcher = MetaSearcher.loadYAML(new File("searchproviders.yml"));
|
|
|
|
addCommand(new JoinCommand(this));
|
|
addCommand(new LeaveCommand(this));
|
|
playCommand = new PlayCommand(this);
|
|
addCommand(playCommand);
|
|
addCommand(new QueueCommand(this));
|
|
addCommand(new RemoveCommand(this));
|
|
addCommand(new RestartCommand(this));
|
|
addCommand(new SkipCommand(this));
|
|
helpCommand = new HelpCommand(this);
|
|
addCommand(helpCommand);
|
|
|
|
log("INFO", "Started OK!");
|
|
}
|
|
|
|
|
|
private void addCommand(Command command)
|
|
{
|
|
commands.put(command.getKeyword(), command);
|
|
}
|
|
|
|
public void setJda(JDA jda)
|
|
{
|
|
this.jda = jda;
|
|
}
|
|
|
|
@Override
|
|
public void onGuildVoiceLeave(GuildVoiceLeaveEvent event)
|
|
{
|
|
if (this.currentVoiceChannel == null)
|
|
return;
|
|
|
|
final VoiceChannel channelLeft = event.getChannelLeft();
|
|
|
|
if (channelLeft.getMembers().isEmpty())
|
|
if (channelLeft == currentVoiceChannel)
|
|
disconnect();
|
|
}
|
|
|
|
@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 it's not in a music channel
|
|
if (!event.getChannel().getName().contains("music"))
|
|
return;
|
|
|
|
// Ignore message if bot
|
|
if (author.isBot())
|
|
return;
|
|
|
|
log("MESG", "G:" + guild.getName() + " A:" + author.getName() + " C:" + content);
|
|
|
|
try
|
|
{
|
|
URL parseURL = new URL(content.trim());
|
|
playCommand.call(event, List.of(parseURL.toExternalForm()));
|
|
} catch (MalformedURLException ex)
|
|
{
|
|
// not a URL, then
|
|
}
|
|
|
|
try
|
|
{
|
|
String[] split = content.split("\\s+", 2);
|
|
String cmd = split[0].toLowerCase();
|
|
|
|
if (!cmd.startsWith("!"))
|
|
return; // doesn't start with prefix char
|
|
|
|
cmd = cmd.substring(1); // strip prefix char
|
|
|
|
String arg = "";
|
|
if (split.length > 1)
|
|
arg = split[1];
|
|
|
|
if (commands.containsKey(cmd))
|
|
{
|
|
Command command = commands.get(cmd);
|
|
command.call(event, List.of(arg));
|
|
} else
|
|
{
|
|
helpCommand.call(event, List.of(arg));
|
|
}
|
|
} catch (Exception ex)
|
|
{
|
|
event.getChannel().sendMessage("Error in command! " + ex.getMessage()).queue();
|
|
log("UERR", "Command error:" + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
public Song queueDownload(SongRequest request)
|
|
{
|
|
Song song;
|
|
if (request.getUrl() != null)
|
|
{
|
|
song = new Song(request.getUrl());
|
|
} else
|
|
{
|
|
// interpret search result
|
|
throw new UnsupportedOperationException("Not supported yet.");
|
|
}
|
|
if (request.getRequestMessage() != null)
|
|
{
|
|
song.setRequestedBy(request.getRequestMessage().getAuthor().getName());
|
|
song.setRequestedIn(request.getRequestMessage().getChannel().getId());
|
|
}
|
|
song.setNumber(trackNumber);
|
|
trackNumber++;
|
|
request.setSong(song);
|
|
downloader.accept(new Downloader.DownloadTask(request, musicHandler));
|
|
request.respond("Request pending...");
|
|
return song;
|
|
}
|
|
|
|
// public Song queueDownload(final URL url, GuildMessageReceivedEvent event)
|
|
// {
|
|
// Song song = new Song(url);
|
|
// song.setRequestedBy(event.getAuthor().getName());
|
|
// song.setRequestedIn(event.getChannel().getId());
|
|
// song.setNumber(trackNumber);
|
|
// trackNumber++;
|
|
// downloader.accept(new Downloader.DownloadTask(song, musicHandler));
|
|
// return song;
|
|
// }
|
|
//
|
|
// public Song queueDownload(Result res, GuildMessageReceivedEvent event)
|
|
// {
|
|
// Song song = queueDownload(res.getLink(), event);
|
|
// song.setArtist(res.getArtist());
|
|
// song.setTitle(res.getTitle());
|
|
// song.setNumber(trackNumber);
|
|
// return song;
|
|
// }
|
|
public void setStatus(Song nowPlaying)
|
|
{
|
|
jda.getPresence().setActivity(Activity.listening(nowPlaying.toString()));
|
|
}
|
|
|
|
public void clearStatus()
|
|
{
|
|
jda.getPresence().setActivity(null);
|
|
}
|
|
|
|
/**
|
|
* Connect to requested channel and start echo handler
|
|
*
|
|
* @param channel
|
|
* The channel to connect to
|
|
*/
|
|
public 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);
|
|
currentVoiceChannel = channel;
|
|
|
|
musicHandler.setNowPlayingConsumer(nowPlayingConsumer);
|
|
}
|
|
|
|
public void disconnect()
|
|
{
|
|
if (currentVoiceChannel != null)
|
|
{
|
|
Guild guild = currentVoiceChannel.getGuild();
|
|
AudioManager audioManager = guild.getAudioManager();
|
|
audioManager.setSendingHandler(null);
|
|
audioManager.closeAudioConnection();
|
|
musicHandler = null;
|
|
currentVoiceChannel = null;
|
|
}
|
|
}
|
|
|
|
public void log(String type, String message)
|
|
{
|
|
System.out.println(type + " " + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) + "\t" + message);
|
|
}
|
|
|
|
public MusicHandler getMusicHandler()
|
|
{
|
|
return musicHandler;
|
|
}
|
|
|
|
public Downloader getDownloader()
|
|
{
|
|
return downloader;
|
|
}
|
|
|
|
public Searcher getSearcher()
|
|
{
|
|
return searcher;
|
|
}
|
|
|
|
public JDA getJda()
|
|
{
|
|
return jda;
|
|
}
|
|
|
|
public VoiceChannel getCurrentVoiceChannel()
|
|
{
|
|
return currentVoiceChannel;
|
|
}
|
|
|
|
public int getTrackNumber()
|
|
{
|
|
return trackNumber;
|
|
}
|
|
|
|
}
|
|
|