mirror of
https://github.com/Myxelium/Lunaris2.0.git
synced 2026-04-11 15:19:53 +00:00
Add Join and Play handlers, Expand Command Builder functionality
This commit is contained in:
61
Bot/Handler/MusicPlayer/Extensions.cs
Normal file
61
Bot/Handler/MusicPlayer/Extensions.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Victoria.Node;
|
||||
|
||||
namespace Lunaris2.Handler.MusicPlayer
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static SocketGuild GetGuild(this SocketSlashCommand message, DiscordSocketClient client)
|
||||
{
|
||||
if (message.GuildId == null)
|
||||
{
|
||||
throw new Exception("Guild ID is null!");
|
||||
}
|
||||
|
||||
return client.GetGuild(message.GuildId.Value);
|
||||
}
|
||||
|
||||
public static IVoiceState GetVoiceState(this SocketSlashCommand message)
|
||||
{
|
||||
var voiceState = message.User as IVoiceState;
|
||||
|
||||
if (voiceState?.VoiceChannel == null)
|
||||
{
|
||||
throw new Exception("You must be connected to a voice channel!");
|
||||
}
|
||||
|
||||
return voiceState;
|
||||
}
|
||||
|
||||
public static async Task RespondAsync(this SocketSlashCommand message, string content)
|
||||
{
|
||||
await message.RespondAsync(content, ephemeral: true);
|
||||
}
|
||||
|
||||
public static async Task EnsureConnected(this LavaNode lavaNode)
|
||||
{
|
||||
if(!lavaNode.IsConnected)
|
||||
await lavaNode.ConnectAsync();
|
||||
}
|
||||
|
||||
public static async Task JoinVoiceChannel(this SocketSlashCommand context, LavaNode lavaNode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var textChannel = context.Channel as ITextChannel;
|
||||
await lavaNode.JoinAsync(context.GetVoiceState().VoiceChannel, textChannel);
|
||||
await context.RespondAsync($"Joined {context.GetVoiceState().VoiceChannel.Name}!");
|
||||
}
|
||||
catch (Exception exception) {
|
||||
Console.WriteLine(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOptionValueByName(this SocketSlashCommand command, string optionName)
|
||||
{
|
||||
return command.Data.Options.FirstOrDefault(option => option.Name == optionName)?.Value.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Bot/Handler/MusicPlayer/JoinCommand/JoinHandler.cs
Normal file
34
Bot/Handler/MusicPlayer/JoinCommand/JoinHandler.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using MediatR;
|
||||
using Victoria.Node;
|
||||
|
||||
namespace Lunaris2.Handler.MusicPlayer.JoinCommand;
|
||||
|
||||
public record JoinCommand(SocketSlashCommand Message) : IRequest;
|
||||
|
||||
public class JoinHandler : IRequestHandler<JoinCommand>
|
||||
{
|
||||
private readonly LavaNode _lavaNode;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public JoinHandler(LavaNode lavaNode, DiscordSocketClient client)
|
||||
{
|
||||
_lavaNode = lavaNode;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task Handle(JoinCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var context = command.Message;
|
||||
|
||||
await _lavaNode.EnsureConnected();
|
||||
|
||||
if (_lavaNode.HasPlayer(context.GetGuild(_client))) {
|
||||
await context.RespondAsync("I'm already connected to a voice channel!");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.JoinVoiceChannel(_lavaNode);
|
||||
}
|
||||
}
|
||||
110
Bot/Handler/MusicPlayer/PlayCommand/PlayHandler.cs
Normal file
110
Bot/Handler/MusicPlayer/PlayCommand/PlayHandler.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Lunaris2.SlashCommand;
|
||||
using MediatR;
|
||||
using Victoria.Node;
|
||||
using Victoria.Node.EventArgs;
|
||||
using Victoria.Player;
|
||||
using Victoria.Responses.Search;
|
||||
|
||||
namespace Lunaris2.Handler.MusicPlayer.PlayCommand;
|
||||
|
||||
public record PlayCommand(SocketSlashCommand Message) : IRequest;
|
||||
|
||||
public class PlayHandler : IRequestHandler<PlayCommand>
|
||||
{
|
||||
private readonly LavaNode _lavaNode;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public PlayHandler(LavaNode lavaNode, DiscordSocketClient client)
|
||||
{
|
||||
_lavaNode = lavaNode;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task Handle(PlayCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var context = command.Message;
|
||||
|
||||
await _lavaNode.EnsureConnected();
|
||||
|
||||
var songName = context.GetOptionValueByName(Option.Input);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(songName)) {
|
||||
await context.RespondAsync("Please provide search terms.");
|
||||
return;
|
||||
}
|
||||
|
||||
var player = await GetPlayer(context);
|
||||
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
var searchResponse = await _lavaNode.SearchAsync(
|
||||
Uri.IsWellFormedUriString(songName, UriKind.Absolute)
|
||||
? SearchType.Direct
|
||||
: SearchType.YouTube, songName);
|
||||
|
||||
if (!await HandleSearchResponse(searchResponse, player, context, songName))
|
||||
return;
|
||||
|
||||
await PlayTrack(player);
|
||||
|
||||
_lavaNode.OnTrackEnd += OnTrackEnd;
|
||||
}
|
||||
|
||||
private async Task OnTrackEnd(TrackEndEventArg<LavaPlayer<LavaTrack>, LavaTrack> arg)
|
||||
{
|
||||
var player = arg.Player;
|
||||
if (!player.Vueue.TryDequeue(out var nextTrack))
|
||||
{
|
||||
await player.TextChannel.SendMessageAsync("Queue completed!");
|
||||
return;
|
||||
}
|
||||
|
||||
await player.PlayAsync(nextTrack);
|
||||
}
|
||||
|
||||
private async Task PlayTrack(LavaPlayer<LavaTrack> player)
|
||||
{
|
||||
if (player.PlayerState is PlayerState.Playing or PlayerState.Paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.Vueue.TryDequeue(out var lavaTrack);
|
||||
await player.PlayAsync(lavaTrack);
|
||||
}
|
||||
|
||||
private async Task<LavaPlayer<LavaTrack>?> GetPlayer(SocketSlashCommand context)
|
||||
{
|
||||
var voiceState = context.User as IVoiceState;
|
||||
|
||||
if (voiceState?.VoiceChannel != null)
|
||||
return await _lavaNode.JoinAsync(voiceState.VoiceChannel, context.Channel as ITextChannel);
|
||||
|
||||
await context.RespondAsync("You must be connected to a voice channel!");
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<bool> HandleSearchResponse(SearchResponse searchResponse, LavaPlayer<LavaTrack> player, SocketSlashCommand context, string songName)
|
||||
{
|
||||
if (searchResponse.Status is SearchStatus.LoadFailed or SearchStatus.NoMatches) {
|
||||
await context.RespondAsync($"I wasn't able to find anything for `{songName}`.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchResponse.Playlist.Name)) {
|
||||
player.Vueue.Enqueue(searchResponse.Tracks);
|
||||
|
||||
await context.RespondAsync($"Enqueued {searchResponse.Tracks.Count} songs.");
|
||||
}
|
||||
else {
|
||||
var track = searchResponse.Tracks.FirstOrDefault()!;
|
||||
player.Vueue.Enqueue(track);
|
||||
|
||||
await context.RespondAsync($"Enqueued {track?.Title}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user