diff --git a/PluralKit.Bot/CommandSystem/Context/Context.cs b/PluralKit.Bot/CommandSystem/Context/Context.cs index 2dd2dce9..d70ee7d2 100644 --- a/PluralKit.Bot/CommandSystem/Context/Context.cs +++ b/PluralKit.Bot/CommandSystem/Context/Context.cs @@ -82,7 +82,7 @@ public class Context internal readonly ModelRepository Repository; internal readonly RedisService Redis; - public async Task Reply(string text = null, Embed embed = null, AllowedMentions? mentions = null) + public async Task Reply(string text = null, Embed embed = null, AllowedMentions? mentions = null, MultipartFile[]? files = null) { var botPerms = await BotPermissions; @@ -92,6 +92,9 @@ public class Context if (embed != null && !botPerms.HasFlag(PermissionSet.EmbedLinks)) throw new PKError("PluralKit does not have permission to send embeds in this channel. Please ensure I have the **Embed Links** permission enabled."); + + if (files != null && !botPerms.HasFlag(PermissionSet.AttachFiles)) + throw new PKError("PluralKit does not have permission to attach files in this channel. Please ensure I have the **Attach Files** permission enabled."); var msg = await Rest.CreateMessage(Channel.Id, new MessageRequest { @@ -99,7 +102,7 @@ public class Context Embeds = embed != null ? new[] { embed } : null, // Default to an empty allowed mentions object instead of null (which means no mentions allowed) AllowedMentions = mentions ?? new AllowedMentions() - }); + }, files: files); // store log of sent message, so it can be queried or deleted later // skip DMs as DM messages can always be deleted diff --git a/PluralKit.Bot/Commands/Groups.cs b/PluralKit.Bot/Commands/Groups.cs index a314b248..45c5f8b4 100644 --- a/PluralKit.Bot/Commands/Groups.cs +++ b/PluralKit.Bot/Commands/Groups.cs @@ -443,10 +443,11 @@ public class Groups await ctx.Reply(embed: new EmbedBuilder() .Title("Group color") .Color(target.Color.ToDiscordColor()) - .Thumbnail(new Embed.EmbedThumbnail($"https://fakeimg.pl/256x256/{target.Color}/?text=%20")) + .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) .Description($"This group's color is **#{target.Color}**." + (isOwnSystem ? $" To clear it, type `{ctx.DefaultPrefix}group {target.Reference(ctx)} color -clear`." : "")) - .Build()); + .Build(), + files: [MiscUtils.GenerateColorPreview(target.Color)]); return; } @@ -471,8 +472,9 @@ public class Groups await ctx.Reply(embed: new EmbedBuilder() .Title($"{Emojis.Success} Group color changed.") .Color(color.ToDiscordColor()) - .Thumbnail(new Embed.EmbedThumbnail($"https://fakeimg.pl/256x256/{color}/?text=%20")) - .Build()); + .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) + .Build(), + files: [MiscUtils.GenerateColorPreview(color)]); } } diff --git a/PluralKit.Bot/Commands/MemberEdit.cs b/PluralKit.Bot/Commands/MemberEdit.cs index 0585abd7..525d60ab 100644 --- a/PluralKit.Bot/Commands/MemberEdit.cs +++ b/PluralKit.Bot/Commands/MemberEdit.cs @@ -308,10 +308,11 @@ public class MemberEdit await ctx.Reply(embed: new EmbedBuilder() .Title("Member color") .Color(target.Color.ToDiscordColor()) - .Thumbnail(new Embed.EmbedThumbnail($"https://fakeimg.pl/256x256/{target.Color}/?text=%20")) + .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) .Description($"This member's color is **#{target.Color}**." + (isOwnSystem ? $" To clear it, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} color -clear`." : "")) - .Build()); + .Build(), + files: [MiscUtils.GenerateColorPreview(target.Color)]); return; } @@ -336,8 +337,9 @@ public class MemberEdit await ctx.Reply(embed: new EmbedBuilder() .Title($"{Emojis.Success} Member color changed.") .Color(color.ToDiscordColor()) - .Thumbnail(new Embed.EmbedThumbnail($"https://fakeimg.pl/256x256/{color}/?text=%20")) - .Build()); + .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) + .Build(), + files: [MiscUtils.GenerateColorPreview(color)]); } } diff --git a/PluralKit.Bot/Commands/SystemEdit.cs b/PluralKit.Bot/Commands/SystemEdit.cs index 42d6ab5c..3af4a639 100644 --- a/PluralKit.Bot/Commands/SystemEdit.cs +++ b/PluralKit.Bot/Commands/SystemEdit.cs @@ -241,10 +241,11 @@ public class SystemEdit await ctx.Reply(embed: new EmbedBuilder() .Title("System color") .Color(target.Color.ToDiscordColor()) - .Thumbnail(new Embed.EmbedThumbnail($"https://fakeimg.pl/256x256/{target.Color}/?text=%20")) + .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) .Description( $"This system's color is **#{target.Color}**." + (isOwnSystem ? $" To clear it, type `{ctx.DefaultPrefix}s color -clear`." : "")) - .Build()); + .Build(), + files: [MiscUtils.GenerateColorPreview(target.Color)]); return; } @@ -269,8 +270,9 @@ public class SystemEdit await ctx.Reply(embed: new EmbedBuilder() .Title($"{Emojis.Success} System color changed.") .Color(color.ToDiscordColor()) - .Thumbnail(new Embed.EmbedThumbnail($"https://fakeimg.pl/256x256/{color}/?text=%20")) - .Build()); + .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) + .Build(), + files: [MiscUtils.GenerateColorPreview(color)]); } } diff --git a/PluralKit.Bot/Utils/MiscUtils.cs b/PluralKit.Bot/Utils/MiscUtils.cs index 5ee99901..8cc24029 100644 --- a/PluralKit.Bot/Utils/MiscUtils.cs +++ b/PluralKit.Bot/Utils/MiscUtils.cs @@ -1,7 +1,8 @@ using System.Net; using System.Net.Sockets; - +using System.Globalization; using Myriad.Rest.Exceptions; +using Myriad.Rest.Types; using Newtonsoft.Json; @@ -102,4 +103,26 @@ public static class MiscUtils return true; } + + public static MultipartFile GenerateColorPreview(string color) + { + //generate a 128x128 solid color gif from bytes + //image data is a 1x1 pixel, using the background color to fill the rest of the canvas + var imgBytes = new byte[] + { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, // Header + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // Logical Screen Descriptor + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, // Global Color Table + 0x21, 0xF9, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, // Graphics Control Extension + 0x2C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // Image Descriptor + 0x02, 0x02, 0x4C, 0x01, 0x00, // Image Data + 0x3B // Trailer + }; //indices 13, 14 and 15 are the R, G, and B values respectively + + imgBytes[13] = byte.Parse(color.Substring(0, 2), NumberStyles.HexNumber); + imgBytes[14] = byte.Parse(color.Substring(2, 2), NumberStyles.HexNumber); + imgBytes[15] = byte.Parse(color.Substring(4, 2), NumberStyles.HexNumber); + + return new MultipartFile("color.gif", new MemoryStream(imgBytes), null, null, null); + } } \ No newline at end of file