import { Discord, Slash, SlashGroup, SlashOption } from "discordx"; import { ApplicationCommandOptionType, CommandInteraction, EmbedBuilder, GuildMember, MessageFlags } from "discord.js"; import db from "../db"; import { colonTable, type ColonThreeType } from "../db/schema"; import { eq, desc } from "drizzle-orm"; @Discord() export class ColonThreeInit { @Slash({ description: "Init all users for :3 Leaderboard", name: "init_colonthree" }) async init_colon(inter: CommandInteraction) { if (Bun.env.OWNER != inter.user.id) { await inter.reply({ content: "You're not allowed to run this.", flags: MessageFlags.Ephemeral }) return; } for (const userObject of await inter.guild!.members.cache) { const user = userObject[1]; if (user.user.bot) { continue; } const check = await db.select().from(colonTable).where(eq(colonTable.user, user.id)); if (check.length >= 1) { continue; } await db.insert(colonTable).values({ user: user.id, amount: 0, messages_count: 0 }); } await inter.reply({ content: "All users have been initalized", flags: MessageFlags.Ephemeral }); } } @Discord() @SlashGroup({ description: "The :3 Commands", name: "colonthree" }) @SlashGroup("colonthree") export class ColonThree { @Slash({ description: "Stats" }) async stats( @SlashOption({ description: "Get stats from user", name: "user", required: false, type: ApplicationCommandOptionType.User, }) user: GuildMember, inter: CommandInteraction ) { const statsUser = ( await db .select() .from(colonTable) .where(eq(colonTable.user, (user?.id || inter.user.id))) )[0]; if (!statsUser) { await inter.reply({ content: `Failed to get <@${user?.id || inter.user.id}>'s stats.`, flags: MessageFlags.Ephemeral }); return; } const userObject = inter.client.users.cache.get(statsUser.user); if (!userObject) { await inter.reply({ content: "Something went wrong...", flags: MessageFlags.Ephemeral }); return; } const embed = new EmbedBuilder() .setTitle(`${userObject.username}'s Stats`) .setAuthor({ name: userObject.username, iconURL: userObject.avatarURL()! }) .addFields( { name: '**Total :3 Sent**', value: `โ–บ **${statsUser.amount}** times`, inline: true }, { name: '**Average :3 per Message**', value: `โ–บ **${(statsUser.amount / statsUser.messages_count).toFixed(2)}**`, inline: true }, { name: '**Messages Count**', value: `โ–บ **${statsUser.messages_count}**`, inline: true } ); await inter.reply( { embeds: [embed], flags: MessageFlags.Ephemeral }); } @Slash({ description: "Compare" }) async compare( @SlashOption({ description: "Get stats from user", name: "x", required: true, type: ApplicationCommandOptionType.User, }) x: GuildMember, @SlashOption({ description: "Get stats from user", name: "y", required: true, type: ApplicationCommandOptionType.User, }) y: GuildMember, inter: CommandInteraction ) { const xStats = ( await db .select() .from(colonTable) .where(eq(colonTable.user, x.id)) )[0]; if (!xStats) { await inter.reply({ content: `Failed to get <@${x.id}>'s stats.`, flags: MessageFlags.Ephemeral }); return; } const yStats = ( await db .select() .from(colonTable) .where(eq(colonTable.user, y.id)) )[0]; if (!yStats) { await inter.reply({ content: `Failed to get <@${y.id}>'s stats.`, flags: MessageFlags.Ephemeral }); return; } const winner = xStats.amount > yStats.amount ? x : y; const embed = new EmbedBuilder() .setTitle(`๐ŸŽ‰ ${winner.user.username} is using :3 more!`) .addFields( { name: `๐Ÿ“Š ${x.user.username}'s Stats`, value: `โ–บ Sent **${xStats.amount}** :3\nโ–บ Avg: **${(xStats.amount / xStats.messages_count).toFixed(2)}** :3 per message`, inline: true }, { name: `๐Ÿ“Š ${y.user.username}'s Stats`, value: `โ–บ Sent **${yStats.amount}** :3\nโ–บ Avg: **${(yStats.amount / yStats.messages_count).toFixed(2)}** :3 per message`, inline: true } ) await inter.reply({ embeds: [embed] }); } @Slash({ description: "Leaderboard" }) async board(inter: CommandInteraction) { const theColonThreeLeaders = await db.select() .from(colonTable) .orderBy(desc(colonTable.amount)); const topTen = theColonThreeLeaders .slice(0, 10) .filter(user => user.amount >= 1); const leaderboardText = topTen.map((user, index) => { const rank = index + 1; const avg = (user.amount / user.messages_count).toFixed(2); const medal = rank === 1 ? "๐Ÿฅ‡" : rank === 2 ? "๐Ÿฅˆ" : rank === 3 ? "๐Ÿฅ‰" : `**${rank}.**`; return `${medal} <@${user.user}> ยป **${user.amount}** :3 (avg: **${avg}**)`; }); const embed = new EmbedBuilder() .setTitle(`๐Ÿ† :3 Leaderboard`) .setDescription(leaderboardText.join("\n") || "*No data yet!*") .addFields({ name: 'Stats', value: `โ–บ **Tracking users:** ${theColonThreeLeaders.length}`, inline: false }) .setFooter({ text: 'Keep using :3!!!!!!' }) .setTimestamp(); await inter.reply({ embeds: [embed] }); } @Slash({ description: "Stop tracking and delete my data" }) async delete( @SlashOption({ description: "Type confirm to delete", name: "confirmation", required: true, type: ApplicationCommandOptionType.String, }) confirmation: string, inter: CommandInteraction ) { if (confirmation === "confirm") { await db.delete(colonTable).where(eq(colonTable.user, inter.user.id)); await inter.reply({ content: "All of data was deleted, you will not be tracked again.", flags: MessageFlags.Ephemeral }); return; } await inter.reply({ content: 'You need to type "confirm" to delete.', flags: MessageFlags.Ephemeral }); } @Slash({ description: "Start tracking" }) async start( inter: CommandInteraction ) { const check = ( await db .select() .from(colonTable) .where(eq(colonTable.user, inter.user.id) ) )[0]; if (check) { await inter.reply({ content: "Scythe already tracks your :3 data.", flags: MessageFlags.Ephemeral }); return; } await db.insert(colonTable).values({ user: inter.user.id, amount: 0, messages_count: 0 }); await inter.reply({ content: "Scythe starts tracking your :3 data again.", flags: MessageFlags.Ephemeral }); } }