From be8c54c3a9ab7906290b86fc5f1b4016fb00d997 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Mon, 29 Jul 2024 00:03:00 +0200 Subject: [PATCH] Merge emote-stats and emote-search --- src/commands/emote.ts | 129 +++++++++++++++++++++++++++++++++++++ src/commands/emoteStats.ts | 37 ----------- 2 files changed, 129 insertions(+), 37 deletions(-) create mode 100644 src/commands/emote.ts delete mode 100644 src/commands/emoteStats.ts diff --git a/src/commands/emote.ts b/src/commands/emote.ts new file mode 100644 index 00000000..1c9d16dc --- /dev/null +++ b/src/commands/emote.ts @@ -0,0 +1,129 @@ +import { + AttachmentBuilder, + type ChatInputCommandInteraction, + EmbedBuilder, + SlashCommandBuilder, + SlashCommandStringOption, + SlashCommandSubcommandBuilder, + type CommandInteraction, +} from "discord.js"; + +import type { ApplicationCommand } from "@/commands/command.js"; +import type { BotContext } from "@/context.js"; +import type { Emote } from "@/storage/db/model.js"; +import * as emoteLoggingService from "@/service/emoteLogging.js"; +import { formatDateTime } from "@/utils/dateUtils.js"; + +function buildSingleEmoteResponse( + emote: Emote, + context: BotContext, +): [EmbedBuilder, AttachmentBuilder] { + const filename = `${emote.name}.webp`; + const file = new AttachmentBuilder(Buffer.from(emote.data)).setName(filename); + const embed = new EmbedBuilder() + .setColor(0x24283b) + .setAuthor({ + name: context.client.user.username, + iconURL: context.client.user.avatarURL() ?? undefined, + }) + .setThumbnail(`attachment://${filename}`) + .setTitle(emote.name) + .addFields( + { name: "Erstellt", value: formatDateTime(new Date(emote.createdAt)), inline: true }, + { name: "Bearbeitet", value: formatDateTime(new Date(emote.updatedAt)), inline: true }, + { + name: "Gelöscht", + value: emote.deletedAt ? formatDateTime(new Date(emote.deletedAt)) : "-", + inline: true, + }, + ); + + return [embed, file]; +} + +export default class EmoteCommand implements ApplicationCommand { + name = "emote"; + description = "Emoteverwaltung des Servers"; + + applicationCommand = new SlashCommandBuilder() + .setName(this.name) + .setDescription(this.description) + .addSubcommand( + new SlashCommandSubcommandBuilder() + .setName("search") + .setDescription( + "Sucht in der Emote Datenbank nach einem oder mehreren passenden Emotes.", + ) + .addStringOption( + new SlashCommandStringOption() + .setRequired(true) + .setName("query") + .setDescription("Wonach du suchen willst"), + ), + ) + .addSubcommand( + new SlashCommandSubcommandBuilder() + .setName("stats") + .setDescription("Zeigt Emote-Statistiken."), + ); + + async handleInteraction(command: CommandInteraction, context: BotContext): Promise { + if (!command.isChatInputCommand()) { + return; + } + + const subCommand = command.options.getSubcommand(); + switch (subCommand) { + case "search": + return this.#search(command, context); + case "stats": + return this.#stats(command, context); + default: + throw new Error("Unknown subcommand"); + } + } + + async #search(command: ChatInputCommandInteraction, context: BotContext) { + const query = command.options.getString("query", true); + const emotes = await emoteLoggingService.getMatchingEmotes(query, 5); + + if (emotes.length === 0) { + await command.reply({ + content: "Hab keine gefunden, dicker", + }); + return; + } + + const responses = emotes.map(emote => buildSingleEmoteResponse(emote, context)); + const embeds = responses.map(r => r[0]); + const files = responses.map(r => r[1]); + + await command.reply({ + embeds, + files, + }); + } + + async #stats(command: ChatInputCommandInteraction, context: BotContext) { + const stats = await emoteLoggingService.getGlobalStats(10); + const totalEmotes = Math.sumPrecise(stats.map(s => s.count)) | 0; + await command.reply({ + embeds: [ + { + title: "Emote-Statistiken", + author: { + name: context.guild.name, + icon_url: context.guild.iconURL() ?? undefined, + }, + fields: stats.map(s => ({ + name: `<${s.isAnimated ? "a" : ""}:${s.name}:${s.emoteId}>`, + value: `${s.count} mal`, + })), + footer: { + text: `Es wurden insgesamt ${totalEmotes} Emotes verwendet.`, + }, + }, + ], + }); + } +} diff --git a/src/commands/emoteStats.ts b/src/commands/emoteStats.ts deleted file mode 100644 index 0afffac5..00000000 --- a/src/commands/emoteStats.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { SlashCommandBuilder, type CommandInteraction } from "discord.js"; - -import type { ApplicationCommand } from "@/commands/command.js"; -import type { BotContext } from "@/context.js"; -import * as emoteLoggingService from "@/service/emoteLogging.js"; - -export default class EmoteStatsCommand implements ApplicationCommand { - name = "emote-stats"; - description = "Schickt Emote-Statistiken."; - - applicationCommand = new SlashCommandBuilder() - .setName(this.name) - .setDescription(this.description); - - async handleInteraction(command: CommandInteraction, context: BotContext): Promise { - const stats = await emoteLoggingService.getGlobalStats(10); - const totalEmotes = Math.sumPrecise(stats.map(s => s.count)) | 0; - await command.reply({ - embeds: [ - { - title: "Emote-Statistiken", - author: { - name: context.guild.name, - icon_url: context.guild.iconURL() ?? undefined, - }, - fields: stats.map(s => ({ - name: `<${s.isAnimated ? "a" : ""}:${s.name}:${s.emoteId}>`, - value: `${s.count} mal`, - })), - footer: { - text: `Es wurden insgesamt ${totalEmotes} Emotes verwendet.`, - }, - }, - ], - }); - } -}