-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0659f7c
commit 1dee038
Showing
80 changed files
with
2,063 additions
and
669 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
namespace Lavalink4NET.DiscordNet.ExampleBot; | ||
|
||
using System; | ||
using System.Reflection; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Discord; | ||
using Discord.Interactions; | ||
using Discord.WebSocket; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
internal sealed class DiscordClientHost : IHostedService | ||
{ | ||
private readonly DiscordSocketClient _discordSocketClient; | ||
private readonly InteractionService _interactionService; | ||
private readonly IServiceProvider _serviceProvider; | ||
|
||
public DiscordClientHost( | ||
DiscordSocketClient discordSocketClient, | ||
InteractionService interactionService, | ||
IServiceProvider serviceProvider) | ||
{ | ||
ArgumentNullException.ThrowIfNull(discordSocketClient); | ||
ArgumentNullException.ThrowIfNull(interactionService); | ||
ArgumentNullException.ThrowIfNull(serviceProvider); | ||
|
||
_discordSocketClient = discordSocketClient; | ||
_interactionService = interactionService; | ||
_serviceProvider = serviceProvider; | ||
} | ||
|
||
public async Task StartAsync(CancellationToken cancellationToken) | ||
{ | ||
_discordSocketClient.InteractionCreated += InteractionCreated; | ||
_discordSocketClient.Ready += ClientReady; | ||
|
||
// Put bot token here | ||
await _discordSocketClient | ||
.LoginAsync(TokenType.Bot, "") | ||
.ConfigureAwait(false); | ||
|
||
await _discordSocketClient | ||
.StartAsync() | ||
.ConfigureAwait(false); | ||
} | ||
|
||
public async Task StopAsync(CancellationToken cancellationToken) | ||
{ | ||
_discordSocketClient.InteractionCreated -= InteractionCreated; | ||
_discordSocketClient.Ready -= ClientReady; | ||
|
||
await _discordSocketClient | ||
.StopAsync() | ||
.ConfigureAwait(false); | ||
} | ||
|
||
private Task InteractionCreated(SocketInteraction interaction) | ||
{ | ||
var interactionContext = new SocketInteractionContext(_discordSocketClient, interaction); | ||
return _interactionService!.ExecuteCommandAsync(interactionContext, _serviceProvider); | ||
} | ||
|
||
private async Task ClientReady() | ||
{ | ||
await _interactionService | ||
.AddModulesAsync(Assembly.GetExecutingAssembly(), _serviceProvider) | ||
.ConfigureAwait(false); | ||
|
||
// Put your guild id to test here | ||
await _interactionService | ||
.RegisterCommandsToGuildAsync(0) | ||
.ConfigureAwait(false); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
samples/Lavalink4NET.Samples.Cluster/Lavalink4NET.Samples.Cluster.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Discord.Net.Interactions" Version="3.10.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> | ||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> | ||
|
||
<ProjectReference Include="..\..\src\Lavalink4NET.Cluster\Lavalink4NET.Cluster.csproj" /> | ||
<ProjectReference Include="..\..\src\Lavalink4NET.DiscordNet\Lavalink4NET.DiscordNet.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
namespace Lavalink4NET.Discord_NET.ExampleBot; | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using Discord.Interactions; | ||
using Lavalink4NET.Clients; | ||
using Lavalink4NET.DiscordNet; | ||
using Lavalink4NET.Players; | ||
using Lavalink4NET.Players.Queued; | ||
using Lavalink4NET.Rest.Entities.Tracks; | ||
|
||
/// <summary> | ||
/// Presents some of the main features of the Lavalink4NET-Library. | ||
/// </summary> | ||
[RequireContext(ContextType.Guild)] | ||
public sealed class MusicModule : InteractionModuleBase<SocketInteractionContext> | ||
{ | ||
private readonly IAudioService _audioService; | ||
|
||
public MusicModule(IAudioService audioService) | ||
{ | ||
ArgumentNullException.ThrowIfNull(audioService); | ||
|
||
_audioService = audioService; | ||
} | ||
|
||
[SlashCommand("play", description: "Plays music", runMode: RunMode.Async)] | ||
public async Task Play(string query) | ||
{ | ||
await DeferAsync().ConfigureAwait(false); | ||
|
||
var player = await GetPlayerAsync(connectToVoiceChannel: true).ConfigureAwait(false); | ||
|
||
if (player is null) | ||
{ | ||
return; | ||
} | ||
|
||
var track = await _audioService.Tracks | ||
.LoadTrackAsync(query, TrackSearchMode.YouTube) | ||
.ConfigureAwait(false); | ||
|
||
if (track is null) | ||
{ | ||
await FollowupAsync("😖 No results.").ConfigureAwait(false); | ||
return; | ||
} | ||
|
||
var position = await player.PlayAsync(track).ConfigureAwait(false); | ||
|
||
if (position is 0) | ||
{ | ||
await FollowupAsync($"🔈 Playing: {track.Uri}").ConfigureAwait(false); | ||
} | ||
else | ||
{ | ||
await FollowupAsync($"🔈 Added to queue: {track.Uri}").ConfigureAwait(false); | ||
} | ||
} | ||
|
||
private async ValueTask<QueuedLavalinkPlayer?> GetPlayerAsync(bool connectToVoiceChannel = true) | ||
{ | ||
var joinOptions = new PlayerJoinOptions(ConnectToVoiceChannel: connectToVoiceChannel); | ||
|
||
var result = await _audioService.Players | ||
.GetOrJoinAsync(Context, playerFactory: PlayerFactory.Queued, joinOptions) | ||
.ConfigureAwait(false); | ||
|
||
if (!result.IsSuccess) | ||
{ | ||
var errorMessage = result.Status switch | ||
{ | ||
PlayerJoinStatus.UserNotInVoiceChannel => "You are not connected to a voice channel.", | ||
PlayerJoinStatus.BotNotConnected => "The bot is currently not connected.", | ||
_ => "Unknown error.", | ||
}; | ||
|
||
await FollowupAsync(errorMessage).ConfigureAwait(false); | ||
return null; | ||
} | ||
|
||
return result.Player; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using System.Collections.Immutable; | ||
using Discord.Interactions; | ||
using Discord.WebSocket; | ||
using Lavalink4NET.Cluster.Extensions; | ||
using Lavalink4NET.Cluster.Nodes; | ||
using Lavalink4NET.DiscordNet; | ||
using Lavalink4NET.DiscordNet.ExampleBot; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
var builder = new HostApplicationBuilder(args); | ||
|
||
// Discord | ||
builder.Services.AddSingleton<DiscordSocketClient>(); | ||
builder.Services.AddSingleton<InteractionService>(); | ||
builder.Services.AddHostedService<DiscordClientHost>(); | ||
|
||
// Lavalink | ||
builder.Services.AddLavalinkCluster<DiscordClientWrapper>(); | ||
builder.Services.AddLogging(x => x.AddConsole().SetMinimumLevel(LogLevel.Trace)); | ||
|
||
builder.Services.ConfigureLavalinkCluster(x => | ||
{ | ||
x.Nodes = ImmutableArray.Create( | ||
new LavalinkClusterNodeOptions { BaseAddress = new Uri("http://localhost:2333/"), }, | ||
new LavalinkClusterNodeOptions { BaseAddress = new Uri("http://localhost:2334/"), }, | ||
new LavalinkClusterNodeOptions { BaseAddress = new Uri("http://localhost:2335/"), }); | ||
}); | ||
|
||
builder.Build().Run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
namespace Lavalink4NET.Cluster; | ||
|
||
using System.Collections.Immutable; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Lavalink4NET.Clients; | ||
using Lavalink4NET.Cluster.Nodes; | ||
using Lavalink4NET.Cluster.Rest; | ||
using Lavalink4NET.Integrations; | ||
using Lavalink4NET.Players; | ||
using Lavalink4NET.Rest; | ||
using Lavalink4NET.Socket; | ||
using Lavalink4NET.Tracks; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
internal sealed class ClusterAudioService : AudioServiceBase, IClusterAudioService | ||
{ | ||
private readonly object _syncRoot; | ||
private readonly ClusterAudioServiceOptions _options; | ||
private readonly LavalinkNodeServiceContext _serviceContext; | ||
private readonly CancellationTokenSource _shutdownCancellationTokenSource; | ||
private readonly CancellationToken _shutdownCancellationToken; | ||
private readonly ILavalinkApiClientFactory _lavalinkApiClientFactory; | ||
private readonly ILoggerFactory _loggerFactory; | ||
|
||
public ClusterAudioService( | ||
IDiscordClientWrapper discordClient, | ||
ILavalinkSocketFactory socketFactory, | ||
ILavalinkApiClientProvider lavalinkApiClientProvider, | ||
ILavalinkApiClientFactory lavalinkApiClientFactory, | ||
IIntegrationManager integrations, | ||
IPlayerManager players, | ||
ITrackManager tracks, | ||
IOptions<ClusterAudioServiceOptions> options, | ||
ILoggerFactory loggerFactory) | ||
: base(lavalinkApiClientProvider, integrations, players, tracks) | ||
{ | ||
ArgumentNullException.ThrowIfNull(options); | ||
ArgumentNullException.ThrowIfNull(discordClient); | ||
ArgumentNullException.ThrowIfNull(loggerFactory); | ||
|
||
_syncRoot = new object(); | ||
_options = options.Value; | ||
|
||
_serviceContext = new LavalinkNodeServiceContext( | ||
ClientWrapper: discordClient, | ||
LavalinkSocketFactory: socketFactory, | ||
IntegrationManager: Integrations, | ||
PlayerManager: Players, | ||
NodeListener: this); | ||
|
||
Nodes = ImmutableArray<ILavalinkNode>.Empty; | ||
_lavalinkApiClientFactory = lavalinkApiClientFactory; | ||
_loggerFactory = loggerFactory; | ||
|
||
_shutdownCancellationTokenSource = new CancellationTokenSource(); | ||
_shutdownCancellationToken = _shutdownCancellationTokenSource.Token; | ||
} | ||
|
||
public ImmutableArray<ILavalinkNode> Nodes { get; private set; } | ||
|
||
public ValueTask<ILavalinkNode> AddAsync(IOptions<LavalinkClusterNodeOptions> options, CancellationToken cancellationToken = default) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
ArgumentNullException.ThrowIfNull(options); | ||
|
||
var nodeLogger = _loggerFactory.CreateLogger<LavalinkNode>(); | ||
var apiClient = _lavalinkApiClientFactory.Create(options); | ||
|
||
var node = new LavalinkClusterNode( | ||
cluster: this, | ||
apiClient: apiClient, | ||
serviceContext: _serviceContext, | ||
options: options, | ||
shutdownCancellationToken: _shutdownCancellationToken, | ||
logger: nodeLogger); | ||
|
||
lock (_syncRoot) | ||
{ | ||
Nodes = Nodes.Add(node); | ||
} | ||
|
||
return ValueTask.FromResult<ILavalinkNode>(node); | ||
} | ||
|
||
public async ValueTask<bool> RemoveAsync(ILavalinkNode node, CancellationToken cancellationToken = default) | ||
{ | ||
ArgumentNullException.ThrowIfNull(node); | ||
|
||
lock (_syncRoot) | ||
{ | ||
var previousNodes = Nodes; | ||
Nodes = previousNodes.Remove(node); | ||
|
||
if (previousNodes == Nodes) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
await node | ||
.StopAsync(cancellationToken) | ||
.ConfigureAwait(false); | ||
|
||
return true; | ||
} | ||
|
||
public override void Dispose() | ||
{ | ||
_shutdownCancellationTokenSource.Dispose(); | ||
} | ||
|
||
public override async ValueTask StartAsync(CancellationToken cancellationToken = default) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
foreach (var nodeOptions in _options.Nodes) | ||
{ | ||
await AddAsync(Options.Create(nodeOptions), cancellationToken).ConfigureAwait(false); | ||
} | ||
} | ||
|
||
public override async ValueTask StopAsync(CancellationToken cancellationToken = default) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
_shutdownCancellationTokenSource.Cancel(); | ||
|
||
var nodes = Nodes; | ||
|
||
foreach (var node in nodes) | ||
{ | ||
await RemoveAsync(node, cancellationToken).ConfigureAwait(false); | ||
} | ||
} | ||
|
||
public override ValueTask WaitForReadyAsync(CancellationToken cancellationToken = default) | ||
{ | ||
throw new NotImplementedException(); // TODO | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace Lavalink4NET.Cluster; | ||
|
||
using System; | ||
using System.Collections.Immutable; | ||
using Lavalink4NET.Cluster.Nodes; | ||
using Microsoft.Extensions.Options; | ||
|
||
public sealed record class ClusterAudioServiceOptions | ||
{ | ||
public string HttpClientName { get; set; } = Options.DefaultName; | ||
|
||
public TimeSpan ReadyTimeout { get; set; } = TimeSpan.FromSeconds(10); | ||
|
||
public ImmutableArray<LavalinkClusterNodeOptions> Nodes { get; set; } = ImmutableArray.Create(new LavalinkClusterNodeOptions()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Lavalink4NET.Cluster; | ||
|
||
public sealed record class ClusterNodeOptions | ||
{ | ||
public string Passphrase { get; set; } = "youshallnotpass"; | ||
|
||
public Uri? WebSocketUri { get; set; } | ||
|
||
|
||
} |
Oops, something went wrong.