Skip to content

Commit 1a6d8a4

Browse files
committed
Started work on adding music support. Using lavalink now!
Will improve over time!
1 parent bea9476 commit 1a6d8a4

13 files changed

Lines changed: 490 additions & 8 deletions

File tree

build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,18 @@ dependencies {
7373
testImplementation platform('org.junit:junit-bom:5.9.1')
7474
testImplementation 'org.junit.jupiter:junit-jupiter'
7575

76-
installer('org.mangorage:installer:4.0.30')
76+
installer('org.mangorage:installer:4.0.31')
7777
bootstrap("org.mangorage:mangobotbootstrap:1.0.101")
7878
launchtarget("org.mangorage:mangobotlaunchtarget:0.1.23")
7979

80-
plugin('org.mangorage:mangobot:12.0.147')
80+
plugin('org.mangorage:mangobot:12.0.149')
8181

8282
library('org.slf4j:slf4j-simple:2.0.13') // Use a recent version)
8383
library('org.luaj:luaj-jme:3.0.1')
8484

85-
library('dev.arbjerg:lavaplayer:+')
86-
library('dev.lavalink.youtube:common:+')
85+
library("dev.arbjerg:lavalink-client:3.4.0") {
86+
exclude group: "org.jetbrains", module: "annotations"
87+
}
8788

8889
library("com.google.zxing:core:3.5.4")
8990
library("com.google.zxing:javase:3.5.4")

src/main/java/module-info.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
requires java.naming;
33
requires okio;
44
requires kotlin.stdlib;
5-
requires com.fasterxml.jackson.databind;
5+
66
requires org.slf4j.simple;
77

88
requires org.mangorage.bootstrap;
@@ -12,10 +12,7 @@
1212
requires com.google.gson;
1313

1414
requires net.minecraftforge.eventbus;
15-
requires org.jetbrains.annotations;
1615

17-
requires lavaplayer;
18-
requires common;
1916

2017
requires java.desktop;
2118
requires luaj.jme;
@@ -24,12 +21,17 @@
2421
requires com.google.zxing;
2522
requires com.google.zxing.javase;
2623
requires org.slf4j;
24+
requires protocol.jvm;
25+
requires lavalink.client;
26+
requires reactor.core;
2727

2828
opens org.mangorage.mangobotplugin;
2929

3030
exports org.mangorage.mangobotplugin.entrypoint;
3131
exports org.mangorage.mangobotplugin.commands.trick;
3232

33+
exports org.mangorage.mangobotplugin.commands.music;
34+
3335
opens org.mangorage.mangobotplugin.pagedlist to net.dv8tion.jda;
3436
opens org.mangorage.mangobotplugin.commands.trick to com.google.gson, org.hibernate.orm.core;
3537

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.mangorage.mangobotplugin.commands.music;
2+
3+
4+
import dev.arbjerg.lavalink.client.AbstractAudioLoadResultHandler;
5+
import dev.arbjerg.lavalink.client.player.*;
6+
7+
import java.util.List;
8+
9+
public final class AudioLoader extends AbstractAudioLoadResultHandler {
10+
private final GuildMusicManager mngr;
11+
12+
public AudioLoader(GuildMusicManager mngr) {
13+
this.mngr = mngr;
14+
}
15+
16+
@Override
17+
public void ontrackLoaded(TrackLoaded result) {
18+
final Track track = result.getTrack();
19+
20+
var userData = new MyUserData(0l);
21+
22+
track.setUserData(userData);
23+
24+
this.mngr.scheduler.enqueue(track);
25+
26+
final var trackTitle = track.getInfo().getTitle();
27+
28+
// event.getHook().sendMessage("Added to queue: " + trackTitle + "\nRequested by: <@" + userData.requester() + '>').queue();
29+
}
30+
31+
@Override
32+
public void onPlaylistLoaded(PlaylistLoaded result) {
33+
final int trackCount = result.getTracks().size();
34+
// event.getHook()
35+
// .sendMessage("Added " + trackCount + " tracks to the queue from " + result.getInfo().getName() + "!")
36+
// .queue();
37+
38+
this.mngr.scheduler.enqueuePlaylist(result.getTracks());
39+
}
40+
41+
@Override
42+
public void onSearchResultLoaded(SearchResult result) {
43+
final List<Track> tracks = result.getTracks();
44+
45+
if (tracks.isEmpty()) {
46+
//event.getHook().sendMessage("No tracks found!").queue();
47+
return;
48+
}
49+
50+
final Track firstTrack = tracks.get(0);
51+
52+
//event.getHook().sendMessage("Adding to queue: " + firstTrack.getInfo().getTitle()).queue();
53+
54+
this.mngr.scheduler.enqueue(firstTrack);
55+
}
56+
57+
@Override
58+
public void noMatches() {
59+
//event.getHook().sendMessage("No matches found for your input!").queue();
60+
}
61+
62+
@Override
63+
public void loadFailed(LoadFailed result) {
64+
//.getHook().sendMessage("Failed to load track! " + result.getException().getMessage()).queue();
65+
}
66+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.mangorage.mangobotplugin.commands.music;
2+
3+
4+
import dev.arbjerg.lavalink.client.LavalinkClient;
5+
import dev.arbjerg.lavalink.client.Link;
6+
import dev.arbjerg.lavalink.client.player.LavalinkPlayer;
7+
8+
import java.util.Optional;
9+
10+
public class GuildMusicManager {
11+
public final TrackScheduler scheduler = new TrackScheduler(this);
12+
private final long guildId;
13+
private final LavalinkClient lavalink;
14+
15+
public GuildMusicManager(long guildId, LavalinkClient lavalink) {
16+
this.lavalink = lavalink;
17+
this.guildId = guildId;
18+
}
19+
20+
public void stop() {
21+
this.scheduler.queue.clear();
22+
23+
this.getPlayer().ifPresent(
24+
(player) -> player.setPaused(false)
25+
.setTrack(null)
26+
.subscribe()
27+
);
28+
}
29+
30+
public Optional<Link> getLink() {
31+
return Optional.ofNullable(
32+
this.lavalink.getLinkIfCached(this.guildId)
33+
);
34+
}
35+
36+
public Optional<LavalinkPlayer> getPlayer() {
37+
return this.getLink().map(Link::getCachedPlayer);
38+
}
39+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.mangorage.mangobotplugin.commands.music;
2+
3+
public interface IMusicManager {
4+
GuildMusicManager getOrCreate(long guildId);
5+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.mangorage.mangobotplugin.commands.music;
2+
3+
4+
public record MyUserData(long requester) {}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.mangorage.mangobotplugin.commands.music;
2+
3+
import dev.arbjerg.lavalink.client.player.Track;
4+
import dev.arbjerg.lavalink.protocol.v4.Message;
5+
6+
import java.util.LinkedList;
7+
import java.util.List;
8+
import java.util.Queue;
9+
10+
public final class TrackScheduler {
11+
private final GuildMusicManager guildMusicManager;
12+
public final Queue<Track> queue = new LinkedList<>();
13+
14+
public TrackScheduler(GuildMusicManager guildMusicManager) {
15+
this.guildMusicManager = guildMusicManager;
16+
}
17+
18+
public void enqueue(Track track) {
19+
this.guildMusicManager.getPlayer().ifPresentOrElse(
20+
(player) -> {
21+
if (player.getTrack() == null) {
22+
this.startTrack(track);
23+
} else {
24+
this.queue.offer(track);
25+
}
26+
},
27+
() -> {
28+
this.startTrack(track);
29+
}
30+
);
31+
}
32+
33+
public void enqueuePlaylist(List<Track> tracks) {
34+
this.queue.addAll(tracks);
35+
36+
this.guildMusicManager.getPlayer().ifPresentOrElse(
37+
(player) -> {
38+
if (player.getTrack() == null) {
39+
this.startTrack(this.queue.poll());
40+
}
41+
},
42+
() -> {
43+
this.startTrack(this.queue.poll());
44+
}
45+
);
46+
}
47+
48+
public void onTrackStart(Track track) {
49+
// Your homework: Send a message to the channel somehow, have fun!
50+
System.out.println("Track started: " + track.getInfo().getTitle());
51+
}
52+
53+
public void onTrackEnd(Track lastTrack, Message.EmittedEvent.TrackEndEvent.AudioTrackEndReason endReason) {
54+
if (endReason.getMayStartNext()) {
55+
final var nextTrack = this.queue.poll();
56+
57+
if (nextTrack != null) {
58+
this.startTrack(nextTrack);
59+
}
60+
}
61+
}
62+
63+
private void startTrack(Track track) {
64+
this.guildMusicManager.getLink().ifPresent(
65+
(link) -> link.createOrUpdatePlayer()
66+
.setTrack(track)
67+
.setVolume(35)
68+
.subscribe()
69+
);
70+
}
71+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.mangorage.mangobotplugin.commands.music.impl;
2+
3+
import net.dv8tion.jda.api.JDA;
4+
import net.dv8tion.jda.api.entities.GuildVoiceState;
5+
import net.dv8tion.jda.api.entities.Member;
6+
import net.dv8tion.jda.api.entities.Message;
7+
import org.mangorage.mangobotcore.api.command.v1.CommandContext;
8+
import org.mangorage.mangobotcore.api.jda.command.v2.AbstractJDACommand;
9+
import org.mangorage.mangobotcore.api.jda.command.v2.JDACommandResult;
10+
import org.mangorage.mangobotcore.api.jda.command.v2.JDACommandType;
11+
import org.mangorage.mangobotplugin.commands.music.IMusicManager;
12+
13+
public final class JoinCommand extends AbstractJDACommand {
14+
15+
private final IMusicManager musicManager;
16+
17+
public JoinCommand(IMusicManager musicManager) {
18+
super("join", "Join the Voicechat!");
19+
this.musicManager = musicManager;
20+
}
21+
22+
@Override
23+
public JDACommandType getCommandType() {
24+
return JDACommandType.GUILD;
25+
}
26+
27+
@Override
28+
public JDACommandResult run(CommandContext<Message> commandContext) throws Throwable {
29+
final var context = commandContext.getContextObject();
30+
final var member = context.getMember();
31+
32+
joinHelper(member, commandContext.getContextObject().getJDA());
33+
34+
return JDACommandResult.PASS;
35+
}
36+
37+
// Makes sure that the bot is in a voice channel!
38+
private void joinHelper(Member member, JDA jda) {
39+
final GuildVoiceState memberVoiceState = member.getVoiceState();
40+
41+
if (memberVoiceState.inAudioChannel()) {
42+
jda.getDirectAudioController().connect(memberVoiceState.getChannel());
43+
}
44+
45+
musicManager.getOrCreate(member.getGuild().getIdLong());
46+
}
47+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.mangorage.mangobotplugin.commands.music.impl;
2+
3+
import dev.arbjerg.lavalink.client.LavalinkClient;
4+
import net.dv8tion.jda.api.JDA;
5+
import net.dv8tion.jda.api.entities.GuildVoiceState;
6+
import net.dv8tion.jda.api.entities.Member;
7+
import net.dv8tion.jda.api.entities.Message;
8+
import org.mangorage.mangobotcore.api.command.v1.CommandContext;
9+
import org.mangorage.mangobotcore.api.jda.command.v2.AbstractJDACommand;
10+
import org.mangorage.mangobotcore.api.jda.command.v2.JDACommandResult;
11+
import org.mangorage.mangobotcore.api.jda.command.v2.JDACommandType;
12+
import org.mangorage.mangobotplugin.commands.music.AudioLoader;
13+
import org.mangorage.mangobotplugin.commands.music.GuildMusicManager;
14+
import org.mangorage.mangobotplugin.commands.music.IMusicManager;
15+
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
19+
public final class MusicCommand extends AbstractJDACommand implements IMusicManager {
20+
private final Map<Long, GuildMusicManager> musicManagerMap = new HashMap<>();
21+
private final LavalinkClient client;
22+
23+
public MusicCommand(String name, LavalinkClient client) {
24+
super(name, "Music Commands!");
25+
this.client = client;
26+
addSubCommand(new JoinCommand(this));
27+
addSubCommand(new PlayCommand(this));
28+
addSubCommand(new PauseCommand(this));
29+
addSubCommand(new StopCommand(this));
30+
}
31+
32+
@Override
33+
public JDACommandType getCommandType() {
34+
return JDACommandType.GUILD;
35+
}
36+
37+
@Override
38+
public JDACommandResult run(CommandContext<Message> commandContext) throws Throwable {
39+
return JDACommandResult.PASS;
40+
}
41+
42+
43+
@Override
44+
public GuildMusicManager getOrCreate(long guildId) {
45+
return musicManagerMap.computeIfAbsent(
46+
guildId,
47+
id -> new GuildMusicManager(guildId, client)
48+
);
49+
}
50+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.mangorage.mangobotplugin.commands.music.impl;
2+
3+
import dev.arbjerg.lavalink.client.LavalinkClient;
4+
import dev.arbjerg.lavalink.client.player.LavalinkPlayer;
5+
import net.dv8tion.jda.api.entities.Message;
6+
import org.mangorage.mangobotcore.api.command.v1.CommandContext;
7+
import org.mangorage.mangobotcore.api.jda.command.v2.AbstractJDACommand;
8+
import org.mangorage.mangobotcore.api.jda.command.v2.JDACommandResult;
9+
import org.mangorage.mangobotcore.api.jda.command.v2.JDACommandType;
10+
import org.mangorage.mangobotplugin.commands.music.IMusicManager;
11+
import reactor.core.CoreSubscriber;
12+
13+
public final class PauseCommand extends AbstractJDACommand {
14+
15+
private final IMusicManager manager;
16+
17+
public PauseCommand(IMusicManager manager) {
18+
super("pause", "Pause the music!");
19+
this.manager = manager;
20+
}
21+
22+
@Override
23+
public JDACommandType getCommandType() {
24+
return JDACommandType.GUILD;
25+
}
26+
27+
@Override
28+
public JDACommandResult run(CommandContext<Message> commandContext) throws Throwable {
29+
final var guild = commandContext.getContextObject().getGuild();
30+
31+
final var guildManager = manager.getOrCreate(guild.getIdLong());
32+
33+
guildManager.getPlayer()
34+
.ifPresent(player -> {
35+
player.setPaused(true).subscribe();
36+
});
37+
38+
return JDACommandResult.PASS;
39+
}
40+
}

0 commit comments

Comments
 (0)