Skip to content

Commit

Permalink
some improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Techbot121 authored and Meta Construct committed Dec 26, 2024
1 parent d817987 commit 7894adb
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 190 deletions.
286 changes: 149 additions & 137 deletions app/services/Starboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import Discord from "discord.js";
import config from "@/config/starboard.json";
import discordConfig from "@/config/discord.json";

const DEFAULT_AMOUNT = config.amount;
const DEFAULT_EMOTE = config.defaultEmote;
const STARBOARD_CONFIG = {
MESSAGE_AGE_LIMIT_MS: 3 * 28 * 24 * 60 * 60 * 1000, // 3 months
DEFAULT_AMOUNT: config.amount,
DEFAULT_EMOTE: config.defaultEmote,
} as const;

export class Starboard extends Service {
name = "Starboard";
Expand Down Expand Up @@ -57,154 +60,163 @@ export class Starboard extends Service {
}

public async handleReactionAdded(reaction: Discord.MessageReaction): Promise<void> {
const client = reaction.client;
const channel = reaction.message.channel as Discord.GuildChannel;
const parent = channel.parentId;

if (config.channelIgnores.includes(channel.id)) return;
if (parent && config.categoryIgnores.includes(parent)) return;

let needed: number = DEFAULT_AMOUNT;
let emojiFilter: string[] | undefined = [DEFAULT_EMOTE];
let targetChannel: Discord.Channel | undefined = client.channels.cache.get(
discordConfig.channels.h
);
let title: string | undefined;
let shouldReact = false;

if (reaction.emoji.name !== DEFAULT_EMOTE) {
switch (parent) {
// the parent of a thread is the main channel, so we sadly can't get the category without fetching, so much for dry
case discordConfig.channels.postYourStuff:
emojiFilter = undefined;
shouldReact = true;
needed = 6;
title =
reaction.message.channel.isThread() &&
reaction.message.id === reaction.message.channel.id
? reaction.message.channel.name
: undefined;
targetChannel = client.channels.cache.get(discordConfig.channels.hArt);
break;
default:
switch (channel.id) {
case discordConfig.channels.artChat:
emojiFilter = undefined;
shouldReact = true;
needed = 6;
targetChannel = client.channels.cache.get(discordConfig.channels.hArt);
break;
}
}
}
if (this.isBusy) return;

const ego = reaction.message.author
? reaction.users.cache.has(reaction.message.author.id)
: false;
const count = ego ? reaction.count - 1 : reaction.count;

if (
count >= needed &&
!this.isBusy &&
(emojiFilter ? emojiFilter.includes(reaction.emoji.name ?? "") : true)
) {
this.isBusy = true;
const msg = await reaction.message.fetch();
if (!msg) {
console.error("[Starboard] couldn't fetch message", reaction);
this.isBusy = false;
return;
}
try {
const client = reaction.client;
const channel = reaction.message.channel as Discord.GuildChannel;
const parent = channel.parentId;

if (msg.author.bot)
targetChannel = client.channels.cache.get(discordConfig.channels.hBot);
if (config.channelIgnores.includes(channel.id)) return;
if (parent && config.categoryIgnores.includes(parent)) return;

if (!targetChannel) {
console.error("[Starboard] wtf invalid channel", reaction);
this.isBusy = false;
return;
let needed: number = STARBOARD_CONFIG.DEFAULT_AMOUNT;
let emojiFilter: string[] | undefined = [STARBOARD_CONFIG.DEFAULT_EMOTE];
let targetChannel: Discord.Channel | undefined = client.channels.cache.get(
discordConfig.channels.h
);
let title: string | undefined;
let shouldReact = false;

if (reaction.emoji.name !== STARBOARD_CONFIG.DEFAULT_EMOTE) {
switch (parent) {
// the parent of a thread is the main channel, so we sadly can't get the category without fetching, so much for dry
case discordConfig.channels.postYourStuff:
emojiFilter = undefined;
shouldReact = true;
needed = 6;
title =
reaction.message.channel.isThread() &&
reaction.message.id === reaction.message.channel.id
? reaction.message.channel.name
: undefined;
targetChannel = client.channels.cache.get(discordConfig.channels.hArt);
break;
default:
switch (channel.id) {
case discordConfig.channels.artChat:
emojiFilter = undefined;
shouldReact = true;
needed = 6;
targetChannel = client.channels.cache.get(
discordConfig.channels.hArt
);
break;
}
}
}

// check against our local db first
if (await this.isMsgStarred(msg.id)) {
this.isBusy = false;
return;
}
const ego = reaction.message.author
? reaction.users.cache.has(reaction.message.author.id)
: false;
const count = ego ? reaction.count - 1 : reaction.count;

if (
count >= needed &&
(emojiFilter ? emojiFilter.includes(reaction.emoji.name ?? "") : true)
) {
this.isBusy = true;
const msg = await reaction.message.fetch();
if (!msg) {
console.error("[Starboard] couldn't fetch message", reaction);
this.isBusy = false;
return;
}

// skip messages older than 3 months
if (Date.now() - msg.createdTimestamp > 3 * 28 * 24 * 60 * 60 * 1000) {
this.isBusy = false;
return;
}
if (msg.author.bot)
targetChannel = client.channels.cache.get(discordConfig.channels.hBot);

let text = title ? `## ${title}\n` : "";

const reference = msg.reference;
if (reference && reference.messageId) {
const refMsg = await (
client.channels.cache.get(reference.channelId) as Discord.TextChannel
).messages.fetch(reference.messageId);

text += `${
reference
? `[replying to ${
refMsg.system ? "System Message" : refMsg.author.username
}](${refMsg.url})\n`
: ""
}`;
}
if (!targetChannel) {
console.error("[Starboard] wtf invalid channel", reaction);
this.isBusy = false;
return;
}

text += msg.content;
text += msg.stickers.size > 0 ? msg.stickers.first()?.url : "";
// check against our local db first
if (await this.isMsgStarred(msg.id)) {
this.isBusy = false;
return;
}

const files: string[] = [];
msg.attachments.map(a => files.push(a.url));
// skip messages older than 3 months
if (Date.now() - msg.createdTimestamp > STARBOARD_CONFIG.MESSAGE_AGE_LIMIT_MS) {
this.isBusy = false;
return;
}

const channel = targetChannel as Discord.TextChannel;
let text = title ? `## ${title}\n` : "";

const reference = msg.reference;
if (reference && reference.messageId) {
const refMsg = await (
client.channels.cache.get(reference.channelId) as Discord.TextChannel
).messages.fetch(reference.messageId);

text += `${
reference
? `[replying to ${
refMsg.system ? "System Message" : refMsg.author.username
}](${refMsg.url})\n`
: ""
}`;
}

// we need a webhook created by the application so we can attach components
const webhooks = await channel.fetchWebhooks();
let webhook = webhooks.find(
h => h.applicationId === discordConfig.bot.applicationId && h.token
);
if (!webhook) webhook = await channel.createWebhook({ name: "metaconcord starboard" });

if (webhook) {
const starred = await webhook
.send({
content: text,
avatarURL: msg.author.avatarURL() ?? "",
username: msg.author.username,
allowedMentions: { parse: ["users", "roles"] },
files: files,
embeds: msg.author.bot ? msg.embeds : undefined,
components: [
{
type: Discord.ComponentType.ActionRow,
components: [
{
type: Discord.ComponentType.Button,
label: "Jump to message",
style: Discord.ButtonStyle.Link,
url: msg.url,
},
{
type: Discord.ComponentType.Button,
label: "Delete",
style: Discord.ButtonStyle.Danger,
customId: `starboard:${msg.id}:${msg.channelId}`,
},
],
},
],
})
.catch();
if (starred) {
await this.starMsg(msg.id);
if (shouldReact) await starred.react(reaction.emoji);
text += msg.content;
text += msg.stickers.size > 0 ? msg.stickers.first()?.url : "";

const files: string[] = [];
msg.attachments.map(a => files.push(a.url));

const channel = targetChannel as Discord.TextChannel;

// we need a webhook created by the application so we can attach components
const webhooks = await channel.fetchWebhooks();
let webhook = webhooks.find(
h => h.applicationId === discordConfig.bot.applicationId && h.token
);
if (!webhook)
webhook = await channel.createWebhook({ name: "metaconcord starboard" });

if (webhook) {
const components: Discord.ActionRowBuilder<Discord.ButtonBuilder>[] = [
new Discord.ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
new Discord.ButtonBuilder()
.setLabel("Jump to message")
.setStyle(Discord.ButtonStyle.Link)
.setURL(msg.url),
...(!msg.author.bot
? [
new Discord.ButtonBuilder()
.setLabel("Delete")
.setStyle(Discord.ButtonStyle.Danger)
.setCustomId(`starboard:${msg.id}:${msg.channelId}`),
]
: [])
),
];

const starred = await webhook
.send({
content: text,
avatarURL: msg.author.avatarURL() ?? "",
username: msg.author.username,
allowedMentions: { parse: ["users", "roles"] },
files: files,
embeds: msg.author.bot ? msg.embeds : undefined,
components,
})
.catch();
if (starred) {
await this.starMsg(msg.id);
if (shouldReact) await starred.react(reaction.emoji);
}
}
}

this.isBusy = false;
}
} catch (error) {
console.error("[Starboard] Error handling reaction:", error);
} finally {
this.isBusy = false;
}
}
Expand Down
Loading

0 comments on commit 7894adb

Please sign in to comment.