✨ Ajout de la gestion audio avec les commandes play et stop, et implémentation des gestionnaires de musique
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
This commit is contained in:
parent
0fedd154ea
commit
f858684132
@ -1,21 +1,26 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
plugins {
|
||||
application
|
||||
id("java")
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
}
|
||||
|
||||
group = "fr.melaine.gerard.kiss.shot.acerola"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
application {
|
||||
mainClass = "org.camelia.studio.kiss.shot.acerola.KissShotAcerola"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { setUrl("https://jitpack.io") }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("io.github.cdimascio:dotenv-kotlin:6.4.2")
|
||||
implementation("net.dv8tion:JDA:5.2.1")
|
||||
implementation("ch.qos.logback:logback-classic:1.5.12")
|
||||
implementation ("dev.arbjerg:lavaplayer:2.2.2")
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame;
|
||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class AudioPlayerSendHandler implements AudioSendHandler {
|
||||
private final AudioPlayer audioPlayer;
|
||||
private final ByteBuffer buffer;
|
||||
private final MutableAudioFrame frame;
|
||||
|
||||
public AudioPlayerSendHandler(AudioPlayer audioPlayer) {
|
||||
this.audioPlayer = audioPlayer;
|
||||
this.buffer = ByteBuffer.allocate(1024);
|
||||
this.frame = new MutableAudioFrame();
|
||||
this.frame.setBuffer(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProvide() {
|
||||
return audioPlayer.provide(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer provide20MsAudio() {
|
||||
((Buffer) buffer).flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpus() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
|
||||
public class GuildMusicManager {
|
||||
public final AudioPlayer audioPlayer;
|
||||
public final TrackScheduler scheduler;
|
||||
private final AudioPlayerSendHandler sendHandler;
|
||||
|
||||
public GuildMusicManager(AudioPlayerManager manager) {
|
||||
this.audioPlayer = manager.createPlayer();
|
||||
this.scheduler = new TrackScheduler(this.audioPlayer);
|
||||
this.audioPlayer.addListener(this.scheduler);
|
||||
this.sendHandler = new AudioPlayerSendHandler(this.audioPlayer);
|
||||
}
|
||||
|
||||
public AudioPlayerSendHandler getSendHandler() {
|
||||
return sendHandler;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
|
||||
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.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerManager {
|
||||
private static PlayerManager INSTANCE;
|
||||
private final Map<Long, GuildMusicManager> musicManagers;
|
||||
private final AudioPlayerManager audioPlayerManager;
|
||||
|
||||
public PlayerManager() {
|
||||
this.musicManagers = new HashMap<>();
|
||||
this.audioPlayerManager = new DefaultAudioPlayerManager();
|
||||
AudioSourceManagers.registerRemoteSources(audioPlayerManager);
|
||||
}
|
||||
|
||||
public static PlayerManager getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new PlayerManager();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public GuildMusicManager getMusicManager(Guild guild) {
|
||||
return musicManagers.computeIfAbsent(guild.getIdLong(), (guildId) -> {
|
||||
final GuildMusicManager guildMusicManager = new GuildMusicManager(audioPlayerManager);
|
||||
guild.getAudioManager().setSendingHandler(guildMusicManager.getSendHandler());
|
||||
return guildMusicManager;
|
||||
});
|
||||
}
|
||||
|
||||
public void loadAndPlay(TextChannel channel, String url) {
|
||||
final GuildMusicManager musicManager = getMusicManager(channel.getGuild());
|
||||
|
||||
audioPlayerManager.loadItemOrdered(musicManager, url, new AudioLoadResultHandler() {
|
||||
@Override
|
||||
public void trackLoaded(AudioTrack track) {
|
||||
musicManager.scheduler.queue(track);
|
||||
channel.sendMessage("Ajout à la file d'attente: `" + track.getInfo().title + "`").queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playlistLoaded(AudioPlaylist playlist) {
|
||||
final AudioTrack track = playlist.getTracks().get(0);
|
||||
musicManager.scheduler.queue(track);
|
||||
channel.sendMessage("Ajout à la file d'attente: `" + track.getInfo().title + "`").queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noMatches() {
|
||||
channel.sendMessage("Aucun résultat trouvé pour: " + url).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFailed(FriendlyException e) {
|
||||
channel.sendMessage("Erreur lors du chargement: " + e.getMessage()).queue();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
||||
|
||||
public class TrackScheduler extends AudioEventAdapter {
|
||||
private final AudioPlayer player;
|
||||
|
||||
public TrackScheduler(AudioPlayer player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void queue(AudioTrack track) {
|
||||
player.startTrack(track, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
|
||||
if (endReason.mayStartNext) {
|
||||
// Ici vous pouvez gérer la lecture de la prochaine piste si vous implémentez une file d'attente
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.commands.utils;
|
||||
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.GuildVoiceState;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
import net.dv8tion.jda.api.managers.AudioManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.camelia.studio.kiss.shot.acerola.audio.PlayerManager;
|
||||
import org.camelia.studio.kiss.shot.acerola.interfaces.ISlashCommand;
|
||||
|
||||
public class PlayAudioCommand implements ISlashCommand {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "playaudio";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Permet de lancer une musique en .mp3 dans un salon vocal";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OptionData> getOptions() {
|
||||
return List.of(
|
||||
new OptionData(OptionType.STRING, "url", "URL de la musique à jouer", true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(SlashCommandInteractionEvent event) {
|
||||
event.deferReply().queue();
|
||||
String url = event.getOption("url").getAsString();
|
||||
Member member = event.getMember();
|
||||
GuildVoiceState voiceState = member.getVoiceState();
|
||||
|
||||
if (!member.getVoiceState().inAudioChannel()) {
|
||||
event.getHook().editOriginal("Vous devez être connecté à un salon vocal pour utiliser cette commande !")
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
VoiceChannel channel = voiceState.getChannel().asVoiceChannel();
|
||||
|
||||
AudioManager audioManager = event.getGuild().getAudioManager();
|
||||
audioManager.openAudioConnection(channel);
|
||||
PlayerManager.getInstance().getMusicManager(event.getGuild()).audioPlayer.setVolume(25);
|
||||
PlayerManager.getInstance().loadAndPlay(event.getChannel().asTextChannel(), url);
|
||||
event.getHook().editOriginal("Chargement du fichier audio en cours...").queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.commands.utils;
|
||||
|
||||
import org.camelia.studio.kiss.shot.acerola.audio.GuildMusicManager;
|
||||
import org.camelia.studio.kiss.shot.acerola.audio.PlayerManager;
|
||||
import org.camelia.studio.kiss.shot.acerola.interfaces.ISlashCommand;
|
||||
|
||||
import net.dv8tion.jda.api.entities.GuildVoiceState;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.managers.AudioManager;
|
||||
|
||||
public class StopCommand implements ISlashCommand{
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "stopaudio"
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Permet de stopper la musique en cours";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(SlashCommandInteractionEvent event) {
|
||||
// Vérifier si l'utilisateur est dans un canal vocal
|
||||
GuildVoiceState voiceState = event.getMember().getVoiceState();
|
||||
if (!voiceState.inAudioChannel()) {
|
||||
event.reply("Vous devez être dans un canal vocal pour utiliser cette commande !").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier si le bot est dans le même canal vocal
|
||||
AudioManager audioManager = event.getGuild().getAudioManager();
|
||||
if (!audioManager.isConnected()) {
|
||||
event.reply("Je ne suis pas connecté à un canal vocal !").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (voiceState.getChannel() != audioManager.getConnectedChannel()) {
|
||||
event.reply("Vous devez être dans le même canal vocal que moi !").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Arrêter la musique
|
||||
GuildMusicManager musicManager = PlayerManager.getInstance().getMusicManager(event.getGuild());
|
||||
musicManager.audioPlayer.stopTrack();
|
||||
|
||||
// Déconnecter le bot
|
||||
audioManager.closeAudioConnection();
|
||||
|
||||
event.reply("Musique arrêtée et déconnexion du canal vocal.").queue();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.camelia.studio.kiss.shot.acerola.listeners;
|
||||
|
||||
import org.camelia.studio.kiss.shot.acerola.audio.PlayerManager;
|
||||
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.managers.AudioManager;
|
||||
|
||||
public class VoiceLeaveListener extends ListenerAdapter {
|
||||
@Override
|
||||
public void onGuildVoiceUpdate(GuildVoiceUpdateEvent event) {
|
||||
Guild guild = event.getGuild();
|
||||
AudioManager audioManager = guild.getAudioManager();
|
||||
|
||||
// Vérifie si le bot est connecté à un canal vocal
|
||||
if (!audioManager.isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VoiceChannel botChannel = audioManager.getConnectedChannel().asVoiceChannel();
|
||||
|
||||
// Compte le nombre de membres dans le canal (excluant les bots)
|
||||
long realMembersCount = botChannel.getMembers().stream()
|
||||
.filter(member -> !member.getUser().isBot())
|
||||
.count();
|
||||
|
||||
// Si plus personne dans le salon
|
||||
if (realMembersCount == 0) {
|
||||
// Arrête la musique
|
||||
PlayerManager.getInstance().getMusicManager(guild).audioPlayer.stopTrack();
|
||||
|
||||
// Déconnecte le bot
|
||||
audioManager.closeAudioConnection();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import org.camelia.studio.kiss.shot.acerola.listeners.GuildMemberJoinListener;
|
||||
import org.camelia.studio.kiss.shot.acerola.listeners.SlashCommandListener;
|
||||
import org.camelia.studio.kiss.shot.acerola.listeners.VoiceLeaveListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -13,11 +14,13 @@ import java.util.List;
|
||||
public class ListenerManager {
|
||||
private final List<ListenerAdapter> listener;
|
||||
private final Logger logger = LoggerFactory.getLogger(ListenerManager.class.getName());
|
||||
|
||||
public ListenerManager() {
|
||||
listener = new ArrayList<>();
|
||||
|
||||
addListener(new SlashCommandListener());
|
||||
addListener(new GuildMemberJoinListener());
|
||||
addListener(new VoiceLeaveListener());
|
||||
}
|
||||
|
||||
public void registerListeners(JDA jda) {
|
||||
|
Loading…
Reference in New Issue
Block a user