From 598262d9528a4f49d47dc31154e5c703bf9360e2 Mon Sep 17 00:00:00 2001 From: NycroV <83246959+NycroV@users.noreply.github.com> Date: Wed, 14 Aug 2024 06:54:37 -0400 Subject: [PATCH] Add DSharpPlus.Nightly sample bot --- ...k4NET.DSharpPlus.Nightly.ExampleBot.csproj | 21 +++ .../MusicCommands.cs | 121 ++++++++++++++++++ .../Program.cs | 54 ++++++++ src/Lavalink4NET.sln | 7 + 4 files changed, 203 insertions(+) create mode 100644 samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Lavalink4NET.DSharpPlus.Nightly.ExampleBot.csproj create mode 100644 samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/MusicCommands.cs create mode 100644 samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Program.cs diff --git a/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Lavalink4NET.DSharpPlus.Nightly.ExampleBot.csproj b/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Lavalink4NET.DSharpPlus.Nightly.ExampleBot.csproj new file mode 100644 index 00000000..6a339b33 --- /dev/null +++ b/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Lavalink4NET.DSharpPlus.Nightly.ExampleBot.csproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + diff --git a/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/MusicCommands.cs b/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/MusicCommands.cs new file mode 100644 index 00000000..ac31b92a --- /dev/null +++ b/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/MusicCommands.cs @@ -0,0 +1,121 @@ +namespace ExampleBot; + +using System; +using System.Threading.Tasks; +using DSharpPlus.Entities; +using DSharpPlus.Commands; +using Lavalink4NET; +using Lavalink4NET.Players; +using Lavalink4NET.Players.Queued; +using Lavalink4NET.Rest.Entities.Tracks; +using Microsoft.Extensions.Options; +using System.ComponentModel; +using DSharpPlus.Commands.ContextChecks; + +public class MusicCommands +{ + private readonly IAudioService _audioService; + + public MusicCommands(IAudioService audioService) + { + ArgumentNullException.ThrowIfNull(audioService); + _audioService = audioService; + } + + [Command("play")] + [Description("Plays music")] + [DirectMessageUsage(DirectMessageUsage.DenyDMs)] + public async Task Play(CommandContext context, + + [Parameter("query")] + [Description("Track to play")] + string query) + { + // This operation could take a while - deferring the interaction lets Discord know we've + // received it and lets us update it later. Users see a "thinking..." state. + await context.DeferResponseAsync().ConfigureAwait(false); + + // Attempt to get the player + var player = await GetPlayerAsync(context, connectToVoiceChannel: true).ConfigureAwait(false); + + // If something went wrong getting the player, don't attempt to play any tracks + if (player is null) + return; + + // Fetch the tracks + var track = await _audioService.Tracks + .LoadTrackAsync(query, TrackSearchMode.YouTube) + .ConfigureAwait(false); + + // If no results were found + if (track is null) + { + var errorResponse = new DiscordFollowupMessageBuilder() + .WithContent("😖 No results.") + .AsEphemeral(); + + await context + .EditResponseAsync(errorResponse) + .ConfigureAwait(false); + + return; + } + + // Play the track + var position = await player + .PlayAsync(track) + .ConfigureAwait(false); + + // If it was added to the queue + if (position is 0) + { + await context + .FollowupAsync(new DiscordFollowupMessageBuilder().WithContent($"🔈 Playing: {track.Uri}")) + .ConfigureAwait(false); + } + + // If it was played directly + else + { + await context + .FollowupAsync(new DiscordFollowupMessageBuilder().WithContent($"🔈 Added to queue: {track.Uri}")) + .ConfigureAwait(false); + } + } + + private async ValueTask GetPlayerAsync(CommandContext commandContext, bool connectToVoiceChannel = true) + { + ArgumentNullException.ThrowIfNull(commandContext); + + var retrieveOptions = new PlayerRetrieveOptions( + ChannelBehavior: connectToVoiceChannel ? PlayerChannelBehavior.Join : PlayerChannelBehavior.None); + + var playerOptions = new QueuedLavalinkPlayerOptions { HistoryCapacity = 10000 }; + + var result = await _audioService.Players + .RetrieveAsync(commandContext.Guild!.Id, commandContext.Member?.VoiceState?.Channel?.Id ?? null, 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 commandContext + .FollowupAsync(errorResponse) + .ConfigureAwait(false); + + return null; + } + + return result.Player; + } +} \ No newline at end of file diff --git a/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Program.cs b/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Program.cs new file mode 100644 index 00000000..42c6b8ec --- /dev/null +++ b/samples/Lavalink4NET.DSharpPlus.Nightly.ExampleBot/Program.cs @@ -0,0 +1,54 @@ +using DSharpPlus; +using DSharpPlus.Commands; +using DSharpPlus.Extensions; +using ExampleBot; +using Lavalink4NET.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +var builder = new HostApplicationBuilder(args); + +// Your host service +builder.Services.AddHostedService(); + + +// DSharpPlus +builder.Services.AddDiscordClient("Your token here", DiscordIntents.AllUnprivileged); +builder.Services.AddCommandsExtension(extension => extension.AddCommands(typeof(MusicCommands).Assembly)); + + +// Lavalink4NET +builder.Services.AddLavalink(); + + +// Logging +builder.Services.AddLogging(s => s.AddConsole().SetMinimumLevel(LogLevel.Debug)); + + +// Start the host +builder.Build().Run(); + + +file sealed class ApplicationHost : BackgroundService +{ + private readonly DiscordClient _discordClient; + + public ApplicationHost(DiscordClient discordClient) + { + ArgumentNullException.ThrowIfNull(discordClient); + _discordClient = discordClient; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + // Connect to discord gateway and initialize node connection + await _discordClient + .ConnectAsync() + .ConfigureAwait(false); + + await Task + .Delay(-1, stoppingToken) + .ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/src/Lavalink4NET.sln b/src/Lavalink4NET.sln index 035963e4..191bea52 100644 --- a/src/Lavalink4NET.sln +++ b/src/Lavalink4NET.sln @@ -98,6 +98,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lavalink4NET.Integrations.L EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lavalink4NET.DSharpPlus.Nightly", "Lavalink4NET.DSharpPlus.Nightly\Lavalink4NET.DSharpPlus.Nightly.csproj", "{1A30629A-399B-4293-B5F4-B3909C1772D0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lavalink4NET.DSharpPlus.Nightly.ExampleBot", "..\samples\Lavalink4NET.DSharpPlus.Nightly.ExampleBot\Lavalink4NET.DSharpPlus.Nightly.ExampleBot.csproj", "{E4390813-D7C6-4FF8-BF3E-B4504696CAF6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -264,6 +266,10 @@ Global {1A30629A-399B-4293-B5F4-B3909C1772D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {1A30629A-399B-4293-B5F4-B3909C1772D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {1A30629A-399B-4293-B5F4-B3909C1772D0}.Release|Any CPU.Build.0 = Release|Any CPU + {E4390813-D7C6-4FF8-BF3E-B4504696CAF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4390813-D7C6-4FF8-BF3E-B4504696CAF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4390813-D7C6-4FF8-BF3E-B4504696CAF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4390813-D7C6-4FF8-BF3E-B4504696CAF6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -293,6 +299,7 @@ Global {9A30E985-6D67-41D4-A12F-F1ADCD2ED0FE} = {48ECDC71-B9E3-4086-8194-DA81B4667CA6} {176B0345-DF57-42B4-A8FD-4E6436D9554C} = {48ECDC71-B9E3-4086-8194-DA81B4667CA6} {1A30629A-399B-4293-B5F4-B3909C1772D0} = {5FAEC63E-9752-48C4-8BC9-B101E0DBDBD3} + {E4390813-D7C6-4FF8-BF3E-B4504696CAF6} = {B9402D29-5B12-4672-97B8-570A60C0F878} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {466A619D-5C4B-4A8F-9852-7A5322F160A2}