/** * @copyright NHCarrigan * @license Naomi's Public License * @author Naomi Carrigan */ import { buildAuthorization, getUserRecentAchievements, type UserRecentAchievement, } from "@retroachievements/api"; import { MessageFlags, TextDisplayBuilder, ContainerBuilder, SectionBuilder, ThumbnailBuilder, SeparatorBuilder, SeparatorSpacingSize, ActionRowBuilder, ButtonBuilder, ButtonStyle, type MessageActionRowComponentBuilder, } from "discord.js"; import { ids } from "../config/ids.js"; import type { Amari } from "../interfaces/amari.js"; const username = "naomilgbt"; const webApiKey = process.env.RA_KEY; const constructComponents = ( achievement: UserRecentAchievement, ): Array< TextDisplayBuilder | ContainerBuilder | ActionRowBuilder> => { return [ new TextDisplayBuilder(). setContent("Naomi has unlocked a new achievement!"), new ContainerBuilder(). setAccentColor(16_758_493). addSectionComponents( new SectionBuilder(). setThumbnailAccessory( new ThumbnailBuilder(). setURL(`https://retroachievements.org/${achievement.badgeUrl}`), ). addTextDisplayComponents( new TextDisplayBuilder().setContent(`# ${achievement.title}`), new TextDisplayBuilder().setContent(achievement.description), ), ). addSeparatorComponents( new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small). setDivider(true), ). addSectionComponents( new SectionBuilder(). setThumbnailAccessory( new ThumbnailBuilder(). setURL(`https://retroachievements.org${achievement.gameIcon}`), ). addTextDisplayComponents( new TextDisplayBuilder().setContent( `-# From ${achievement.gameTitle} on ${achievement.consoleName}`, ), new TextDisplayBuilder().setContent( `-# Worth ${achievement.points.toString()} points!`, ), ), ), new ActionRowBuilder(). addComponents( new ButtonBuilder(). setStyle(ButtonStyle.Link). setLabel("See her profile"). setURL("https://retroachievements.org/user/naomilgbt"), ), ]; }; /** * Checks for RA achievements earned in the last 10 minutes. * If achievements are found, formats them and sends to Discord. * @param amari - Amari's instance. */ export const checkRetroAchievements = async( amari: Amari, ): Promise => { if (webApiKey === undefined) { return; } try { const auth = buildAuthorization({ username, webApiKey }); const recentAchievements = await getUserRecentAchievements(auth, { recentMinutes: 10, username: username, }); if (recentAchievements.length <= 0) { return; } const channel = amari.discord.channels.cache.get(ids.channels.gaming) ?? await amari.discord.channels.fetch(ids.channels.gaming); if (channel?.isSendable() !== true) { return; } await Promise.all(recentAchievements.map(async(achievement) => { await channel.send({ components: constructComponents(achievement), flags: [ MessageFlags.IsComponentsV2 ], }); })); } catch { // Fetch errors from RetroAchievements are non-critical; the job retries every 10 minutes. } };