=Fixing Youtube Player

This commit is contained in:
Alex
2019-10-19 02:56:11 -04:00
parent dfbf646abc
commit 462bb58ead
13 changed files with 216 additions and 355 deletions
+3
View File
@@ -15,6 +15,9 @@ public class CommandMusicMain extends Command
framework.addCommand("join", new SubCommandJoin(KittyRole.General, KittyRating.Safe)); framework.addCommand("join", new SubCommandJoin(KittyRole.General, KittyRating.Safe));
framework.addCommand("leave", new SubCommandLeave(KittyRole.General, KittyRating.Safe)); framework.addCommand("leave", new SubCommandLeave(KittyRole.General, KittyRating.Safe));
framework.addCommand("add", new SubCommandAddTrack(KittyRole.General, KittyRating.Safe)); framework.addCommand("add", new SubCommandAddTrack(KittyRole.General, KittyRating.Safe));
framework.addCommand("skip", new SubCommandSkip(KittyRole.General, KittyRating.Safe));
framework.addCommand("stop", new SubCommandStop(KittyRole.General, KittyRating.Safe));
framework.addCommand("playlist", new SubCommandPlaylist(KittyRole.General, KittyRating.Safe));
} }
@Override @Override
+6 -6
View File
@@ -9,7 +9,6 @@ import dataStructures.KittyRole;
import dataStructures.KittyUser; import dataStructures.KittyUser;
import dataStructures.UserInput; import dataStructures.UserInput;
import network.NetworkYoutube; import network.NetworkYoutube;
import utils.audio.AudioController;
public class SubCommandAddTrack extends SubCommand public class SubCommandAddTrack extends SubCommand
{ {
@@ -17,16 +16,17 @@ public class SubCommandAddTrack extends SubCommand
public SubCommandAddTrack(KittyRole level, KittyRating rating) { super(level, rating); } public SubCommandAddTrack(KittyRole level, KittyRating rating) { super(level, rating); }
NetworkYoutube YT = new NetworkYoutube(); NetworkYoutube YT = new NetworkYoutube();
AudioController ac = new AudioController();
@Override @Override
public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input)
{ {
//Get track from Youtube //Get track from Youtube
String video = YT.getYT(input.args); String video = input.args;
ac.loadAndPlay(video, guild); if(!(video.startsWith("https://www.youtube") || video.startsWith("https://www.youtu.be")))
System.out.println("Internal: " + ac.response); {
video = YT.getYT(video);
}
guild.audio.playVideo(video);
return new SubCommandFormattable(video); return new SubCommandFormattable(video);
} }
} }
@@ -0,0 +1,24 @@
package commands.music;
import java.util.ArrayList;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import core.SubCommand;
import core.SubCommandFormattable;
import dataStructures.*;
public class SubCommandPlaylist extends SubCommand
{
public SubCommandPlaylist(KittyRole roleLevel, KittyRating contentRating) {super(roleLevel, contentRating); }
@Override
public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input)
{
// ArrayList<AudioTrack> playlist = guild.audio.getPlaylist();
String stringPlaylist = guild.audio.getPlaylist(guild.audio.player);
return new SubCommandFormattable(stringPlaylist);
}
}
+23
View File
@@ -0,0 +1,23 @@
package commands.music;
import core.SubCommand;
import core.SubCommandFormattable;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.UserInput;
public class SubCommandSkip extends SubCommand
{
public SubCommandSkip(KittyRole level, KittyRating rating) { super(level, rating); }
{
}
@Override
public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input)
{
return new SubCommandFormattable(guild.audio.skipVideo(guild.audio.player));
}
}
+24
View File
@@ -0,0 +1,24 @@
package commands.music;
import core.SubCommand;
import core.SubCommandFormattable;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.UserInput;
public class SubCommandStop extends SubCommand
{
public SubCommandStop(KittyRole roleLevel, KittyRating contentRating) {super(roleLevel, contentRating);}
@Override
public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input)
{
return new SubCommandFormattable(guild.audio.stopPlayer(guild.audio.player));
}
}
+20 -4
View File
@@ -7,16 +7,29 @@ import java.util.concurrent.Semaphore;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
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.player.AudioPlayerManager; //import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
//import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; //import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import core.lua.PluginManager; import core.lua.PluginManager;
import dataStructures.*; import dataStructures.KittyChannel;
import dataStructures.KittyCore;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import main.Main; import main.Main;
import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.AccountType;
import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDA;
import net.dv8tion.jda.core.JDABuilder; import net.dv8tion.jda.core.JDABuilder;
import net.dv8tion.jda.core.entities.*; import net.dv8tion.jda.core.entities.Emote;
import net.dv8tion.jda.core.entities.Game;
import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.entities.User;
import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent;
import offline.Ref; import offline.Ref;
import utils.AdminControl; import utils.AdminControl;
@@ -56,7 +69,7 @@ public class ObjectBuilderFactory
private static CommandManager commandManager; private static CommandManager commandManager;
//Audio track manager //Audio track manager
// private static AudioPlayerManager audioPlayer = new DefaultAudioPlayerManager(); private static AudioPlayerManager playerManager = new DefaultAudioPlayerManager();
// Localization classes - these are singletons, but should be initialized before almost all other // Localization classes - these are singletons, but should be initialized before almost all other
// things so their inclusion in the factory is to ensure they're started at the correct time. // things so their inclusion in the factory is to ensure they're started at the correct time.
@@ -91,6 +104,9 @@ public class ObjectBuilderFactory
database = null; database = null;
stats = null; stats = null;
AudioSourceManagers.registerRemoteSources(playerManager);
AudioSourceManagers.registerLocalSource(playerManager);
// Start by reading from things that are external. Because // Start by reading from things that are external. Because
// we require these things to be resolved before the rest of the application, // we require these things to be resolved before the rest of the application,
// we place them here. // we place them here.
@@ -148,7 +164,7 @@ public class ObjectBuilderFactory
else else
{ {
// Construct a new guild with defaults // Construct a new guild with defaults
guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString, new AudioUtils(event.getGuild())); guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString, new AudioUtils(event.getGuild(), playerManager));
DatabaseManager.instance.globalRegister(guild); DatabaseManager.instance.globalRegister(guild);
guildCache.put(uid, guild); guildCache.put(uid, guild);
} }
+1 -10
View File
@@ -2,15 +2,10 @@ package dataStructures;
import java.util.ArrayList; import java.util.ArrayList;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
import core.DatabaseManager; import core.DatabaseManager;
import core.DatabaseTrackedObject; import core.DatabaseTrackedObject;
import utils.AdminControl; import utils.AdminControl;
import utils.audio.AudioUtils; import utils.audio.AudioUtils;
import utils.audio.GuildMusicManager;
// Context for a given guild for kittybot. Primarily designed to hold guild-specific settings. // Context for a given guild for kittybot. Primarily designed to hold guild-specific settings.
public class KittyGuild extends DatabaseTrackedObject public class KittyGuild extends DatabaseTrackedObject
@@ -28,8 +23,6 @@ public class KittyGuild extends DatabaseTrackedObject
public ArrayList <KittyPoll> choices = new ArrayList<KittyPoll>(); public ArrayList <KittyPoll> choices = new ArrayList<KittyPoll>();
public AdminControl control; public AdminControl control;
public AudioUtils audio; public AudioUtils audio;
public GuildMusicManager musicManager;
public AudioPlayerManager playerManager = new DefaultAudioPlayerManager();
public ArrayList <KittyUser> raffleUsersUnchosen = new ArrayList<KittyUser>(); public ArrayList <KittyUser> raffleUsersUnchosen = new ArrayList<KittyUser>();
public ArrayList <KittyUser> raffleUsersChosen = new ArrayList<KittyUser>(); public ArrayList <KittyUser> raffleUsersChosen = new ArrayList<KittyUser>();
@@ -51,14 +44,12 @@ public class KittyGuild extends DatabaseTrackedObject
// Default content for a guild // Default content for a guild
public KittyGuild(String uniqueID, AdminControl adminControl, ArrayList <String> emoji, AudioUtils audio) public KittyGuild(String uniqueID, AdminControl adminControl, ArrayList <String> emoji, AudioUtils audio)
{ {
super(uniqueID); super(uniqueID);
AudioSourceManagers.registerRemoteSources(playerManager);
AudioSourceManagers.registerLocalSource(playerManager);
this.uniqueID = uniqueID; this.uniqueID = uniqueID;
roleList = new KittyTrackedVector(roleListName, uniqueID); roleList = new KittyTrackedVector(roleListName, uniqueID);
beans = new KittyTrackedLong(beansName, uniqueID); beans = new KittyTrackedLong(beansName, uniqueID);
registerTrackedObjects(); registerTrackedObjects();
musicManager = new GuildMusicManager(playerManager);
control = adminControl; control = adminControl;
this.contentRating = KittyRating.Safe; this.contentRating = KittyRating.Safe;
+1 -106
View File
@@ -49,110 +49,6 @@ import utils.GlobalLog;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Main extends ListenerAdapter public class Main extends ListenerAdapter
{ {
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 byte[] provide20MsAudio()
{
return lastFrame.getData();
}
@Override public boolean isOpus()
{
return true;
}
}
public class SmallAudio implements AudioLoadResultHandler
{
private TextChannel channel;
private Guild guild;
private AudioPlayer player;
private SmallAudio(TextChannel channel, Guild guild, AudioPlayer player)
{
this.channel = channel;
this.player = player;
this.guild = guild;
}
@Override public void loadFailed(FriendlyException arg0) { }
@Override public void noMatches() { }
@Override public void playlistLoaded(AudioPlaylist arg0) { }
@Override
public void trackLoaded(AudioTrack track)
{
connectToFirstVoiceChannel(guild.getAudioManager());
player.startTrack(track, false);
}
private void connectToFirstVoiceChannel(AudioManager audioManager)
{
if (!audioManager.isConnected() && !audioManager.isAttemptingToConnect())
{
for (VoiceChannel voiceChannel : audioManager.getGuild().getVoiceChannels())
{
audioManager.openAudioConnection(voiceChannel);
break;
}
}
}
}
public final AudioPlayerManager playerManager;
public final AudioPlayer player;
// Initialization and setup
public static void main(String[] args) throws InterruptedException, LoginException, Exception
{
JDA bot = new JDABuilder(AccountType.BOT).setToken(Ref.TestToken).buildBlocking();
bot.addEventListener(new Main());
}
public Main()
{
this.playerManager = new DefaultAudioPlayerManager();
this.player = playerManager.createPlayer();
AudioSourceManagers.registerRemoteSources(playerManager);
AudioSourceManagers.registerLocalSource(playerManager);
}
@Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event)
{
if(event.getMessage().getContentRaw().contains("!hasan"))
{
final TextChannel channel = event.getChannel();
final Guild guild = channel.getGuild();
guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player));
playerManager.loadItemOrdered(player, "https://www.youtube.com/watch?v=qL-JCVA22Lo", new SmallAudio(channel, guild, player));
}
super.onGuildMessageReceived(event);
}
}
/* ----------------------------------------------------------------------------------------------------------------------------------------------------------
// Variables and bot specific objects // Variables and bot specific objects
private static KittyCore kittyCore; private static KittyCore kittyCore;
private static DatabaseManager databaseManager; private static DatabaseManager databaseManager;
@@ -236,5 +132,4 @@ public class Main extends ListenerAdapter
if(!Superintendent.perCommandUpkeepPost(kittyCore, databaseManager)) if(!Superintendent.perCommandUpkeepPost(kittyCore, databaseManager))
return; return;
} }
} }
*/
-84
View File
@@ -1,84 +0,0 @@
package utils.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 dataStructures.KittyGuild;
public class AudioController
{
private final AudioPlayerManager playerManager;
public String response;
public AudioController()
{
playerManager = new DefaultAudioPlayerManager();
AudioSourceManagers.registerRemoteSources(playerManager);
AudioSourceManagers.registerLocalSource(playerManager);
}
public void loadAndPlay(final String trackUrl, KittyGuild guild)
{
GuildMusicManager musicManager = guild.musicManager;
response = "HERE";
playerManager.loadItemOrdered(musicManager, trackUrl, new AudioLoadResultHandler()
{
@Override
public void trackLoaded(AudioTrack track)
{
response = "Adding to queue " + track.getInfo().title;
System.out.println("QUEUED");
play(musicManager, track);
}
@Override
public void playlistLoaded(AudioPlaylist playlist)
{
AudioTrack firstTrack = playlist.getSelectedTrack();
if (firstTrack == null)
{
firstTrack = playlist.getTracks().get(0);
}
response = "Adding to queue " + firstTrack.getInfo().title + " (first track of playlist " + playlist.getName() + ")";
play(musicManager, firstTrack);
}
@Override
public void noMatches()
{
System.out.println("NOT QUEUED");
response = "Nothing found by " + trackUrl;
}
@Override
public void loadFailed(FriendlyException exception)
{
System.out.println("EXCEPTION");
System.out.println(exception.getCause());
}
});
}
private void play(GuildMusicManager musicManager, AudioTrack track)
{
musicManager.scheduler.queue(track);
}
private void skipTrack(KittyGuild guild)
{
GuildMusicManager musicManager = guild.musicManager;
musicManager.scheduler.nextTrack();
response = "Skipped to next track.";
}
}
@@ -1,41 +0,0 @@
package utils.audio;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
import net.dv8tion.jda.core.audio.AudioSendHandler;
/**
* This is a wrapper around AudioPlayer which makes it behave as an AudioSendHandler for JDA. As JDA calls canProvide
* before every call to provide20MsAudio(), we pull the frame in canProvide() and use the frame we already pulled in
* provide20MsAudio().
*/
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 byte[] provide20MsAudio()
{
return lastFrame.getData();
}
@Override
public boolean isOpus()
{
return true;
}
}
+114 -6
View File
@@ -1,4 +1,17 @@
package utils.audio; package utils.audio;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
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 com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
import net.dv8tion.jda.core.audio.AudioSendHandler;
import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.entities.VoiceChannel; import net.dv8tion.jda.core.entities.VoiceChannel;
import net.dv8tion.jda.core.managers.AudioManager; import net.dv8tion.jda.core.managers.AudioManager;
@@ -6,13 +19,19 @@ import net.dv8tion.jda.core.managers.AudioManager;
public class AudioUtils public class AudioUtils
{ {
private Guild guild; private Guild guild;
public AudioManager audio; public AudioManager am;
public final AudioPlayer player;
public final AudioPlayerManager playerManager;
private Queue <AudioTrack> playlist = new LinkedList<>();
public AudioUtils(Guild guild) public AudioUtils(Guild guild, AudioPlayerManager playerManager)
{ {
player = playerManager.createPlayer();
this.playerManager = playerManager;
this.guild = guild; this.guild = guild;
audio = guild.getAudioManager(); am = guild.getAudioManager();
} }
public boolean joinChannel(String channelName) public boolean joinChannel(String channelName)
@@ -21,7 +40,7 @@ public class AudioUtils
channel = guild.getVoiceChannelsByName(channelName, true).get(0); channel = guild.getVoiceChannelsByName(channelName, true).get(0);
if(channel != null) if(channel != null)
{ {
audio.openAudioConnection(channel); am.openAudioConnection(channel);
return true; return true;
} }
return false; return false;
@@ -29,11 +48,100 @@ public class AudioUtils
public boolean leaveChannel() public boolean leaveChannel()
{ {
if(audio.isConnected()) if(am.isConnected())
{ {
audio.closeAudioConnection(); am.closeAudioConnection();
return true; return true;
} }
return false; return false;
} }
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 byte[] provide20MsAudio()
{
return lastFrame.getData();
}
@Override public boolean isOpus()
{
return true;
}
}
public class SmallAudio implements AudioLoadResultHandler
{
private AudioPlayer player;
private SmallAudio(AudioPlayer player)
{
this.player = player;
}
@Override public void loadFailed(FriendlyException arg0) { }
@Override public void noMatches() { }
@Override public void playlistLoaded(AudioPlaylist arg0) { }
@Override
public void trackLoaded(AudioTrack track)
{
synchronized(playlist)
{
playlist.add(track);
}
//if(player.getPlayingTrack() == null)
{
do
{
if(player.getPlayingTrack() == null)
{
player.startTrack(playlist.poll(), false);
}
}
while(!playlist.isEmpty());
}
}
}
public String playVideo(String videoURL)
{
guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player));
playerManager.loadItemOrdered(player, videoURL, new SmallAudio(player));
return null;
}
public String skipVideo(AudioPlayer player)
{
return null;
}
public String stopPlayer(AudioPlayer player)
{
playlist.clear();
player.stopTrack();
return "Stopped";
}
public String getPlaylist(AudioPlayer player)
{
return player.getPlayingTrack().getInfo().title;
}
} }
-36
View File
@@ -1,36 +0,0 @@
package utils.audio;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
/**
* Holder for both the player and a track scheduler for one guild.
*/
public class GuildMusicManager {
/**
* Audio player for the guild.
*/
public final AudioPlayer player;
/**
* Track scheduler for the player.
*/
public final TrackScheduler scheduler;
/**
* Creates a player and a track scheduler.
* @param manager Audio player manager to use for creating the player.
*/
public GuildMusicManager(AudioPlayerManager manager)
{
player = manager.createPlayer();
scheduler = new TrackScheduler(player);
player.addListener(scheduler);
}
/**
* @return Wrapper around AudioPlayer to use it as an AudioSendHandler.
*/
public AudioPlayerSendHandler getSendHandler() {
return new AudioPlayerSendHandler(player);
}
}
-62
View File
@@ -1,62 +0,0 @@
package utils.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;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* This class schedules tracks for the audio player. It contains the queue of tracks.
*/
public class TrackScheduler extends AudioEventAdapter {
private final AudioPlayer player;
private final BlockingQueue<AudioTrack> queue;
/**
* @param player The audio player this scheduler uses
*/
public TrackScheduler(AudioPlayer player)
{
this.player = player;
this.queue = new LinkedBlockingQueue<>();
}
/**
* Add the next track to queue or play right away if nothing is in the queue.
*
* @param track The track to play or add to queue.
*/
public void queue(AudioTrack track)
{
// Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If
// something is playing, it returns false and does nothing. In that case the player was already playing so this
// track goes to the queue instead.
if (!player.startTrack(track, true))
{
queue.offer(track);
}
}
/**
* Start the next track, stopping the current one if it is playing.
*/
public void nextTrack()
{
// Start the next track, regardless of if something is already playing or not. In case queue was empty, we are
// giving null to startTrack, which is a valid argument and will simply stop the player.
player.startTrack(queue.poll(), false);
}
@Override
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason)
{
// Only start the next track if the end reason is suitable for it (FINISHED or LOAD_FAILED)
if (endReason.mayStartNext)
{
nextTrack();
}
}
}