Skip to content

Commit

Permalink
feat: Implement commands in DSharpPlus sample
Browse files Browse the repository at this point in the history
  • Loading branch information
angelobreuer committed Mar 10, 2024
1 parent 175414c commit f03a45b
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>ExampleBot</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="Emzi0767.Common" Version="2.6.2"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DSharpPlus.SlashCommands" Version="4.4.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="Emzi0767.Common" Version="2.6.2" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Lavalink4NET.DSharpPlus\Lavalink4NET.DSharpPlus.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Lavalink4NET.DSharpPlus\Lavalink4NET.DSharpPlus.csproj" />
</ItemGroup>
</Project>
106 changes: 106 additions & 0 deletions samples/Lavalink4NET.DSharpPlus.ExampleBot/MusicCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
namespace ExampleBot;

using System;
using System.Threading.Tasks;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using Lavalink4NET;
using Lavalink4NET.Players;
using Lavalink4NET.Players.Queued;
using Lavalink4NET.Rest.Entities.Tracks;
using Microsoft.Extensions.Options;

public class MusicCommands : ApplicationCommandModule
{
private readonly IAudioService _audioService;

public MusicCommands(IAudioService audioService)
{
ArgumentNullException.ThrowIfNull(audioService);

_audioService = audioService;
}

[SlashCommand("play", description: "Plays music")]
public async Task Play(InteractionContext interactionContext, [Option("query", "Track to play")] string query)
{
await interactionContext.DeferAsync().ConfigureAwait(false);

var player = await GetPlayerAsync(interactionContext, connectToVoiceChannel: true).ConfigureAwait(false);

if (player is null)
{
return;
}

var track = await _audioService.Tracks
.LoadTrackAsync(query, TrackSearchMode.YouTube)
.ConfigureAwait(false);

if (track is null)
{
var errorResponse = new DiscordFollowupMessageBuilder()
.WithContent("😖 No results.")
.AsEphemeral();

await interactionContext
.FollowUpAsync(errorResponse)
.ConfigureAwait(false);

return;
}

var position = await player
.PlayAsync(track)
.ConfigureAwait(false);

if (position is 0)
{
await interactionContext
.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent($"🔈 Playing: {track.Uri}"))
.ConfigureAwait(false);
}
else
{
await interactionContext
.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent($"🔈 Added to queue: {track.Uri}"))
.ConfigureAwait(false);
}
}

private async ValueTask<QueuedLavalinkPlayer?> GetPlayerAsync(InteractionContext interactionContext, bool connectToVoiceChannel = true)
{
ArgumentNullException.ThrowIfNull(interactionContext);

var retrieveOptions = new PlayerRetrieveOptions(
ChannelBehavior: connectToVoiceChannel ? PlayerChannelBehavior.Join : PlayerChannelBehavior.None);

var playerOptions = new QueuedLavalinkPlayerOptions { HistoryCapacity = 10000 };

var result = await _audioService.Players
.RetrieveAsync(interactionContext.Guild.Id, interactionContext.Member?.VoiceState.Channel.Id, playerFactory: PlayerFactory.Queued, Options.Create(playerOptions), retrieveOptions)
.ConfigureAwait(false);

if (!result.IsSuccess)
{
var errorMessage = result.Status switch
{
PlayerRetrieveStatus.UserNotInVoiceChannel => "You are not connected to a voice channel.",
PlayerRetrieveStatus.BotNotConnected => "The bot is currently not connected.",
_ => "Unknown error.",
};

var errorResponse = new DiscordFollowupMessageBuilder()
.WithContent(errorMessage)
.AsEphemeral();

await interactionContext
.FollowUpAsync(errorResponse)
.ConfigureAwait(false);

return null;
}

return result.Player;
}
}
38 changes: 22 additions & 16 deletions samples/Lavalink4NET.DSharpPlus.ExampleBot/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using System.Threading;
using System.Threading.Tasks;
using DSharpPlus;
using Lavalink4NET;
using DSharpPlus.EventArgs;
using DSharpPlus.SlashCommands;
using ExampleBot;
using Lavalink4NET.Extensions;
using Lavalink4NET.Players;
using Lavalink4NET.Players.Queued;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
Expand All @@ -17,7 +17,6 @@
builder.Services.AddSingleton<DiscordClient>();
builder.Services.AddSingleton(new DiscordConfiguration { Token = "", }); // Put token here

// Lavalink
builder.Services.AddLavalink();

// Logging
Expand All @@ -27,36 +26,43 @@

file sealed class ApplicationHost : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly DiscordClient _discordClient;
private readonly IAudioService _audioService;

public ApplicationHost(DiscordClient discordClient, IAudioService audioService)
public ApplicationHost(IServiceProvider serviceProvider, DiscordClient discordClient)
{
ArgumentNullException.ThrowIfNull(serviceProvider);
ArgumentNullException.ThrowIfNull(discordClient);
ArgumentNullException.ThrowIfNull(audioService);

_serviceProvider = serviceProvider;
_discordClient = discordClient;
_audioService = audioService;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_discordClient
.UseSlashCommands(new SlashCommandsConfiguration { Services = _serviceProvider })
.RegisterCommands<MusicCommands>(0); // Add guild id here

// connect to discord gateway and initialize node connection
await _discordClient
.ConnectAsync()
.ConfigureAwait(false);

await _audioService
.WaitForReadyAsync(stoppingToken)
.ConfigureAwait(false);
var readyTaskCompletionSource = new TaskCompletionSource();

var playerOptions = new LavalinkPlayerOptions
Task SetResult(DiscordClient client, ReadyEventArgs eventArgs)
{
InitialTrack = new TrackQueueItem("https://www.youtube.com/watch?v=dQw4w9WgXcQ"),
};
readyTaskCompletionSource.TrySetResult();
return Task.CompletedTask;
}

_discordClient.Ready += SetResult;
await readyTaskCompletionSource.Task.ConfigureAwait(false);
_discordClient.Ready -= SetResult;

await _audioService.Players
.JoinAsync(0, 0, playerOptions, stoppingToken) // Ids
await Task
.Delay(Timeout.InfiniteTimeSpan, stoppingToken)
.ConfigureAwait(false);
}
}

0 comments on commit f03a45b

Please sign in to comment.