From c32da2f131c72adb0c16f8e061350f6dd83bd5ef Mon Sep 17 00:00:00 2001 From: Mysaa Date: Thu, 27 May 2021 22:37:07 +0200 Subject: [PATCH] =?UTF-8?q?R=C3=A9=C3=A9criture=20totale=20du=20code.=20C'?= =?UTF-8?q?est=20un=20addon=20nouveau?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bernard/discord/commands/JulSoundBox.java | 427 ++++++++++ src/com/bernard/djulia/DJuLIA.java | 736 ------------------ 2 files changed, 427 insertions(+), 736 deletions(-) create mode 100644 src/com/bernard/discord/commands/JulSoundBox.java delete mode 100644 src/com/bernard/djulia/DJuLIA.java diff --git a/src/com/bernard/discord/commands/JulSoundBox.java b/src/com/bernard/discord/commands/JulSoundBox.java new file mode 100644 index 0000000..e665cb6 --- /dev/null +++ b/src/com/bernard/discord/commands/JulSoundBox.java @@ -0,0 +1,427 @@ +package com.bernard.discord.commands; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Random; +import java.util.Scanner; + +import com.bernard.discord.api.Command; +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.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.TrackEndEvent; +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 com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; + +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.MessageBuilder; +import net.dv8tion.jda.core.audio.AudioSendHandler; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.GuildVoiceState; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.MessageChannel; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.entities.VoiceChannel; +import net.dv8tion.jda.core.managers.AudioManager; + +public class JulSoundBox { + + private static final String soundFolder = "/var/julia/julsoundbox/sounds/"; + public static final String soundExtension = ".opus"; + static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + static AudioManager manager; + static VoiceChannel currentChannel = null; + static VoiceChannel oldChannel = null;//Si set, JuL'IA retournera dans ce salon dès qu'une chanson finira + static BernardSoundHandler soundHandler; + static Queue playlist; + Random randomizator; + static boolean play; + + @Command(name = "playing",grp="snd",group="SoundBox", admin = false, description = "Demande à JuL'IA quel son elle est en train de jouer") + public void playing(Guild guild, Message message) { + if(soundHandler.currentTrack == null && playlist.isEmpty()) { + notifyUser("Ben je suis en fait en train de jouer .... rien du tout", message.getAuthor(), message.getChannel()); + return; + } + EmbedBuilder builder = new EmbedBuilder(); + String playing = ""; + if(soundHandler.currentTrack == null) + playing = "Rien du tout !"; + else + playing = soundHandler.currentTrack.getIdentifier(); + builder.addField("Je joue ", playing, false); + + String queued = ""; + if(playlist.isEmpty()) + queued = "Rien du tout !"; + else { + for (AudioTrack audioTrack : playlist) + queued += audioTrack.getIdentifier().substring(soundFolder.length()) + ","; + queued = queued.substring(0, queued.length()-1); + } + builder.addField("J'ai prévu ", queued, false); + message.getChannel().sendMessage(builder.build()).complete(); + } + + public static void sneakPlay(String sound,VoiceChannel chan) { + oldChannel = currentChannel; + manager.openAudioConnection(chan); + currentChannel = chan; + + playerManager.loadItem("/var/julia/julsoundbox/sounds/" + sound + soundExtension, new AudioLoadResultHandler() { + @Override + public void trackLoaded(AudioTrack track) { + playlist = appendFirst(track, playlist); + play = true; + soundHandler.next(); + } + + @Override + public void playlistLoaded(AudioPlaylist playlist) { + System.err.println("Quoikesquevousavezfaitlà ?!"); + } + + @Override + public void noMatches() { + System.err.println("A moins de transformer le texte en données sonores brutes, je sais pas quoi prononcer"); + } + + @Override + public void loadFailed(FriendlyException exception) { + System.err.println("Je n'ai pas réussi à charger le son ... désolé (en meme temps, vu comme mes devs codent !)"); + } + }); + + } + + @Command(name = "come",grp="snd",group="SoundBox", admin = true, description = "Ammène julia dans le salon vocal auquel l'utilisateur est connécté") + public void come(Guild guild, Message message, User user) { + final GuildVoiceState memberVoiceState = guild.getMember(user).getVoiceState(); + System.out.println("Coming into channel of voice state "+memberVoiceState); + if(!memberVoiceState.inVoiceChannel()) + manager.closeAudioConnection(); + else { + manager.openAudioConnection(memberVoiceState.getChannel()); + currentChannel = memberVoiceState.getChannel(); + } + } + + @Command(name = "go",grp="snd",group="SoundBox", admin = true, description = "Ammène julia dans le salon spécifié") + public void go(Guild guild, Message message, User user) { + String channelName = message.getContentRaw().substring(message.getContentRaw().indexOf("go")+3); + System.out.println("Going to channel : "+channelName); + switch(channelName) { + case "néant": + case "rien": + case "away": + case "null": + case "nichts": + if(currentChannel != null) + manager.closeAudioConnection(); + currentChannel = null; + return; + } + List chans = guild.getVoiceChannelsByName(channelName,true); + if(chans.size() <= 0) { + notifyUser("Je ne connais pas le channel '"+channelName+"'", user, message.getChannel()); + return; + } + currentChannel = chans.get(0); + manager.openAudioConnection(currentChannel); + } + + @Command(name = "play",grp="snd",group="SoundBox", admin = true, description = "Reprends ou lance la lecture d'un son") + public void play(Guild guild, Message message, User user) { + String soundName = null; + if(message.getContentRaw().endsWith("play")) { + if(soundHandler.currentTrack != null || !playlist.isEmpty()) { + soundHandler.update(true); + return; + }else { + System.out.println("Random mode !!!"); + File[] songsFiles = new File("/var/julia/julsoundbox/sounds/").listFiles(); + soundName = songsFiles[randomizator.nextInt(songsFiles.length)].getName().substring(0, soundExtension.length()+1); + } + }else{ + soundName = message.getContentRaw().substring(message.getContentRaw().indexOf("play")+5); + if(!checkUserSoundPermission(user, soundName)){ + notifyUser("Vous n'avez pas accès à ce morceau", user, null); + return; + } + } + System.out.println("Trying to play : "+soundName); + playerManager.loadItem("/var/julia/julsoundbox/sounds/" + soundName + soundExtension, new AudioLoadResultHandler() { + @Override + public void trackLoaded(AudioTrack track) { + playlist = appendFirst(track, playlist); + play = true; + soundHandler.next(); + } + + @Override + public void playlistLoaded(AudioPlaylist playlist) { + notifyUser("Quoikesquevousavezfaitlà ?!", user, null); + } + + @Override + public void noMatches() { + notifyUser("A moins de transformer le texte en données sonores brutes, je sais pas quoi prononcer", user, null); + } + + @Override + public void loadFailed(FriendlyException exception) { + notifyUser("Je n'ai pas réussi à charger le son ... désolé (en meme temps, vu comme mes devs codent !)", user, null); + } + }); + } + + @Command(name = "play2",grp="snd",group="SoundBox", admin = true, description = "Reprends ou lance la lecture d'un son2") + public void play2(Guild guild, Message message, User user) { + String soundName = message.getContentRaw().substring(message.getContentRaw().indexOf("play2")+6); + System.out.println("Trying to play : "+soundName); + playerManager.loadItem("/var/julia/julsoundbox/sounds/" + soundName + soundExtension, new AudioLoadResultHandler() { + @Override + public void trackLoaded(AudioTrack track) { + soundHandler.altTrack = track; + soundHandler.altPlayer.startTrack(track, false); + } + + @Override + public void playlistLoaded(AudioPlaylist playlist) { + notifyUser("Quoikesquevousavezfaitlà ?!", user, null); + } + + @Override + public void noMatches() { + notifyUser("A moins de transformer le texte en données sonores brutes, je sais pas quoi prononcer", user, null); + } + + @Override + public void loadFailed(FriendlyException exception) { + notifyUser("Je n'ai pas réussi à charger le son ... désolé (en meme temps, vu comme mes devs codent !)", user, null); + } + }); + } + + @Command(name = "queue",grp="snd",group="SoundBox", admin = true, description = "Ajoute un son à la liste de lecture") + public void queue(Guild guild, Message message, User user) { + String soundName = null; + if(message.getContentRaw().indexOf("queue")+5 == message.getContentRaw().length()) { + File[] songsFiles = new File("/var/julia/julsoundbox/sounds/").listFiles(); + soundName = songsFiles[randomizator.nextInt(songsFiles.length)].getName().substring(0, ".opus".length()); + }else{ + soundName = message.getContentRaw().substring(message.getContentRaw().indexOf("queue")+6); + if(!checkUserSoundPermission(user, soundName)){ + notifyUser("Vous n'avez pas accès à ce morceau", user, null); + return; + } + } + playerManager.loadItem(soundFolder + soundName + ".opus", new AudioLoadResultHandler() { + @Override + public void trackLoaded(AudioTrack track) { + playlist.add(track); + soundHandler.update(); + } + + @Override + public void playlistLoaded(AudioPlaylist playlist) { + notifyUser("Quoikesquevousavezfaitlà ?!", user, null); + } + + @Override + public void noMatches() { + notifyUser("A moins de transformer le texte en données sonores brutes, je sais pas quoi prononcer", user, null); + } + + @Override + public void loadFailed(FriendlyException exception) { + notifyUser("Je n'ai pas réussi à charger le son ... désolé (en meme temps, vu comme mes devs codent !)", user, null); + } + }); + } + + @Command(name = "unqueue",grp="snd",group="SoundBox", admin = true, description = "Enlève un son de la liste de lecture")//TODO test + public void unqueue(Guild guild, Message message, User user) { + String soundId = message.getContentRaw().substring(message.getContentRaw().indexOf("unqueue")+8); + if(soundId.matches("^[0-9]+$")) { + Iterator it = playlist.iterator(); + int end = Integer.parseInt(soundId, 10) - 1;//Mathe way + int i = 0; + AudioTrack track = null; + for(;i it = playlist.iterator(); + while(it.hasNext()) { + AudioTrack t = it.next(); + if(t.getUserData().equals(soundId)) + playlist.remove(t); + } + } + soundHandler.update(); + } + + @Command(name = "pause",grp="snd",group="SoundBox", admin = true, description = "Met le son joué en pause (wow)") + public void pause(Guild guild, Message message, User user) { + soundHandler.update(false); + } + + @Command(name = "chut",grp="snd",group="SoundBox", admin = true, description = "Arette le son que JuL'IA joue (un !!play reprendra le morceau suivant ") + public void chut(Guild guild, Message message, User user) { + play = false; + soundHandler.next(); + } + + @Command(name = "soundInit",grp="snd",group="SoundBox", admin = true, description = "Evite que tout le programme ne crashe .... a ne pas oublier (en attendant que tout 'fonctionne' ...)") + public void soundInit(Guild guild) { + playerManager = new DefaultAudioPlayerManager(); + soundHandler = new BernardSoundHandler(); + manager = guild.getAudioManager(); + AudioSourceManagers.registerLocalSource(playerManager); + manager.setSendingHandler(soundHandler); + currentChannel = null; + playlist = new LinkedList<>(); + randomizator = new Random(); + play = false; + } + + public class BernardSoundHandler implements AudioSendHandler,AudioEventListener { + + public AudioTrack currentTrack; + public AudioTrack altTrack; + + private final AudioPlayer audioPlayer; + final AudioPlayer altPlayer; + + public BernardSoundHandler() { + audioPlayer = playerManager.createPlayer(); + altPlayer = playerManager.createPlayer(); + audioPlayer.addListener(this); + altPlayer.addListener(this); + } + + public void next() { + currentTrack = playlist.poll(); + audioPlayer.startTrack(currentTrack, false); + update(); + } + + public void update() { + audioPlayer.setPaused(!JulSoundBox.play); + } + + public void update(boolean play) { + JulSoundBox.play = play; + update(); + } + + @Override + public void onEvent(AudioEvent event) { + if(event instanceof TrackEndEvent) { + altTrack = null; + if(oldChannel != null) { + manager.openAudioConnection(oldChannel); + currentChannel = oldChannel; + + } + if(playlist.size() > 0) { + currentTrack = playlist.poll(); + audioPlayer.startTrack(currentTrack, false); + update(); + }else { + play = false; + currentTrack = null; + } + + } + } + + + private AudioFrame lastFrame; + /////////// Methods for sound playing /////////// + @Override + public boolean canProvide() { + if(altTrack != null) { + AudioFrame f1 = audioPlayer.provide(); + AudioFrame f2 = altPlayer.provide(); + lastFrame = (Math.random() > 0.5)?f1:f2; + }else + lastFrame = audioPlayer.provide(); + return lastFrame != null; + } + + @Override + public byte[] provide20MsAudio() { + return lastFrame.data; + } + + @Override + public boolean isOpus() { + return true; + } + + } + + public static final boolean checkUserSoundPermission(User user,String sound) { + if(sound.indexOf("/") == -1) + return true; + File soundFile = new File(soundFolder,sound+".opus"); + if(!soundFile.exists()) + return true;//will be catched later, returning false will cause the 'not permitted' message appear + File lockFile = new File(soundFile.getParent(),"lock");//TODO Change with BernardFilesAPI + if(!lockFile.exists()) + return true;//No lock file : the folder is open + try { + Scanner sc = new Scanner(new FileInputStream(lockFile)); + while(sc.hasNextLine()) + if(user.getId().equals(sc.nextLine())) { + sc.close(); + return true; + } + sc.close(); + } catch (FileNotFoundException e) { + System.err.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); + System.err.println("No right to access to "+lockFile.getAbsolutePath()); + e.printStackTrace(); + System.err.println("\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/"); + } + return false; + } + + //////////// Useful static functions /////////////// + + public static final void notifyUser(String problem, User user, MessageChannel channel) { + MessageBuilder builder = new MessageBuilder(); + builder.append(user); + builder.append(" : "); + builder.append(problem); + user.openPrivateChannel().queue((chan) -> { + chan.sendMessage(builder.build()).queue(); + }); + } + + public static final Queue appendFirst(T element,Queue queue){ + Queue out = new LinkedList(); + out.add(element); + for (T t : queue) { + out.add(t); + } + return out; + } + +} diff --git a/src/com/bernard/djulia/DJuLIA.java b/src/com/bernard/djulia/DJuLIA.java deleted file mode 100644 index 2dd710c..0000000 --- a/src/com/bernard/djulia/DJuLIA.java +++ /dev/null @@ -1,736 +0,0 @@ -package com.bernard.djulia; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; -import java.security.GeneralSecurityException; -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.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import com.bernard.djulia.DJuLIA.JuliaAudioSendHandler.JuliaAudioChannel; -import com.bernard.djulia.DJuLIA.JuliaAudioTrack.Type; -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.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.services.youtube.YouTube; -import com.google.api.services.youtube.model.SearchListResponse; -import com.google.api.services.youtube.model.SearchResult; -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.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.tools.FriendlyException; -import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; -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.Permission; -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; -import net.dv8tion.jda.core.entities.MessageEmbed.Field; -import net.dv8tion.jda.core.entities.PrivateChannel; -import net.dv8tion.jda.core.entities.Role; -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.events.message.react.MessageReactionAddEvent; -import net.dv8tion.jda.core.managers.AudioManager; - - -@JuLIAddon(devs = "Mysaa", name = "djulia", version = "beta") -public class DJuLIA { - - public static final String MUSIC = "musique"; - - Map guilds = new HashMap<>(); - - Map localGuilds = new HashMap<>(); - - AudioPlayerManager audioManager; - - YouTube youtube = getService(); - - 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; - } - 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.isEmpty()) { - if(!playButton(g, commande.getUser())) - bMsg(commande.getChannel(), g.getMember(commande.getUser()).getEffectiveName()+", vous en pouvez pas lancer la lecture ..."); - return; - }else { - JuliaAudioTrack jat = understandSong(arg, commande.getChannel(), commande.getUser()); - if(jat==null) { - bMsg(commande.getChannel(),"Je ne sais pas quoi jouer quand tu me dis "+arg); - return; - } - sender(g).getChan(MUSIC).play(jat); - if(playingMessages.get(g.getIdLong()).stream().anyMatch(m->m.getGuild().getIdLong()==g.getIdLong())) - addPlayingMessage(g, commande.getChannel().sendMessage("DUMMY MESSAGE").complete()); - - } - - - } - @Command(admin = false, description = "Permet de rajouter un morcau à la file d'attente", name = "queue") - public void queueCommand(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; - } - String arg = commande.getStringCommand().substring(commande.getStringCommand().split(" ")[0].length()); - if(!arg.isEmpty())arg = arg.substring(1);// On enlève l'espace en trop - - - JuliaAudioTrack jat = understandSong(arg, commande.getChannel(), commande.getUser()); - if(jat==null) { - bMsg(commande.getChannel(),"Je ne sais pas quoi jouer quand tu me dis "+arg); - return; - } - sender(g).getChan(MUSIC).queue(jat); - if(playingMessages.get(g.getIdLong()).stream().anyMatch(m->m.getGuild().getIdLong()==g.getIdLong())) - addPlayingMessage(g, commande.getChannel().sendMessage("DUMMY MESSAGE").complete()); - - - - - } - - - - @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 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()); - } - - - /// Commandes internes - public boolean playButton(Guild g,User u) { - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - if(!isDJ(g, u) && chan.currentTrack().querier.getIdLong() != u.getIdLong()) - return false; - chan.play(); - return true; - } - public boolean pauseButton(Guild g,User u) { - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - if(!isDJ(g, u) && chan.currentTrack().querier.getIdLong() != u.getIdLong()) - return false; - chan.pause(); - return true; - } - public boolean nextButton(Guild g,User u) { - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - if(!isDJ(g, u) && chan.currentTrack().querier.getIdLong() != u.getIdLong()) - return false; - chan.next(); - return true; - } - public boolean stopButton(Guild g,User u) { - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - if(!isDJ(g, u) && chan.currentTrack().querier.getIdLong() != u.getIdLong()) - return false; - chan.stop(); - return true; - } - public boolean loopButton(Guild g,User u) { - if(!isDJ(g, u)) - return false; - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - chan.looping = !chan.looping; - return true; - } - public boolean emptyButton(Guild g,User u) { - if(!isDJ(g, u)) - return false; - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - chan.empty(); - return true; - } - - - - Map> playingMessages = new HashMap<>(); - public void updatePlayingMessages(Guild g) { - if(!playingMessages.containsKey(g.getIdLong())) - return; - JuliaAudioChannel chan = guilds.get(g.getIdLong()).getChan(MUSIC); - JuliaAudioTrack playing = chan.currentTrack(); - EmbedBuilder builder = new EmbedBuilder(); - builder.setAuthor("DJulia in the place"); - builder.setTitle("Je joue "+playing.displayName+" demandé par"+g.getMember(playing.querier)); - int progressP100 = (int) (chan.playProgress()*10); - String t1 = "==========",t2 = "----------"; - builder.setDescription("`<"+t1.substring(progressP100)+t2.substring(10-progressP100)+">`"); - builder.addField("Il y a "+chan.trackLeftCount()+" musiques dans la queue", null, false); - MessageEmbed embed = builder.build(); - for(Message m : playingMessages.get(g.getIdLong())) - m.editMessage(embed).queue(); - } - public void addPlayingMessage(Guild g,Message m) { - if(!playingMessages.containsKey(g.getIdLong())) - playingMessages.put(g.getIdLong(),new HashSet<>()); - playingMessages.get(g.getIdLong()).add(m); - updatePlayingMessages(g); - m.addReaction("▶").queue(); - m.addReaction("⏸").queue(); - m.addReaction("⏭").queue(); - m.addReaction("⏹").queue(); - m.addReaction("🔁").queue(); - m.addReaction("🗑").queue(); - } - @Discord(description = "Vérifie les boutons des playing messages") - public void onReact(MessageReactionAddEvent e) { - if(!playingMessages.containsKey(e.getGuild().getIdLong()))return; - if(!playingMessages.get(e.getGuild().getIdLong()).stream().map(Message::getIdLong).anyMatch(l->l==e.getMessageIdLong()))return; - if(e.getReactionEmote().isEmote())return; - if(!"▶⏸⏭⏹🔁🗑".contains(e.getReactionEmote().getName()))return; - Guild g = getGuild(e.getUser(),e.getChannel()); - User u = e.getUser(); - switch(e.getReactionEmote().getName()) { - case "▶": - playButton(g, u); - break; - case "⏸": - pauseButton(g, u); - break; - case "⏭": - nextButton(g, u); - break; - case "⏹": - stopButton(g, u); - break; - case "🔁": - loopButton(g, u); - break; - case "🗑": - emptyButton(g, u); - break; - - } - } - - - public Guild getGuild(DiscordCCommande commande) { - return getGuild(commande.getUser(), commande.getChannel()); - } - public Guild getGuild(User u,MessageChannel chan) { - - if(chan instanceof TextChannel) - return ((TextChannel)chan).getGuild(); - - if(localGuilds.containsKey(u.getIdLong())) - return Trukilie.jda().getGuildById(localGuilds.get(u.getIdLong())); - - List mutualGuilds = u.getMutualGuilds(); - if(mutualGuilds.size() == 1) - return mutualGuilds.get(0); - - Set vocalGuilds = mutualGuilds.stream() - .filter(gu->gu.getMember(u).getVoiceState().inVoiceChannel()) - .collect(Collectors.toSet()); - if(vocalGuilds.size() == 1) - return vocalGuilds.iterator().next(); - - Set vocalGuildsWithJulia = vocalGuilds.stream() - .filter(g->guilds.containsKey(g.getIdLong())) - .filter(g->guilds.get(g.getIdLong()).currentChannel.getId().equals(g.getMember(u).getVoiceState().getAudioChannel().getId())) - .collect(Collectors.toSet()); - if(vocalGuildsWithJulia.size() == 1) - return vocalGuildsWithJulia.iterator().next(); - - return null; - } - - public JuliaAudioTrack understandSong(String text,MessageChannel chan, User u) { - //TODO every case - Pattern youtubeURL = Pattern.compile("^(https?\\:\\/\\/)?(www\\.)?(youtube\\.com|youtu\\.?be)\\/.+$"); - String toLoad = text; - String displayName = toLoad; - Type type = Type.LOCAL; - if(!youtubeURL.matcher(text).find()) { - //Search in files - //TODO à implémenter : les fichiers locaux* - - //else make youtube search - try { - YouTube.Search.List request = youtube.search().list("snippet"); - SearchListResponse response = request.setMaxResults(10L) - .setQ(text) - .setType("video") - .execute(); - List results = response.getItems(); - int index = selector(chan, u, "Quelle vidéo Youtube voulez-vous lire ?", results.stream().map(s->s.getSnippet().getTitle()+" de "+s.getSnippet().getChannelTitle()).collect(Collectors.toList())); - toLoad = "htp://youtu.be/"+results.get(index).getId(); - displayName = results.get(index).getSnippet().getTitle(); - type = Type.YOUTUBE; - //TODO traiter le cas pas de réponce - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - AudioTrack[] t = {null}; - try { - audioManager.loadItem(toLoad, new AudioLoadResultHandler() { - - @Override - public void trackLoaded(AudioTrack track) { - t[0] = track; - } - - @Override - public void playlistLoaded(AudioPlaylist playlist) { - //TODO gérer les playlistes - } - - @Override - public void noMatches() { - System.err.println("Les vérifications n'on pas marchées DJulia"); - } - - @Override - public void loadFailed(FriendlyException exception) { - exception.printStackTrace(); - } - }).get(); - return new JuliaAudioTrack(t[0], type, toLoad, u, displayName); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } - return null; - } - - public boolean isDJ(Guild g,User u) { - Optional rr = g.getRolesByName("dj", true).stream().findAny(); - if(!rr.isPresent()) - return g.getMember(u).hasPermission(Permission.ADMINISTRATOR); - else - return g.getMember(u).getRoles().contains(rr.get()); - } - - Map waitingEmojis = new HashMap<>(); - Map everyEventLocks = new HashMap<>(); - - public int selector(MessageChannel chan,String title,List choices) { - List 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 choices) { - return selector(chan,List.of(authorized),title,choices); - } - public int selector(MessageChannel chan,List authorized,String title,List 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 Set inter(Collection c1,Collection 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 JuliaAudioSendHandler sender(Guild g) { - if(guilds.containsKey(g.getIdLong())) - return guilds.get(g.getIdLong()); - guilds.put(g.getIdLong(), new JuliaAudioSendHandler(g)); - return guilds.get(g.getIdLong()); - } - - public class JuliaAudioSendHandler implements AudioSendHandler{ - VoiceChannel currentChannel; - Guild currentGuild; - AudioManager manager; - Map 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 playlist; - int playlistIndex = 0; - boolean looping = false; - - public JuliaAudioChannel() { - player = audioManager.createPlayer(); - player.addListener(this); - playlist = new ArrayList<>(); - } - - public void play() { - if(playlistIndex getPlaylist() { - return playlist; - } - - @Override - public void onEvent(AudioEvent event) { - - if(event instanceof TrackEndEvent) { - if(playlist.size()-1>=playlistIndex) { - if(!looping) - playlistIndex++; - if(playlistIndexc.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 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())); - } - updatePlayingMessages(currentGuild); - return result; - } - - @Override - public boolean isOpus() { - return true; - } - - } - - public static class JuliaAudioTrack{ - AudioTrack track; - Type type; - String identifier; - User querier; - String displayName; - - - - public JuliaAudioTrack(AudioTrack track, Type type, String identifier, User querier,String displayName) { - this.track = track; - this.type = type; - this.identifier = identifier; - this.querier = querier; - this.displayName = displayName; - } - - - - public static enum Type{ - LOCAL, - YOUTUBE; - } - } - - - - private static final String APPLICATION_NAME = "DJulia"; - private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); - - /** - * Build and return an authorized API client service. - * - * @return an authorized API client service - * @throws GeneralSecurityException, IOException - */ - public static YouTube getService() throws GeneralSecurityException, IOException { - final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - return new YouTube.Builder(httpTransport, JSON_FACTORY, null) - .setApplicationName(APPLICATION_NAME) - .build(); - } -}