From 0afcee108eb3d24957eae44d9e7fe9cc3d668b6f Mon Sep 17 00:00:00 2001 From: Iris System Date: Mon, 25 Aug 2025 14:26:29 +1200 Subject: [PATCH] feat(bot): allow querying legacy embeds with -se flag --- PluralKit.Bot/Commands/Groups.cs | 6 ++ PluralKit.Bot/Commands/Member.cs | 8 ++ PluralKit.Bot/Commands/System.cs | 5 ++ PluralKit.Bot/Services/EmbedService.cs | 100 +++++++++++++++++++++++++ 4 files changed, 119 insertions(+) diff --git a/PluralKit.Bot/Commands/Groups.cs b/PluralKit.Bot/Commands/Groups.cs index c4661010..b18764d2 100644 --- a/PluralKit.Bot/Commands/Groups.cs +++ b/PluralKit.Bot/Commands/Groups.cs @@ -520,6 +520,12 @@ public class Groups public async Task ShowGroupCard(Context ctx, PKGroup target) { var system = await GetGroupSystem(ctx, target); + if (ctx.MatchFlag("show-embed", "se")) + { + await ctx.Reply(text: EmbedService.LEGACY_EMBED_WARNING, embed: await _embeds.CreateGroupEmbed(ctx, system, target)); + return; + } + await ctx.Reply(components: await _embeds.CreateGroupMessageComponents(ctx, system, target)); } diff --git a/PluralKit.Bot/Commands/Member.cs b/PluralKit.Bot/Commands/Member.cs index 43582a24..37ab9d18 100644 --- a/PluralKit.Bot/Commands/Member.cs +++ b/PluralKit.Bot/Commands/Member.cs @@ -122,6 +122,14 @@ public class Member public async Task ViewMember(Context ctx, PKMember target) { var system = await ctx.Repository.GetSystem(target.System); + if (ctx.MatchFlag("show-embed", "se")) + { + await ctx.Reply( + text: EmbedService.LEGACY_EMBED_WARNING, + embed: await _embeds.CreateMemberEmbed(system, target, ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone)); + return; + } + await ctx.Reply( components: await _embeds.CreateMemberMessageComponents(system, target, ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone)); } diff --git a/PluralKit.Bot/Commands/System.cs b/PluralKit.Bot/Commands/System.cs index 868fa154..2160dfd1 100644 --- a/PluralKit.Bot/Commands/System.cs +++ b/PluralKit.Bot/Commands/System.cs @@ -17,6 +17,11 @@ public class System public async Task Query(Context ctx, PKSystem system) { if (system == null) throw Errors.NoSystemError(ctx.DefaultPrefix); + if (ctx.MatchFlag("show-embed", "se")) + { + await ctx.Reply(text: EmbedService.LEGACY_EMBED_WARNING, embed: await _embeds.CreateSystemEmbed(ctx, system, ctx.LookupContextFor(system.Id))); + return; + } await ctx.Reply(components: await _embeds.CreateSystemMessageComponents(ctx, system, ctx.LookupContextFor(system.Id))); } diff --git a/PluralKit.Bot/Services/EmbedService.cs b/PluralKit.Bot/Services/EmbedService.cs index d66a6b5a..16a9ef13 100644 --- a/PluralKit.Bot/Services/EmbedService.cs +++ b/PluralKit.Bot/Services/EmbedService.cs @@ -15,6 +15,8 @@ namespace PluralKit.Bot; public class EmbedService { + public const string LEGACY_EMBED_WARNING = "\u26A0\uFE0F The \"legacy\" embeds for system/member/group cards are deprecated, and will be removed in future."; + private readonly IDiscordCache _cache; private readonly IDatabase _db; private readonly ModelRepository _repo; @@ -186,6 +188,104 @@ public class EmbedService ]; } + public async Task CreateSystemEmbed(Context cctx, PKSystem system, LookupContext ctx) + { + // Fetch/render info for all accounts simultaneously + var accounts = await _repo.GetSystemAccounts(system.Id); + var users = (await GetUsers(accounts)).Select(x => x.User?.NameAndMention() ?? $"(deleted account {x.Id})"); + + var countctx = LookupContext.ByNonOwner; + if (cctx.MatchFlag("a", "all")) + { + if (system.Id == cctx.System.Id) + countctx = LookupContext.ByOwner; + else + throw Errors.LookupNotAllowed; + } + + var memberCount = await _repo.GetSystemMemberCount(system.Id, countctx == LookupContext.ByOwner ? null : PrivacyLevel.Public); + + var eb = new EmbedBuilder() + .Title(system.NameFor(ctx)) + .Footer(new Embed.EmbedFooter( + $"System ID: {system.DisplayHid(cctx.Config)} | Created on {system.Created.FormatZoned(cctx.Zone)}")) + .Color(system.Color?.ToDiscordColor()) + .Url($"https://dash.pluralkit.me/profile/s/{system.Hid}"); + + var avatar = system.AvatarFor(ctx); + if (avatar != null) + eb.Thumbnail(new Embed.EmbedThumbnail(avatar)); + + if (system.BannerPrivacy.CanAccess(ctx)) + eb.Image(new Embed.EmbedImage(system.BannerImage)); + + var latestSwitch = await _repo.GetLatestSwitch(system.Id); + if (latestSwitch != null && system.FrontPrivacy.CanAccess(ctx)) + { + var switchMembers = + await _db.Execute(conn => _repo.GetSwitchMembers(conn, latestSwitch.Id)).ToListAsync(); + if (switchMembers.Count > 0) + { + var memberStr = string.Join(", ", switchMembers.Select(m => m.NameFor(ctx))); + if (memberStr.Length > 200) + memberStr = $"[too many to show, see `{cctx.DefaultPrefix}system {system.DisplayHid(cctx.Config)} fronters`]"; + eb.Field(new Embed.Field("Fronter".ToQuantity(switchMembers.Count, ShowQuantityAs.None), memberStr)); + } + } + + if (system.Tag != null) + eb.Field(new Embed.Field("Tag", system.Tag.EscapeMarkdown(), true)); + + if (cctx.Guild != null) + { + var guildSettings = await _repo.GetSystemGuild(cctx.Guild.Id, system.Id); + + if (guildSettings.Tag != null && guildSettings.TagEnabled) + eb.Field(new Embed.Field($"Tag (in server '{cctx.Guild.Name}')", guildSettings.Tag + .EscapeMarkdown(), true)); + + if (!guildSettings.TagEnabled) + eb.Field(new Embed.Field($"Tag (in server '{cctx.Guild.Name}')", + "*(tag is disabled in this server)*")); + + if (guildSettings.DisplayName != null) + eb.Title(guildSettings.DisplayName); + + var guildAvatar = guildSettings.AvatarUrl.TryGetCleanCdnUrl(); + if (guildAvatar != null) + { + eb.Thumbnail(new Embed.EmbedThumbnail(guildAvatar)); + var sysDesc = "*(this system has a server-specific avatar set"; + if (avatar != null) + sysDesc += $"; [click here]({system.AvatarUrl.TryGetCleanCdnUrl()}) to see their global avatar)*"; + else + sysDesc += ")*"; + eb.Description(sysDesc); + } + } + + if (system.PronounPrivacy.CanAccess(ctx) && system.Pronouns != null) + eb.Field(new Embed.Field("Pronouns", system.Pronouns, true)); + + if (!system.Color.EmptyOrNull()) eb.Field(new Embed.Field("Color", $"#{system.Color}", true)); + + eb.Field(new Embed.Field("Linked accounts", string.Join("\n", users).Truncate(1000), true)); + + if (system.MemberListPrivacy.CanAccess(ctx)) + { + if (memberCount > 0) + eb.Field(new Embed.Field($"Members ({memberCount})", + $"(see `{cctx.DefaultPrefix}system {system.DisplayHid(cctx.Config)} list` or `{cctx.DefaultPrefix}system {system.DisplayHid(cctx.Config)} list full`)", true)); + else + eb.Field(new Embed.Field($"Members ({memberCount})", $"Add one with `{cctx.DefaultPrefix}member new`!", true)); + } + + if (system.DescriptionFor(ctx) is { } desc) + eb.Field(new Embed.Field("Description", desc.NormalizeLineEndSpacing().Truncate(1024))); + + return eb.Build(); + } + public Embed CreateLoggedMessageEmbed(Message triggerMessage, Message proxiedMessage, string systemHid, PKMember member, string channelName, string oldContent = null) {