From db7d734aa902a15ec2e6ab08482f2b5d5f09af4b Mon Sep 17 00:00:00 2001 From: PoisnFang Date: Mon, 5 Jun 2023 23:32:23 -0700 Subject: [PATCH] Updated with slash commands --- Commands/SlashCommands.cs | 277 ++++++++++++++++++++++++++++++++++++++ PoisnCopy.csproj | 1 + Program.cs | 24 ++-- 3 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 Commands/SlashCommands.cs diff --git a/Commands/SlashCommands.cs b/Commands/SlashCommands.cs new file mode 100644 index 0000000..435990e --- /dev/null +++ b/Commands/SlashCommands.cs @@ -0,0 +1,277 @@ +using CsvHelper; +using DSharpPlus; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; +using System.Globalization; +using System.Threading.Channels; +using static DSharpPlus.Entities.DiscordEmbedBuilder; + +namespace PoisnCopy; + +public class SlashCommands : ApplicationCommandModule +{ + [SlashCommand("copychannel", "Copy a channel")] + public async Task CopyChannel(InteractionContext ctx) + { + try + { + await ctx.DeferAsync(); + + var textChannels = ctx.Guild.Channels + .Where(i => i.Value.Type == ChannelType.Text) + .ToList(); + List messages = new() { "Here is your list of channels:" }; + + foreach (var txtChan in textChannels) + { + messages.Add($"`{txtChan.Value.Id}-{txtChan.Value.Name}`"); + } + + messages.Add("**--Thats all of the channels!--**"); + messages.Add( + $"Copy command: `/loadchannel` server_id:`{ctx.Guild.Id}` channel_id:`###`" + ); + messages.Add( + $"Export command: `/exportchannel` server_id:`{ctx.Guild.Id}` channel_id:`###`" + ); + await ctx.EditResponseAsync( + new DiscordWebhookBuilder().WithContent(string.Join("\n", messages)) + ); + } + catch (Exception e) + { + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent(e.Message)); + return; + } + } + + [SlashCommand("loadchannel", "Load a copied channel")] + public async Task LoadChannel( + InteractionContext ctx, + [Option("server_id", "Originating Server ID")] string server_id, + [Option("channel_id", "Channel ID")] string channel_id, + [Option("new_channel_name", "The name of the new channel to create")] + string new_channel_name + ) + { + try + { + var chanParsed = ulong.TryParse(channel_id, out ulong chan_id); + + if (!chanParsed) + { + await ctx.CreateResponseAsync("Invalid Channel ID"); + + return; + } + + var serverParsed = ulong.TryParse(server_id, out ulong serv_id); + + if (!serverParsed) + { + await ctx.CreateResponseAsync("Invalid Server ID"); + + return; + } + + var guild = await ctx.Client.GetGuildAsync(serv_id); + var selectedChannel = guild.GetChannel(chan_id); + + await ctx.CreateResponseAsync("Collecting messages..."); + + await ctx.Channel.TriggerTypingAsync(); + var messag = await selectedChannel.GetMessagesAsync(); + + var messCopy = messag.ToList(); + var more = await selectedChannel.GetMessagesAsync(100); + + while (more.Count > 0) + { + messCopy.AddRange(more); + await Task.Delay(800); + more = await selectedChannel.GetMessagesBeforeAsync(more.LastOrDefault().Id, 100); + } + + await ctx.EditResponseAsync( + new DiscordWebhookBuilder().WithContent("Organizing messages...") + ); + + messCopy.Reverse(); + + await ctx.EditResponseAsync( + new DiscordWebhookBuilder().WithContent("Creating channel...") + ); + + var newChan = await ctx.Guild.CreateChannelAsync( + new_channel_name, + selectedChannel.Type + ); + + await ctx.EditResponseAsync( + new DiscordWebhookBuilder().WithContent( + $"Posting {messCopy.Count} messages... (this could take awhile)" + ) + ); + + foreach (var mes in messCopy) + { + if (!string.IsNullOrEmpty(mes.Content)) + { + var whAu = new EmbedAuthor + { + Name = mes.Author.Username, + IconUrl = mes.Author.AvatarUrl + }; + var what = new DiscordEmbedBuilder + { + Description = mes.Content, + Author = whAu, + Timestamp = mes.Timestamp + }; + + await newChan.SendMessageAsync(what); + await Task.Delay(800); + } + + if (mes.Attachments.Count > 0) + { + foreach (var att in mes.Attachments) + { + var whAu = new EmbedAuthor + { + Name = mes.Author.Username, + IconUrl = mes.Author.AvatarUrl + }; + var what = new DiscordEmbedBuilder + { + ImageUrl = att.Url, + Author = whAu, + Timestamp = mes.Timestamp + }; + + await newChan.SendMessageAsync(what); + await Task.Delay(800); + } + } + } + + await ctx.FollowUpAsync( + new DiscordFollowupMessageBuilder().WithContent($"{newChan.Name} copy complete!") + ); + } + catch (Exception e) + { + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent(e.Message)); + return; + } + } + + [SlashCommand("exportchannel", "Export a copied channel")] + public async Task ExportChannel( + InteractionContext ctx, + [Option("server_id", "Originating Server ID")] string server_id, + [Option("channel_id", "Channel ID")] string channel_id + ) + { + try + { + var chanParsed = ulong.TryParse(channel_id, out ulong chan_id); + + if (!chanParsed) + { + await ctx.CreateResponseAsync("Invalid Channel ID"); + + return; + } + + var serverParsed = ulong.TryParse(server_id, out ulong serv_id); + + if (!serverParsed) + { + await ctx.CreateResponseAsync("Invalid Server ID"); + + return; + } + + var guild = await ctx.Client.GetGuildAsync(serv_id); + var selectedChannel = guild.GetChannel(chan_id); + + await ctx.CreateResponseAsync("Collecting messages..."); + + await ctx.Channel.TriggerTypingAsync(); + var messag = await selectedChannel.GetMessagesAsync(); + + var messCopy = messag.ToList(); + var more = await selectedChannel.GetMessagesAsync(100); + + while (more.Count > 0) + { + messCopy.AddRange(more); + await Task.Delay(800); + more = await selectedChannel.GetMessagesBeforeAsync(more.LastOrDefault().Id, 100); + } + + await ctx.EditResponseAsync( + new DiscordWebhookBuilder().WithContent("Organizing messages...") + ); + + messCopy.Reverse(); + var messageExports = new List(); + + await ctx.EditResponseAsync( + new DiscordWebhookBuilder().WithContent( + $"Exporting {messCopy.Count} messages... (this could take awhile)" + ) + ); + + foreach (var mes in messCopy) + { + if (!string.IsNullOrEmpty(mes.Content)) + { + var textMessage = new MessageExport + { + AuthorName = mes.Author.Username, + IconUrl = mes.Author.AvatarUrl, + MessageConent = mes.Content, + Timestamp = mes.Timestamp.ToString("o") + }; + messageExports.Add(textMessage); + } + + if (mes.Attachments.Count > 0) + { + foreach (var att in mes.Attachments) + { + var imageMessage = new MessageExport + { + AuthorName = mes.Author.Username, + IconUrl = mes.Author.AvatarUrl, + MessageConent = att.Url, + Timestamp = mes.Timestamp.ToString("o") + }; + messageExports.Add(imageMessage); + } + } + } + + using var memStream = new MemoryStream(); + using var writer = new StreamWriter(memStream); + using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); + csv.WriteRecords(messageExports); + await writer.FlushAsync(); + memStream.Position = 0; + var fileMessage = new DiscordFollowupMessageBuilder().WithContent( + $"{selectedChannel.Name} export complete!" + ); + fileMessage.AddFile($"{selectedChannel.Name}-export.csv", memStream, true); + + await ctx.FollowUpAsync(fileMessage); + } + catch (Exception e) + { + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent(e.Message)); + return; + } + } +} \ No newline at end of file diff --git a/PoisnCopy.csproj b/PoisnCopy.csproj index 3429bfd..de63aac 100644 --- a/PoisnCopy.csproj +++ b/PoisnCopy.csproj @@ -9,6 +9,7 @@ + diff --git a/Program.cs b/Program.cs index 42dd428..0054caf 100644 --- a/Program.cs +++ b/Program.cs @@ -3,6 +3,7 @@ using DSharpPlus.Interactivity; using DSharpPlus.Interactivity.Enums; using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -21,8 +22,6 @@ internal class Program private CommandsNextExtension _commands; private InteractivityExtension _interactivity; - /* Use the async main to create an instance of the class and await it(async main is only available in C# 7.1 onwards). */ - private static async Task Main(string[] args) => await new Program().InitBot(args); private async Task InitBot(string[] args) @@ -54,9 +53,9 @@ private async Task InitBot(string[] args) _interactivity = _discord.UseInteractivity( new InteractivityConfiguration() { - PaginationBehaviour = PaginationBehaviour.WrapAround, // What to do when a pagination request times out - PaginationDeletion = PaginationDeletion.DeleteMessage, // How long to wait before timing out - Timeout = TimeSpan.FromSeconds(30) // Default time to wait for interactive commands like waiting for a message or a reaction + PaginationBehaviour = PaginationBehaviour.WrapAround, + PaginationDeletion = PaginationDeletion.DeleteMessage, + Timeout = TimeSpan.FromSeconds(30) } ); @@ -68,21 +67,24 @@ private async Task InitBot(string[] args) StringPrefixes = new List { _config.GetValue("discord:CommandPrefix") - }, // Load the command prefix(what comes before the command, eg "!" or "/") from our config file + }, Services = services, EnableDms = false } ); + var slash = _discord.UseSlashCommands(); + + slash.RegisterCommands(); Console.WriteLine("[info] Loading command modules.."); - var type = typeof(IModule); // Get the type of our interface + var type = typeof(IModule); var types = AppDomain.CurrentDomain - .GetAssemblies() // Get the assemblies associated with our project - .SelectMany(s => s.GetTypes()) // Get all the types - .Where(p => type.IsAssignableFrom(p) && !p.IsInterface); // Filter to find any type that can be assigned to an IModule + .GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(p => type.IsAssignableFrom(p) && !p.IsInterface); - var typeList = types as Type[] ?? types.ToArray(); // Convert to an array + var typeList = types as Type[] ?? types.ToArray(); foreach (var t in typeList) { _commands.RegisterCommands(t);