Premier commit - Introudction au système git
This commit is contained in:
commit
1320fec143
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
dependencies/
|
||||
bin/
|
||||
.gradle
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
419
src/com/bernard/djulia/DJuLIA.java
Normal file
419
src/com/bernard/djulia/DJuLIA.java
Normal file
@ -0,0 +1,419 @@
|
||||
package com.bernard.djulia;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.bernard.juliabot.api.Command;
|
||||
import com.bernard.juliabot.api.Discord;
|
||||
import com.bernard.juliabot.api.DiscordCCommande;
|
||||
import com.bernard.juliabot.api.JuLIAddon;
|
||||
import com.bernard.juliabot.api.Trukilie;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventListener;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.PlayerPauseEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.PlayerResumeEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.TrackEndEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.TrackExceptionEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.TrackStartEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.TrackStuckEvent;
|
||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
|
||||
|
||||
import net.dv8tion.jda.core.EmbedBuilder;
|
||||
import net.dv8tion.jda.core.audio.AudioSendHandler;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.core.entities.Member;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.core.entities.MessageChannel;
|
||||
import net.dv8tion.jda.core.entities.MessageEmbed.Field;
|
||||
import net.dv8tion.jda.core.entities.PrivateChannel;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.core.events.message.react.GenericMessageReactionEvent;
|
||||
import net.dv8tion.jda.core.managers.AudioManager;
|
||||
|
||||
|
||||
@JuLIAddon(devs = "Mysaa", name = "djulia", version = "beta")
|
||||
public class DJuLIA {
|
||||
|
||||
public static final String MUSIC = "musique";
|
||||
|
||||
Map<Long,JuliaAudioSendHandler> guilds = new HashMap<>();
|
||||
|
||||
Map<Long,Long> localGuilds = new HashMap<>();
|
||||
|
||||
AudioPlayerManager audioManager;
|
||||
|
||||
public DJuLIA() {
|
||||
audioManager = new DefaultAudioPlayerManager();
|
||||
AudioSourceManagers.registerRemoteSources(audioManager);
|
||||
}
|
||||
|
||||
@Command(admin = false, description = "Permet de jouer un ou plusieurs morceaux", name = "play")
|
||||
public void playCommand(DiscordCCommande commande) {
|
||||
Guild g = getGuild(commande);
|
||||
if(g==null) {
|
||||
bMsg(commande.getChannel(), "Impossible de deviner dans quel serveur vous voulez éxecuter cette commande (y a la commande soundGuild)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Command(admin = false, description = "Définis le serveur utilisé pour les commandes de son de cet utilisateur", name = "soundGuild", synopsis = "!!soundGuild [null|long guildid|string guildName]")
|
||||
public void soundGuild(DiscordCCommande commande) {
|
||||
String arg = commande.getStringCommand().substring(commande.getStringCommand().split(" ")[0].length());
|
||||
if(!arg.isEmpty())arg = arg.substring(1);// On enlève l'espace en trop
|
||||
if(arg.equalsIgnoreCase("null") || (arg.isEmpty() && !(commande.getChannel() instanceof TextChannel))) {
|
||||
localGuilds.remove(commande.getUser().getIdLong());
|
||||
bMsg(commande.getChannel(), "Très bien, aucun serveur n'est séléctionné");
|
||||
return;
|
||||
}
|
||||
if(arg.isEmpty()) {
|
||||
bMsg(commande.getChannel(), "Vous devez indiquer un serveur ou lancer cette commande dans un serveur");
|
||||
return;
|
||||
}
|
||||
Long l = null;
|
||||
Guild g = null;
|
||||
try {
|
||||
l = Long.parseLong(arg);
|
||||
g = Trukilie.jda().getGuildById(l);
|
||||
}catch(NumberFormatException e) {
|
||||
|
||||
}
|
||||
if(g!=null) {
|
||||
localGuilds.put(commande.getUser().getIdLong(), g.getIdLong());
|
||||
bMsg(commande.getChannel(), "Très bien, le serveur `"+g.getName()+"` a été séléctionné *(id "+g.getIdLong()+")*");
|
||||
return;
|
||||
}
|
||||
List<Guild> guilds = Trukilie.jda().getGuildsByName(arg, true);
|
||||
if(guilds.isEmpty()) {
|
||||
bMsg(commande.getChannel(), "Excuse-moi, `"+arg+"` ne correspond à aucun nom ou id de serveur (que je connaisse, du moins :wink:)");
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
if(guilds.size() > 1) {
|
||||
index = selector(commande.getChannel(),commande.getUser(),"Quel serveur électionnez-vous ?",guilds.stream().map(gu->"`"+ gu.getName()+"` *(id:"+gu.getId()+")*").collect(Collectors.toList()));
|
||||
if(index==-1) {
|
||||
bMsg(commande.getChannel(), "Tu n'as pas séléctionné de serveur, donc je ne t'en assigne pas");
|
||||
return;
|
||||
}
|
||||
}
|
||||
localGuilds.put(commande.getUser().getIdLong(), guilds.get(index).getIdLong());
|
||||
}
|
||||
|
||||
public Guild getGuild(DiscordCCommande commande) {
|
||||
|
||||
if(commande.getChannel() instanceof TextChannel)
|
||||
return ((TextChannel)commande.getChannel()).getGuild();
|
||||
|
||||
if(localGuilds.containsKey(commande.getUser().getIdLong()))
|
||||
return Trukilie.jda().getGuildById(localGuilds.get(commande.getUser().getIdLong()));
|
||||
|
||||
List<Guild> mutualGuilds = commande.getUser().getMutualGuilds();
|
||||
if(mutualGuilds.size() == 1)
|
||||
return mutualGuilds.get(0);
|
||||
|
||||
Set<Guild> vocalGuilds = mutualGuilds.stream()
|
||||
.filter(gu->gu.getMember(commande.getUser()).getVoiceState().inVoiceChannel())
|
||||
.collect(Collectors.toSet());
|
||||
if(vocalGuilds.size() == 1)
|
||||
return vocalGuilds.iterator().next();
|
||||
|
||||
Set<Guild> vocalGuildsWithJulia = vocalGuilds.stream()
|
||||
.filter(g->guilds.containsKey(g.getIdLong()))
|
||||
.filter(g->guilds.get(g.getIdLong()).currentChannel.getId().equals(g.getMember(commande.getUser()).getVoiceState().getAudioChannel().getId()))
|
||||
.collect(Collectors.toSet());
|
||||
if(vocalGuildsWithJulia.size() == 1)
|
||||
return vocalGuildsWithJulia.iterator().next();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Map<Long,Object> waitingEmojis = new HashMap<>();
|
||||
Map<Long,Lock> everyEventLocks = new HashMap<>();
|
||||
|
||||
public int selector(MessageChannel chan,String title,List<String> choices) {
|
||||
List<User> authorized = new ArrayList<>();
|
||||
if(chan instanceof TextChannel)
|
||||
authorized = ((TextChannel)chan).getMembers().stream().map(Member::getUser).collect(Collectors.toList());
|
||||
else
|
||||
authorized = List.of(((PrivateChannel)chan).getUser());
|
||||
return selector(chan,authorized,title,choices);
|
||||
}
|
||||
public int selector(MessageChannel chan,User authorized,String title,List<String> choices) {
|
||||
return selector(chan,List.of(authorized),title,choices);
|
||||
}
|
||||
public int selector(MessageChannel chan,List<User> authorized,String title,List<String> choices) {
|
||||
String[] enames;
|
||||
if(choices.size() > 20) {
|
||||
throw new IllegalArgumentException("Je ne gère pas (encore) les trop nombreux choix >20");
|
||||
}
|
||||
if(choices.size() <= 10)
|
||||
enames = new String[] {"one","two","three","four","five","six","seven","eight","nine","ten"};
|
||||
else
|
||||
enames = new String[] {"regional_indicator_a","regional_indicator_b","regional_indicator_c","regional_indicator_d","regional_indicator_e","regional_indicator_f","regional_indicator_g","regional_indicator_h","regional_indicator_i","regional_indicator_j","regional_indicator_k","regional_indicator_l","regional_indicator_m","regional_indicator_n","regional_indicator_o","regional_indicator_p","regional_indicator_q","regional_indicator_r","regional_indicator_s","regional_indicator_t","regional_indicator_u","regional_indicator_v","regional_indicator_w","regional_indicator_x","regional_indicator_y","regional_indicator_z"};
|
||||
|
||||
EmbedBuilder builder = new EmbedBuilder();
|
||||
builder.setTitle(title);
|
||||
for (int i = 0; i < choices.size(); i++)
|
||||
builder.addField(":"+enames[i]+":", choices.get(i), false);
|
||||
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.HOUR, 1);
|
||||
String expiration = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()).format(c.getTime());
|
||||
|
||||
builder.setFooter("Éxpire le "+expiration, null);
|
||||
|
||||
Message m = chan.sendMessage(builder.build()).complete();
|
||||
|
||||
for (int i = 0; i < choices.size(); i++)
|
||||
m.addReaction(enames[i]).queue();
|
||||
|
||||
|
||||
Object o = new Object();
|
||||
waitingEmojis.put(m.getIdLong(), o);
|
||||
ReentrantLock lock = new ReentrantLock();
|
||||
everyEventLocks.put(m.getIdLong(), lock);
|
||||
int index = -1;
|
||||
do {
|
||||
lock.unlock();
|
||||
try {
|
||||
o.wait(c.getTimeInMillis() - Calendar.getInstance().getTimeInMillis());
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
//Check for emoji
|
||||
Message mm = chan.getMessageById(m.getIdLong()).complete();
|
||||
index = mm.getReactions().stream()
|
||||
.filter(mr->!inter(mr.getUsers().complete(),authorized).isEmpty())
|
||||
.mapToInt(mr->Arrays.binarySearch(enames,0,choices.size(),mr.getReactionEmote().getName()))
|
||||
.filter(i->i>=0)
|
||||
.findAny()
|
||||
.orElse(-1);
|
||||
}while(index==-1 || Calendar.getInstance().after(c));
|
||||
|
||||
waitingEmojis.remove(m.getIdLong());
|
||||
everyEventLocks.remove(m.getIdLong());
|
||||
|
||||
lock.unlock();
|
||||
o.notifyAll();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@Discord(description = "Regarde les réactions pour le sélecteur")
|
||||
public void reaction(GenericMessageReactionEvent event) {
|
||||
long messageID = event.getMessageIdLong();
|
||||
if(!waitingEmojis.containsKey(messageID))
|
||||
return;
|
||||
Optional.ofNullable(everyEventLocks.get(messageID)).ifPresent(Lock::lock);
|
||||
if(!waitingEmojis.containsKey(messageID))
|
||||
return;
|
||||
everyEventLocks.get(messageID).unlock();
|
||||
waitingEmojis.get(messageID).notifyAll();
|
||||
}
|
||||
|
||||
public static final <E> Set<E> inter(Collection<E> c1,Collection<E> c2) {
|
||||
return c1.stream()
|
||||
.distinct()
|
||||
.filter(c2::contains)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Guild targetGuild(DiscordCCommande commande) {
|
||||
Guild g = getGuild(commande);
|
||||
if(g==null) {
|
||||
bMsg(commande.getChannel(),"Je ne sais pas pour quel serveur vous voulez lancer ces commandes. Veuillez utiliser `!!soundGuild` pour séléctionner le serveur");
|
||||
}
|
||||
return g;
|
||||
}
|
||||
public static final void bMsg(MessageChannel chan,String text) {
|
||||
EmbedBuilder builder = new EmbedBuilder();
|
||||
builder.addField(new Field("text", text, true));
|
||||
chan.sendMessage(builder.build()).queue();
|
||||
}
|
||||
|
||||
public class JuliaAudioSendHandler implements AudioSendHandler{
|
||||
VoiceChannel currentChannel;
|
||||
Guild currentGuild;
|
||||
AudioManager manager;
|
||||
Map<String,JuliaAudioChannel> chans = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
public JuliaAudioSendHandler(Guild g) {
|
||||
currentChannel = g.getMember(Trukilie.jda().getSelfUser()).getVoiceState().getChannel();
|
||||
manager = g.getAudioManager();
|
||||
manager.setSendingHandler(this);
|
||||
}
|
||||
|
||||
public JuliaAudioChannel getChan(String chanName) {
|
||||
if(chans.containsKey(chanName))
|
||||
return chans.get(chanName);
|
||||
JuliaAudioChannel chan = new JuliaAudioChannel();
|
||||
chans.put(chanName, chan);
|
||||
return chan;
|
||||
}
|
||||
|
||||
public void goTo(VoiceChannel chan) {
|
||||
currentChannel = chan;
|
||||
manager.openAudioConnection(chan);
|
||||
}
|
||||
|
||||
public class JuliaAudioChannel implements AudioEventListener{
|
||||
AudioPlayer player;
|
||||
AudioFrame frame;
|
||||
List<JuliaAudioTrack> playlist;
|
||||
int playlistIndex = 0;
|
||||
boolean looping = false;
|
||||
|
||||
public JuliaAudioChannel() {
|
||||
player = audioManager.createPlayer();
|
||||
player.addListener(this);
|
||||
playlist = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void play(JuliaAudioTrack track) {
|
||||
playlist.add(playlistIndex+1, track);
|
||||
playlistIndex++;
|
||||
player.playTrack(playlist.get(playlistIndex).track);
|
||||
player.setPaused(false);
|
||||
}
|
||||
|
||||
public void queue(JuliaAudioTrack track) {
|
||||
playlist.add(track);
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
player.setPaused(!player.isPaused());
|
||||
}
|
||||
|
||||
public AudioTrack currentTrack() {
|
||||
return player.getPlayingTrack();
|
||||
}
|
||||
|
||||
public List<JuliaAudioTrack> getPlaylist() {
|
||||
return playlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(AudioEvent event) {
|
||||
|
||||
if(event instanceof TrackEndEvent) {
|
||||
if(playlist.size()-1>=playlistIndex) {
|
||||
if(!looping)
|
||||
playlistIndex++;
|
||||
player.playTrack(playlist.get(playlistIndex).track);
|
||||
player.setPaused(false);
|
||||
}
|
||||
}else if(event instanceof TrackExceptionEvent) {
|
||||
|
||||
}else if(event instanceof TrackStuckEvent) {
|
||||
|
||||
}else if(event instanceof PlayerPauseEvent) {
|
||||
|
||||
}else if(event instanceof PlayerResumeEvent) {
|
||||
|
||||
}else if(event instanceof TrackStartEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canProvide() {
|
||||
chans.values().stream().forEach(c->c.frame = c.player.provide());
|
||||
return chans.values().stream().anyMatch(c->c.frame!=null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] provide20MsAudio() {
|
||||
int dataL = chans.values().stream().map(c->c.frame).filter(f->f!=null).findAny().get().getDataLength();
|
||||
Set<ShortBuffer> afs = chans.values().stream()
|
||||
.map(c->c.frame)
|
||||
.filter(af->af!=null)
|
||||
.map(af->ByteBuffer.wrap(af.getData()).asShortBuffer())
|
||||
.collect(Collectors.toSet());
|
||||
int n = afs.size();
|
||||
|
||||
byte[] result = new byte[dataL];
|
||||
ShortBuffer resultBuffer = ByteBuffer.wrap(result).asShortBuffer();
|
||||
|
||||
int samples = dataL / 2;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
int j = i;
|
||||
resultBuffer.put(i, (short) (afs.stream().mapToInt(sb->sb.get(j)/n).sum()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpus() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class JuliaAudioTrack{
|
||||
AudioTrack track;
|
||||
Type type;
|
||||
String identifier;
|
||||
User querier;
|
||||
|
||||
|
||||
|
||||
public JuliaAudioTrack(AudioTrack track, Type type, String identifier, User querier) {
|
||||
this.track = track;
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.querier = querier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static enum Type{
|
||||
LOCAL,
|
||||
YOUTUBE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user