-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from CurseForgeCommunity/feat-discord
wip: Discord bot
- Loading branch information
Showing
16 changed files
with
416 additions
and
325 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
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,26 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="CurseForge.APIClient" Version="2.2.0" /> | ||
<PackageReference Include="Discord.Net" Version="3.13.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Update="appsettings.Dev.json"> | ||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
</None> | ||
<None Update="appsettings.json"> | ||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
</None> | ||
</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,39 @@ | ||
using Discord; | ||
using Discord.Interactions; | ||
|
||
namespace CFDiscordBot.Commands | ||
{ | ||
[DefaultMemberPermissions(GuildPermission.Administrator)] | ||
public class DebugCommands : InteractionModuleBase<ShardedInteractionContext> | ||
{ | ||
[SlashCommand("ping", "Returns the latency of the bot")] | ||
public async Task PingAsync() | ||
{ | ||
await RespondAsync($"Pong! {Context.Client.Latency}ms", ephemeral: true); | ||
await Task.Delay(2000); | ||
|
||
await Context.Interaction.DeleteOriginalResponseAsync(); | ||
} | ||
|
||
[SlashCommand("shardinfo", "Returns information about the shard")] | ||
public async Task ShardInfoAsync() | ||
{ | ||
var shardId = Context.Client.GetShardIdFor(Context.Guild); | ||
var shard = Context.Client.GetShard(shardId); | ||
|
||
var embed = new EmbedBuilder() | ||
.WithTitle("Shard Information") | ||
.WithDescription($""" | ||
Shard ID: {shardId} | ||
Guilds: {shard.Guilds.Count} | ||
Users: {shard.Guilds.Sum(x => x.MemberCount)} | ||
Channels: {shard.Guilds.Sum(x => x.Channels.Count)} | ||
Latency: {shard.Latency}ms | ||
""") | ||
.WithColor(Color.Blue) | ||
.Build(); | ||
|
||
await RespondAsync(embeds: new[] { embed }, ephemeral: true); | ||
} | ||
} | ||
} |
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,43 @@ | ||
using Discord; | ||
using Discord.Interactions; | ||
|
||
namespace CFDiscordBot.Commands | ||
{ | ||
public partial class Lookup | ||
{ | ||
[SlashCommand("game", "Looks up a game by its ID")] | ||
public async Task GameIdAsync( | ||
[Summary("id", "The ID of the game to look up")] | ||
int gameId | ||
) | ||
{ | ||
var game = await apiClient.GetGameAsync(gameId); | ||
|
||
if (game is null) | ||
{ | ||
await RespondAsync($"Game with id {gameId} was not found.", ephemeral: true); | ||
|
||
await Task.Delay(2000); | ||
await Context.Interaction.DeleteOriginalResponseAsync(); | ||
return; | ||
} | ||
|
||
var embed = new EmbedBuilder() | ||
.WithTitle(game.Data.Name) | ||
.WithUrl($"https://curseforge.com/{game.Data.Slug}") | ||
.WithColor(Color.Blue); | ||
|
||
if (!string.IsNullOrWhiteSpace(game.Data.Assets.IconUrl)) | ||
{ | ||
embed.WithThumbnailUrl(game.Data.Assets.IconUrl); | ||
} | ||
|
||
if (!string.IsNullOrWhiteSpace(game.Data.Assets.CoverUrl)) | ||
{ | ||
embed.WithImageUrl(game.Data.Assets.CoverUrl); | ||
} | ||
|
||
await RespondAsync(embeds: new[] { embed.Build() }, ephemeral: true); | ||
} | ||
} | ||
} |
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,8 @@ | ||
using CurseForge.APIClient; | ||
using Discord.Interactions; | ||
|
||
namespace CFDiscordBot.Commands | ||
{ | ||
[Group("lookup", "Does lookups against CurseForge")] | ||
public partial class Lookup(ApiClient apiClient) : InteractionModuleBase<ShardedInteractionContext> { } | ||
} |
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,35 @@ | ||
using Discord; | ||
using Discord.Interactions; | ||
|
||
namespace CFDiscordBot.Commands | ||
{ | ||
public partial class Lookup | ||
{ | ||
[SlashCommand("projectid", "Looks up a project by its ID")] | ||
public async Task ProjectIdAsync( | ||
[Summary("id", "The ID of the project to look up")] | ||
int projectId | ||
) | ||
{ | ||
var project = await apiClient.GetModAsync(projectId); | ||
|
||
if (project is null) | ||
{ | ||
await RespondAsync($"Project with id {projectId} was not found.", ephemeral: true); | ||
|
||
await Task.Delay(2000); | ||
await Context.Interaction.DeleteOriginalResponseAsync(); | ||
return; | ||
} | ||
|
||
var embed = new EmbedBuilder() | ||
.WithTitle(project.Data.Name) | ||
.WithUrl(project.Data.Links.WebsiteUrl) | ||
.WithDescription(project.Data.Summary) | ||
.WithColor(Color.Blue) | ||
.Build(); | ||
|
||
await RespondAsync(embeds: new[] { embed }, ephemeral: true); | ||
} | ||
} | ||
} |
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,83 @@ | ||
using CurseForge.APIClient; | ||
using Discord; | ||
using Discord.Interactions; | ||
using Discord.WebSocket; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using System.Reflection; | ||
|
||
namespace CFDiscordBot | ||
{ | ||
public partial class DiscordBot( | ||
ILogger logger, | ||
DiscordShardedClient discordClient, | ||
string botToken, | ||
ApiClient apiClient, | ||
IServiceProvider serviceProvider | ||
) : BackgroundService | ||
{ | ||
private InteractionService? interactionService; | ||
|
||
protected override async Task ExecuteAsync(CancellationToken stoppingToken) | ||
{ | ||
discordClient.ShardReady += DiscordClient_ShardReady; | ||
|
||
discordClient.Log += Log; | ||
|
||
await discordClient.LoginAsync(TokenType.Bot, botToken); | ||
await discordClient.StartAsync(); | ||
|
||
await Task.Delay(-1, stoppingToken); | ||
|
||
await discordClient.StopAsync(); | ||
await discordClient.LogoutAsync(); | ||
} | ||
|
||
private async Task DiscordClient_ShardReady(DiscordSocketClient _shardClient) | ||
{ | ||
discordClient.ShardReady -= DiscordClient_ShardReady; | ||
|
||
interactionService = new InteractionService(_shardClient); | ||
|
||
interactionService.Log += Log; | ||
|
||
logger.LogInformation("Registering slash commands"); | ||
await interactionService.AddModulesAsync(Assembly.GetEntryAssembly(), serviceProvider); | ||
await interactionService.RegisterCommandsGloballyAsync(true); | ||
|
||
discordClient.InteractionCreated += DiscordClient_InteractionCreated; ; | ||
|
||
logger.LogInformation("Slash commands registered"); | ||
} | ||
|
||
private async Task Log(LogMessage msg) | ||
{ | ||
switch (msg.Severity) | ||
{ | ||
case LogSeverity.Critical: | ||
case LogSeverity.Error: | ||
logger.LogError(msg.Exception, msg.Message); | ||
break; | ||
case LogSeverity.Warning: | ||
logger.LogWarning(msg.Exception, msg.Message); | ||
break; | ||
case LogSeverity.Info: | ||
logger.LogInformation(msg.Exception, msg.Message); | ||
break; | ||
case LogSeverity.Verbose: | ||
case LogSeverity.Debug: | ||
logger.LogDebug(msg.Exception, msg.Message); | ||
break; | ||
} | ||
await Task.CompletedTask; | ||
} | ||
|
||
private async Task DiscordClient_InteractionCreated(SocketInteraction interaction) | ||
{ | ||
logger.LogDebug("Interaction received: {Interaction}", interaction); | ||
var ctx = new ShardedInteractionContext(discordClient, interaction); | ||
await interactionService!.ExecuteCommandAsync(ctx, serviceProvider); | ||
logger.LogDebug("Interaction handled"); | ||
} | ||
} | ||
} |
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,37 @@ | ||
using CFDiscordBot; | ||
using CurseForge.APIClient; | ||
using Discord.WebSocket; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
var configuration = new ConfigurationBuilder() | ||
.SetBasePath(Directory.GetCurrentDirectory()) | ||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) | ||
.AddJsonFile("appsettings.Dev.json", optional: true, reloadOnChange: true) | ||
.AddEnvironmentVariables("CFLOOKUP_") | ||
.Build(); | ||
|
||
await Host.CreateDefaultBuilder(args) | ||
.ConfigureServices(services => | ||
{ | ||
services.AddLogging(services => services.AddConsole()); | ||
services.AddSingleton(x => new ApiClient(configuration["CurseForge:ApiKey"])); | ||
services.AddSingleton(x => new DiscordSocketConfig | ||
{ | ||
UseInteractionSnowflakeDate = false | ||
}); | ||
services.AddSingleton<DiscordShardedClient>(); | ||
services.AddHostedService(x => | ||
new DiscordBot( | ||
x.GetRequiredService<ILogger<DiscordBot>>(), | ||
x.GetRequiredService<DiscordShardedClient>(), | ||
configuration["Discord:BotToken"]!, | ||
x.GetRequiredService<ApiClient>(), | ||
x | ||
) | ||
); | ||
}) | ||
.Build() | ||
.RunAsync(); |
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 @@ | ||
{ | ||
"CurseForge": { | ||
"ApiKey": "..." | ||
}, | ||
"Discord": { | ||
"AppId": "...", | ||
"PublicKey": "...", | ||
"BotToken": "..." | ||
}, | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information" | ||
} | ||
} | ||
} |
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
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
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
Oops, something went wrong.