mirror of
https://github.com/JonasunderscoreJones/ZtereoMUSIC.git
synced 2025-10-25 21:49:17 +02:00
Initial commit with base
This commit is contained in:
commit
6d7addc22d
20 changed files with 810 additions and 0 deletions
61
src/main/java/codes/ztereohype/ztereomusic/Bot.java
Normal file
61
src/main/java/codes/ztereohype/ztereomusic/Bot.java
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package codes.ztereohype.ztereomusic;
|
||||
|
||||
import codes.ztereohype.ztereomusic.audio.TrackScheduer;
|
||||
import codes.ztereohype.ztereomusic.command.Command;
|
||||
import codes.ztereohype.ztereomusic.command.commands.Ping;
|
||||
import codes.ztereohype.ztereomusic.command.commands.Playtest;
|
||||
import codes.ztereohype.ztereomusic.database.Config;
|
||||
import codes.ztereohype.ztereomusic.listeners.CommandListener;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.JDABuilder;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Bot {
|
||||
private static @Getter Config config;
|
||||
private static @Getter JDA bot;
|
||||
|
||||
private static @Getter final Map<String, Command> commandMap = new HashMap<>();
|
||||
private static @Getter final Map<String, String> commandAliases = new HashMap<>();
|
||||
|
||||
public static AudioPlayerManager playerManager;
|
||||
public static Map<VoiceChannel, TrackScheduer> trackScheduerMap = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
config = new Config("./config.json5");
|
||||
bot = JDABuilder.createDefault(config.getPropreties().get("token")).build().awaitReady();
|
||||
|
||||
setCommands();
|
||||
setupAudio();
|
||||
setListeners();
|
||||
}
|
||||
|
||||
public static void setCommands() {
|
||||
Ping ping = new Ping();
|
||||
commandMap.put(ping.getMeta().getName(), ping);
|
||||
|
||||
Playtest playtest = new Playtest();
|
||||
commandMap.put(playtest.getMeta().getName(), playtest);
|
||||
|
||||
for (String commandName : commandMap.keySet()) {
|
||||
for (String aliasName : commandMap.get(commandName).getMeta().getAliases()) {
|
||||
commandAliases.put(aliasName, commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setupAudio() {
|
||||
playerManager = new DefaultAudioPlayerManager();
|
||||
AudioSourceManagers.registerRemoteSources(playerManager);
|
||||
}
|
||||
|
||||
public static void setListeners() {
|
||||
bot.addEventListener(new CommandListener());
|
||||
}
|
||||
}
|
||||
14
src/main/java/codes/ztereohype/ztereomusic/api/Search.java
Normal file
14
src/main/java/codes/ztereohype/ztereomusic/api/Search.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package codes.ztereohype.ztereomusic.api;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Search {
|
||||
public String getVideoUrl(String title) throws IOException {
|
||||
return "WIP";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package codes.ztereohype.ztereomusic.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
|
||||
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager;
|
||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class AudioPlayerSendHandler implements AudioSendHandler {
|
||||
private final AudioPlayer audioPlayer;
|
||||
private AudioFrame lastFrame;
|
||||
|
||||
public AudioPlayerSendHandler(AudioPlayer audioPlayer) {
|
||||
this.audioPlayer = audioPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProvide() {
|
||||
lastFrame = audioPlayer.provide();
|
||||
return lastFrame != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer provide20MsAudio() {
|
||||
return ByteBuffer.wrap(lastFrame.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpus() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package codes.ztereohype.ztereomusic.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEvent;
|
||||
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.AudioTrack;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
||||
import net.dv8tion.jda.api.entities.Invite;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TrackScheduer extends AudioEventAdapter {
|
||||
|
||||
private final AudioPlayer player;
|
||||
private final List<AudioTrack> trackQueue = new ArrayList<AudioTrack>();
|
||||
private AudioTrack currentTrack;
|
||||
private final MessageChannel infoChannel;
|
||||
|
||||
public TrackScheduer(AudioPlayer player, MessageChannel infoChannel) {
|
||||
this.player = player;
|
||||
this.infoChannel = infoChannel;
|
||||
}
|
||||
|
||||
public void queue(AudioTrack track) {
|
||||
// change this to add to queue and call onTrackEnd!
|
||||
if (this.currentTrack == null) {
|
||||
System.out.println("Playing song directly as there is no song playing rn");
|
||||
this.currentTrack = track;
|
||||
player.playTrack(track);
|
||||
} else {
|
||||
trackQueue.add(track);
|
||||
System.out.println("Added song to queue");
|
||||
}
|
||||
}
|
||||
|
||||
public AudioPlayer getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerPause(AudioPlayer player) {
|
||||
infoChannel.sendMessage("Pausing...").queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerResume(AudioPlayer player) {
|
||||
infoChannel.sendMessage("Resuming...").queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackStart(AudioPlayer player, AudioTrack track) {
|
||||
infoChannel.sendMessage("Starting track: " + track.getInfo().title).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
|
||||
currentTrack = null;
|
||||
|
||||
if (endReason.mayStartNext) {
|
||||
if (trackQueue.isEmpty()) {
|
||||
System.out.println("track finishd, no more tracks in queue!");
|
||||
infoChannel.sendMessage("no more tracks in queue!").queue();
|
||||
} else {
|
||||
System.out.println("track finishd, trying next track");
|
||||
AudioTrack nextTrack = trackQueue.get(0);
|
||||
trackQueue.remove(0);
|
||||
currentTrack = nextTrack;
|
||||
infoChannel.sendMessage("Playing next track: " + nextTrack.getInfo().title).queue();
|
||||
player.playTrack(currentTrack);
|
||||
}
|
||||
} else {
|
||||
System.out.println("track finishd, cant start next, bye");
|
||||
infoChannel.sendMessage("oopsie woopsie byebye").queue();
|
||||
}
|
||||
|
||||
// endReason == FINISHED: A track finished or died by an exception (mayStartNext = true).
|
||||
// endReason == LOAD_FAILED: Loading of a track failed (mayStartNext = true).
|
||||
// endReason == STOPPED: The player was stopped.
|
||||
// endReason == REPLACED: Another track started playing while this had not finished
|
||||
// endReason == CLEANUP: Player hasn't been queried for a while, if you want you can put a
|
||||
// clone of this back to your queue
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) {
|
||||
// An already playing track threw an exception (track end event will still be received separately)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) {
|
||||
// Audio track has been unable to provide us any audio, might want to just start a new track
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package codes.ztereohype.ztereomusic.command;
|
||||
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
|
||||
// TODO: add categories/groups and perms but in a smart way pls
|
||||
public interface Command {
|
||||
CommandMeta getMeta();
|
||||
void execute(MessageReceivedEvent messageRecievedEvent, String[] args);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package codes.ztereohype.ztereomusic.command;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class CommandMeta {
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final String[] aliases;
|
||||
private final boolean isNsfw;
|
||||
private final boolean isHidden;
|
||||
|
||||
public CommandMeta(String name, String description, String[] aliases, boolean isNsfw, boolean isHidden) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.aliases = aliases;
|
||||
this.isNsfw = isNsfw;
|
||||
this.isHidden = isHidden;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package codes.ztereohype.ztereomusic.command.commands;
|
||||
|
||||
import codes.ztereohype.ztereomusic.command.Command;
|
||||
import codes.ztereohype.ztereomusic.command.CommandMeta;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Ping implements Command {
|
||||
CommandMeta meta = new CommandMeta("ping", "A command to get pinged", new String[]{"pong", "pog"}, false, false);
|
||||
private List<String> list;
|
||||
|
||||
@Override
|
||||
public CommandMeta getMeta() {
|
||||
return this.meta;
|
||||
}
|
||||
|
||||
public void execute(MessageReceivedEvent messageEvent, String[] args) {
|
||||
messageEvent.getMessage().reply("get ping'd lolmao").queue();
|
||||
list.add("owo");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package codes.ztereohype.ztereomusic.command.commands;
|
||||
|
||||
import codes.ztereohype.ztereomusic.Bot;
|
||||
import codes.ztereohype.ztereomusic.audio.AudioPlayerSendHandler;
|
||||
import codes.ztereohype.ztereomusic.audio.TrackScheduer;
|
||||
import codes.ztereohype.ztereomusic.command.Command;
|
||||
import codes.ztereohype.ztereomusic.command.CommandMeta;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.managers.AudioManager;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Playtest implements Command {
|
||||
CommandMeta meta = new CommandMeta("playtest", "A command to test music commands", new String[]{"play"}, false, false);
|
||||
|
||||
@Override
|
||||
public CommandMeta getMeta() {
|
||||
return this.meta;
|
||||
}
|
||||
|
||||
public void execute(MessageReceivedEvent messageEvent, String[] args) {
|
||||
Member author = Objects.requireNonNull(messageEvent.getMember());
|
||||
|
||||
if (author.getVoiceState() == null) {
|
||||
messageEvent.getChannel().sendMessage("I was unable to access your information... strange...").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!author.getVoiceState().inVoiceChannel()) {
|
||||
messageEvent.getMessage().reply("You are not in a voice channel!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
Guild guild = messageEvent.getGuild();
|
||||
VoiceChannel voiceChannel = author.getVoiceState().getChannel();
|
||||
MessageChannel messageChannel = messageEvent.getChannel();
|
||||
AudioManager manager = guild.getAudioManager();
|
||||
AudioPlayerManager playerManager = Bot.playerManager;
|
||||
|
||||
// check if args merged are/have url, if so try to feed it into lava, else try to youtube api the fuck out of it.
|
||||
String mergedArgs = String.join(" ", args);
|
||||
|
||||
//todo find better one
|
||||
Pattern urlPattern = Pattern.compile("^(http|https)://([a-z]+\\.[a-z]+)+/\\S+$", Pattern.CASE_INSENSITIVE);
|
||||
Matcher matchedUrls = urlPattern.matcher(mergedArgs);
|
||||
boolean urlFound = matchedUrls.find();
|
||||
|
||||
String identifier;
|
||||
if (!urlFound) {
|
||||
// youtube api shit
|
||||
messageEvent.getMessage().reply("please send a link").queue();
|
||||
return;
|
||||
} else {
|
||||
// set identifier to the parsed url
|
||||
identifier = mergedArgs;
|
||||
}
|
||||
|
||||
|
||||
/* Generally you would want to create a player per every
|
||||
different target you might want to separately stream audio to.
|
||||
It is totally fine to create them even if they are unlikely to be used,
|
||||
as they do not use any resources on their own without an active track. */
|
||||
AudioPlayer player;
|
||||
TrackScheduer trackScheduler;
|
||||
|
||||
boolean isInVC = manager.isConnected();
|
||||
boolean isInSameVC = isInVC && Objects.equals(manager.getConnectedChannel(), voiceChannel);
|
||||
|
||||
if (isInSameVC && Bot.trackScheduerMap.containsKey(voiceChannel)) {
|
||||
System.out.println("Found a trackScheduler for this VC already! reusing...");
|
||||
|
||||
trackScheduler = Bot.trackScheduerMap.get(voiceChannel);
|
||||
player = trackScheduler.getPlayer();
|
||||
|
||||
player.addListener(trackScheduler);
|
||||
|
||||
} else {
|
||||
// Maybe we don't wanna clear the whole queue when he gets kicked out?
|
||||
// idk
|
||||
if (Bot.trackScheduerMap.containsKey(voiceChannel)) {
|
||||
System.out.println("Found old trackScheduler for this channel. Cleaning it up...");
|
||||
Bot.trackScheduerMap.remove(voiceChannel);
|
||||
}
|
||||
|
||||
System.out.println("Creating a new trackScheduler...");
|
||||
|
||||
player = playerManager.createPlayer();
|
||||
trackScheduler = new TrackScheduer(player, messageChannel);
|
||||
|
||||
player.addListener(trackScheduler);
|
||||
manager.setSendingHandler(new AudioPlayerSendHandler(player));
|
||||
manager.openAudioConnection(voiceChannel);
|
||||
|
||||
Bot.trackScheduerMap.put(voiceChannel, trackScheduler);
|
||||
}
|
||||
|
||||
playerManager.loadItem(identifier, new AudioLoadResultHandler() {
|
||||
@Override
|
||||
public void trackLoaded(AudioTrack track) {
|
||||
trackScheduler.queue(track);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playlistLoaded(AudioPlaylist playlist) {
|
||||
for (AudioTrack track : playlist.getTracks()) {
|
||||
trackScheduler.queue(track);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noMatches() {
|
||||
messageEvent.getMessage().reply("I found no matches for that song!").queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFailed(FriendlyException throwable) {
|
||||
messageEvent.getMessage().reply("everything blew up and died. i'm sorry.").queue();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package codes.ztereohype.ztereomusic.database;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.shadew.json.Json;
|
||||
import net.shadew.json.JsonNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Config {
|
||||
private @Getter final Map<String, String> propreties = new HashMap<>();
|
||||
private final String path;
|
||||
|
||||
public Config(String pathname) throws Exception {
|
||||
Json json5 = Json.json5();
|
||||
JsonNode tree = json5.parse(new File(pathname));
|
||||
this.path = pathname;
|
||||
|
||||
for (String key : tree.keys()) {
|
||||
propreties.put(key, tree.get(key).asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
//package codes.ztereohype.ztereomusic.listeners;
|
||||
//
|
||||
//import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
//
|
||||
//public class AloneInVcListener extends ListenerAdapter {
|
||||
// @Override
|
||||
// public void on
|
||||
//}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package codes.ztereohype.ztereomusic.listeners;
|
||||
|
||||
import codes.ztereohype.ztereomusic.Bot;
|
||||
import codes.ztereohype.ztereomusic.command.Command;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommandListener extends ListenerAdapter {
|
||||
// TODO: load prefix from a config
|
||||
private static final String PREFIX = Bot.getConfig().getPropreties().get("prefix");
|
||||
private static final Map<String, Command> COMMAND_MAP = Bot.getCommandMap();
|
||||
private static final Map<String, String> COMMAND_ALIASES = Bot.getCommandAliases();
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
|
||||
Message message = event.getMessage();
|
||||
String content = message.getContentRaw();
|
||||
|
||||
// ignore messages from bots, dms, and that don't start with the prefix
|
||||
if (!content.startsWith(PREFIX)) return;
|
||||
if (event.getAuthor().isBot()) return;
|
||||
if (!event.isFromGuild()) return;
|
||||
|
||||
// parse the message
|
||||
String[] parsed = content.substring(PREFIX.length()).split(" +");
|
||||
String commandName = parsed[0].toLowerCase();
|
||||
String[] args = Arrays.copyOfRange(parsed, 1, parsed.length);
|
||||
|
||||
// check if the command exists
|
||||
Command command;
|
||||
if (COMMAND_MAP.containsKey(commandName)) {
|
||||
command = COMMAND_MAP.get(commandName);
|
||||
} else if (COMMAND_ALIASES.containsKey(commandName)) {
|
||||
command = COMMAND_MAP.get(COMMAND_ALIASES.get(commandName));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// try to execute the command
|
||||
try {
|
||||
command.execute(event, args);
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
message.getChannel().sendMessage("uh oh something really bad happened and yeah so yeah everything is aborted and cancelled i give up this is too hard kthxbye").queue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
//package codes.ztereohype.ztereomusic.listeners;
|
||||
//
|
||||
//public class onVcDisconnect {
|
||||
//}
|
||||
Loading…
Add table
Add a link
Reference in a new issue