Initial Code

This commit is contained in:
2025-11-23 13:22:13 -05:00
parent b16d4adfd2
commit c3e52d6a03
96 changed files with 7088 additions and 135 deletions

View File

@@ -0,0 +1,19 @@
import { post } from "../../../handlers/command_handler";
import BotClient from "../../../libs/BotClient";
import ms from "ms";
export default async(Discord: any, client: BotClient) => {
client.user?.setPresence({ activities: [{ name: '/help' }] });
try {
post(client);
setInterval(() => {
client.emit("birthdayCheck");
}, ms('30m'));
} catch (err) {
console.log(err);
} finally {
console.log(`Logged in as ${client.user?.tag}!`);
}
}

View File

@@ -0,0 +1,76 @@
import fs from 'fs';
import BotClient from "../../../libs/BotClient";
export default async(Discord: any, client: BotClient, message: any) => {
// let content = message.content;
// if (message.channel && typeof message.channel.sendTyping === 'function') {
// try {
// await message.channel.sendTyping();
// } catch (e) {
// console.error('Error sending typing indicator:', e);
// }
// }
// try {
// const { content: messageContent, typst } = await client.ai.generateText(message.author.id, message.author.username, content);
// const userId = message.author.id;
// const typPath = `./storage/typst/message_${userId}.typ`;
// const pdfPath = `./storage/typst/message_${userId}.pdf`;
// try {
// fs.writeFileSync(typPath, typst || messageContent);
// } catch (err) {
// console.error('Error writing typst file:', err);
// await message.reply({
// content: "Failed to write Typst file.",
// allowedMentions: { repliedUser: true }
// });
// return;
// }
// const { execSync } = require('child_process');
// let pdfBuffer = null;
// let hasPDF = false;
// try {
// execSync(`typst compile "${typPath}" "${pdfPath}"`);
// if (fs.existsSync(pdfPath)) {
// try {
// pdfBuffer = fs.readFileSync(pdfPath);
// hasPDF = true;
// } catch (readErr) {
// console.error('Error reading PDF file:', readErr);
// }
// }
// } catch (e) {
// console.error('Typst compile error:', e);
// await message.reply({
// content: "Failed to compile Typst to PDF.",
// allowedMentions: { repliedUser: true }
// });
// return;
// }
// const messageOptions: any = {
// content: messageContent,
// allowedMentions: { repliedUser: true }
// };
// if (hasPDF && pdfBuffer) {
// messageOptions.files = [
// {
// attachment: pdfBuffer,
// name: `message_${userId}.pdf`
// }
// ];
// }
// console.log('Sending message with options:', {
// contentLength: messageContent.length,
// hasFiles: !!messageOptions.files,
// fileCount: messageOptions.files ? messageOptions.files.length : 0
// });
// await message.reply(messageOptions);
// } catch (error) {
// console.error('Error in AI chat:', error);
// await message.reply({
// content: "I'm having trouble processing your request right now. Please try again later.",
// allowedMentions: { repliedUser: true }
// });
// }
};

View File

@@ -0,0 +1,115 @@
import BotClient from "../../../libs/BotClient";
const birthdayRole = "1385648190551888014";
const chemistryGuildID = "1310183749320835173";
function getTimezoneOffset(timezone: string): number {
const tz = timezone.toLowerCase();
// Handle GMT+/-N format
const gmtMatch = tz.match(/^gmt([+-])(\d+)$/);
if (gmtMatch) {
const sign = gmtMatch[1] === '+' ? 1 : -1;
const hours = parseInt(gmtMatch[2]);
return sign * hours;
}
// Handle UTC+/-N format
const utcMatch = tz.match(/^utc([+-])(\d+)$/);
if (utcMatch) {
const sign = utcMatch[1] === '+' ? 1 : -1;
const hours = parseInt(utcMatch[2]);
return sign * hours;
}
// Predefined timezone offsets (in hours from UTC)
const offsets: { [key: string]: number } = {
"est": -5, // Eastern Standard Time
"edt": -4, // Eastern Daylight Time
"cst": -6, // Central Standard Time
"cdt": -5, // Central Daylight Time
"mst": -7, // Mountain Standard Time
"mdt": -6, // Mountain Daylight Time
"pst": -8, // Pacific Standard Time
"pdt": -7, // Pacific Daylight Time
"gmt": 0, // Greenwich Mean Time
"utc": 0 // Coordinated Universal Time
};
return offsets[tz] || 0; // Default to UTC if not found
}
function getTodayInTimezone(timezone?: string): Date {
const now = new Date();
if (!timezone) {
const today = new Date(now);
today.setHours(0, 0, 0, 0);
return today;
}
const offsetHours = getTimezoneOffset(timezone);
const userTime = new Date(now.getTime() + (offsetHours * 60 * 60 * 1000));
userTime.setUTCHours(0, 0, 0, 0);
return userTime;
}
export default async(Discord: any, client: BotClient) => {
let bdays = client.config.getBdays();
if (!bdays || Object.keys(bdays).length === 0) return;
let guild = client.guilds.cache.get(chemistryGuildID);
if (!guild) return console.error("Guild not found");
let birthdayRoleObj = guild.roles.cache.get(birthdayRole);
if (!birthdayRoleObj) return console.error("Birthday role not found");
for (let userId in bdays) {
let bday = bdays[userId];
if (!bday || !bday.day || !bday.month) {
console.warn(`Invalid birthday data for user ${userId}`);
continue;
}
const { day, month, timezone } = bday;
const todayInUserTimezone = getTodayInTimezone(timezone);
const isBirthday = (
todayInUserTimezone.getUTCDate() === day &&
todayInUserTimezone.getUTCMonth() === month - 1
);
let member = await guild.members.fetch(userId);
if (!member) {
console.warn(`Member with ID ${userId} not found in the guild.`);
continue;
}
if (isBirthday) {
if (!member.roles.cache.has(birthdayRole)) {
try {
console.log(`🎉 It's ${member.user.tag}'s birthday!`);
await member.roles.add(birthdayRoleObj);
console.log(`✅ Added birthday role to ${member.user.tag}`);
} catch (error) {
console.error(`❌ Failed to add birthday role to ${member.user.tag}:`, error);
}
}
} else {
if (member.roles.cache.has(birthdayRole)) {
try {
await member.roles.remove(birthdayRoleObj);
console.log(`🗑️ Removed birthday role from ${member.user.tag}`);
} catch (error) {
console.error(`❌ Failed to remove birthday role from ${member.user.tag}:`, error);
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
import BotClient from "../../../libs/BotClient";
export default async (Discord: any, client: BotClient, message: any) => {
try {
if (message?.author?.bot) return;
const match = message.content?.match(/```typ\s*\n([\s\S]*?)\n```/i);
if (!match) return;
const typSource = match[1];
const messageId = message.id?.toString();
if (messageId && client.typst.hasMessage(messageId)) return;
try { if (message.channel?.sendTyping) await message.channel.sendTyping(); } catch (e) {}
const res = await client.typst.compile(typSource, { cleanup: true });
if (res.error) {
await message.reply({ content: `Typst compile error: ${res.error}`, allowedMentions: { repliedUser: true } });
return;
}
const buffers = res.buffers ?? [];
if (buffers.length === 0) {
await message.reply({ content: 'Compilation finished but no PNG files were produced.', allowedMentions: { repliedUser: true } });
return;
}
const filesToSend = buffers.map((b: Buffer, i: number) => ({ attachment: b, name: `typ_${messageId ?? Date.now()}_${i+1}.png` }));
const makeDeleteRow = () => {
const btn = new Discord.ButtonBuilder().setCustomId('typst_delete').setLabel('Delete').setStyle(Discord.ButtonStyle.Danger);
return new Discord.ActionRowBuilder().addComponents(btn);
};
const replyOpts = { content: `Here's your Typst render (${filesToSend.length} page(s)):`, files: filesToSend, components: [makeDeleteRow()], allowedMentions: { repliedUser: true } };
const replyMsg = await message.reply(replyOpts);
if (messageId && replyMsg?.id) {
client.typst.addMessage(messageId, replyMsg.id, message.author?.id);
setTimeout(async () => {
try {
client.typst.removeMessage(messageId);
try { await replyMsg.edit({ components: [] }); } catch (e) {}
} catch (e) {}
}, 2 * 60 * 1000);
}
} catch (err) {
console.error('typst message handler error:', err);
}
};

View File

@@ -0,0 +1,6 @@
import BotClient from "../../../libs/BotClient";
export default async(Discord: any, client: BotClient, member: any) => {
let memberRole = await member.guild.roles.cache.find((role: any) => role.id === '1310840470037069936');
member.roles.add(memberRole);
}

View File

@@ -0,0 +1,54 @@
import BotClient from "../../../libs/BotClient";
import { PermissionFlagsBits } from "discord.js";
import { MessageFlags } from "discord.js";
import Team from "../../../models/Team";
export default async(Discord: any, client: BotClient, interaction: any) => {
if(interaction.isButton() || interaction.isStringSelectMenu() || interaction.isModalSubmit()) {
client.action.forEach((value: any, key: string) => {
if(interaction.customId.includes(key)) return value.execute(Discord, client, interaction);
});
};
if (interaction.isAutocomplete()) {
if (interaction.commandName === "jointeam") {
const focusedValue = interaction.options.getFocused().toLowerCase();
const teams = await Team.find().exec();
const filtered = teams
.filter(t => t.name.toLowerCase().includes(focusedValue))
.slice(0, 25)
.map(t => ({ name: t.name, value: t.name }));
return interaction.respond(filtered);
}
}
if (interaction.isChatInputCommand()) {
if(process.env.isDev == "true" && !(interaction.member.permissions.has(PermissionFlagsBits.ManageGuild) || interaction.member.permissions.has(PermissionFlagsBits.Administrator))) {
return interaction.reply({ content: `:x: - You are not allowed to use this bot in a development environment`, flags: MessageFlags.Ephemeral });
}
let command = client.commands.get(interaction.commandName);
if(!command) return;
if(!command.isEnabled()) return interaction.reply({ content: `:x: - This Command is not Enabled`, flags: MessageFlags.Ephemeral });
try {
client.logger.log(`&2Command Executed: &f${interaction.commandName} - &5${interaction.user.username}`);
await command.execute(Discord, client, interaction);
} catch(error) {
console.log(error);
client.logger.log(`An error occured while executing the command: ${interaction.commandName}`);
client.logger.log(`${error}`);
const embed = client.formatter.buildEmbed("./responses/error.yaml");
return interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral });
}
};
if(interaction.isCommand()) {
if(!interaction.isChatInputCommand()) client.logger.log(`&2Interaction created: &f${interaction.commandName} - &5${interaction.user.username}`);
};
}

View File

@@ -0,0 +1,39 @@
import BotClient from "../../../libs/BotClient";
import ms from "ms";
let cooldown = false;
export default async(Discord: any, client: BotClient, message: any) => {
if(message.channel.id == "1311034475727028305") {
if(message.author.bot) return;
message.react(message.guild.emojis.cache.get('1310753663001563156'))
}
if(message.author.bot) return;
// typst code block -> emit typst event
try {
const hasTypst = /```typ\s*\n([\s\S]*?)\n```/i.test(message.content || "");
if(hasTypst) {
client.emit("typst", message);
return;
}
} catch (e) {
console.error('Error checking for typst block:', e);
}
const replyText = client.config.getReplyText();
if(replyText) {
for(const [key, value] of Object.entries(replyText)) {
if(message.content == key && !cooldown) {
cooldown = true;
setTimeout(() => {
cooldown = false;
}, ms("10s"));
return message.reply(value);
}
}
}
}

View File

@@ -0,0 +1,69 @@
import BotClient from "../../../libs/BotClient";
export default async(Discord: any, client: BotClient, oldMessage: any, newMessage: any) => {
try {
if (!newMessage || newMessage.author?.bot) return;
const match = newMessage.content?.match(/```typ\s*\n([\s\S]*?)\n```/i);
if (!match) return;
const userMsgId = newMessage.id?.toString();
if (!userMsgId) return;
if (!client.typst.hasMessage(userMsgId)) return;
const typSource = match[1];
const res = await client.typst.compile(typSource, { cleanup: true });
if (res.error) {
const botReplyId = client.typst.getResponse(userMsgId);
if (botReplyId && newMessage.channel?.messages) {
try {
const botMsg = await newMessage.channel.messages.fetch(botReplyId);
if (botMsg) await botMsg.edit({ content: `Typst compile error: ${res.error}` });
} catch (e) {}
}
return;
}
if (!res.buffers || res.buffers.length === 0) return;
const filesToSend = res.buffers.map((b: Buffer, i: number) => ({ attachment: b, name: `typ_${userMsgId}_${i+1}.png` }));
const makeDeleteRow = () => {
const deleteBtn = new Discord.ButtonBuilder().setCustomId('typst_delete').setLabel('Delete').setStyle(Discord.ButtonStyle.Danger);
return new Discord.ActionRowBuilder().addComponents(deleteBtn);
};
const replyOptions = { content: `Here's your updated Typst render (${filesToSend.length} page(s)):`, files: filesToSend, components: [makeDeleteRow()], allowedMentions: { repliedUser: true } };
const botReplyId = client.typst.getResponse(userMsgId);
let sent: any = null;
if (botReplyId && newMessage.channel?.messages) {
try {
const botMsg = await newMessage.channel.messages.fetch(botReplyId);
if (botMsg) {
try { await botMsg.delete(); } catch (e) {}
sent = await newMessage.reply(replyOptions);
}
} catch (e) {
try { sent = await newMessage.reply(replyOptions); } catch (e) {}
}
} else {
try { sent = await newMessage.reply(replyOptions); } catch (e) {}
}
if (sent && sent.id) {
client.typst.addMessage(userMsgId, sent.id, newMessage.author?.id);
setTimeout(async () => {
try {
client.typst.removeMessage(userMsgId);
try { await sent.edit({ components: [] }); } catch (e) {}
} catch (e) {}
}, 2 * 60 * 1000);
}
} catch (err) {
console.error('messageUpdate typst handler error:', err);
}
}

View File

@@ -0,0 +1,202 @@
import BotClient from "../../../libs/BotClient";
import ms from "ms";
async function sendTimeOutMessage(client: BotClient, threadChannel: any, roleID: string, category: string) {
let SolvedTag = await threadChannel.parent.availableTags.find((tag: any) => tag.name === "Solved");
if(threadChannel.appliedTags.includes(SolvedTag.id)) return;
let threadMembers = await threadChannel.guildMembers;
let helperRoles = client.config.getHelperRoles();
helperRoles = helperRoles.filter((role: any) => role.name !== "Student");
helperRoles = helperRoles.map((role: any) => role.id);
let helperInChannel = false;
threadMembers.forEach(async(threadMember: any) => {
if(threadMember.user.id == threadChannel.ownerId) return;
let member = await threadChannel.guild.members.fetch(threadMember.user.id);
let memberRoles = await member.roles.cache.map((role: any) => role.id);
memberRoles.forEach((role: any) => {
if (helperRoles.includes(role)) {
helperInChannel = true;
}
});
});
setTimeout(async() => {
if(helperInChannel) return;
let threadOwner = await threadChannel.guild.members.fetch(threadChannel.ownerId);
let helperChannel = await threadChannel.guild.channels.cache.find((channel: any) => channel.id === "1310993025958150166");
await helperChannel.send({
content: `<@&${roleID}> **${threadOwner.displayName}** has created ${threadChannel.url}. Please help the user with their ${category} question.`
});
}, ms("5s"));
}
async function mathHelpChannel(Discord: any, client: BotClient, threadChannel: any) {
const confirm = new Discord.ButtonBuilder()
.setCustomId('btn-rule-agree')
.setLabel('I Agree')
.setStyle(Discord.ButtonStyle.Success);
const threadEmbed = new Discord.EmbedBuilder()
.setColor("Red")
.setTitle("Math Help")
.setDescription(`
Make sure to follow the rules and guidelines of the server. <#1310725282357055518>
If you need help with a math problem, please provide the problem and any work you have done so far.
If you need help with a concept, please provide the concept you need help with.
Remember to be respectful and patient with others.
Ask your question and someone will help you as soon as possible.
Click the button below to confirm that you have read and understood the rules.
`)
.setTimestamp()
const row = new Discord.ActionRowBuilder().addComponents(confirm);
setTimeout(() => { threadChannel.send({ embeds: [threadEmbed], components: [row] }); }, ms("2s"));
setTimeout(async() => {
await sendTimeOutMessage(client, threadChannel, "1310718557016948788", "math");
}, ms("30m"));
}
async function programmingHelpChannel(Discord: any, client: BotClient, threadChannel: any) {
const confirm = new Discord.ButtonBuilder()
.setCustomId('btn-rule-agree')
.setLabel('I Agree')
.setStyle(Discord.ButtonStyle.Success);
const threadEmbed = new Discord.EmbedBuilder()
.setColor("Red")
.setTitle("Programming Help")
.setDescription(`
Make sure to follow the rules and guidelines of the server. <#1310725282357055518>
If you need help with a programming problem, please provide the problem and any code you have written so far.
If you need help with a concept, please provide the concept you need help with.
Remember to be respectful and patient with others.
Ask your question and someone will help you as soon as possible.
Click the button below to confirm that you have read and understood the rules.
`)
.setTimestamp()
const row = new Discord.ActionRowBuilder().addComponents(confirm);
setTimeout(() => { threadChannel.send({ embeds: [threadEmbed], components: [row] }); }, ms("2s"));
setTimeout(async() => {
await sendTimeOutMessage(client, threadChannel, "1310720256561381457", "programming");
}, ms("30m"));
}
async function chemistryHelpChannel(Discord: any, client: BotClient, threadChannel: any) {
const confirm = new Discord.ButtonBuilder()
.setCustomId('btn-rule-agree')
.setLabel('I Agree')
.setStyle(Discord.ButtonStyle.Success);
const threadEmbed = new Discord.EmbedBuilder()
.setColor("Red")
.setTitle("Chemistry Help")
.setDescription(`
Make sure to follow the rules and guidelines of the server. <#1310725282357055518>
If you need help with a chemistry problem, please provide the problem and any work you have done so far.
If you need help with a concept, please provide the concept you need help with.
Remember to be respectful and patient with others.
Ask your question and someone will help you as soon as possible.
Click the button below to confirm that you have read and understood the rules.
`)
.setTimestamp()
const row = new Discord.ActionRowBuilder().addComponents(confirm);
setTimeout(() => { threadChannel.send({ embeds: [threadEmbed], components: [row] }); }, ms("2s"));
setTimeout(async() => {
await sendTimeOutMessage(client, threadChannel, "1310715870821220497", "chemistry");
}, ms("30m"));
}
async function physicsHelpChannel(Discord: any, client: BotClient, threadChannel: any) {
const confirm = new Discord.ButtonBuilder()
.setCustomId('btn-rule-agree')
.setLabel('I Agree')
.setStyle(Discord.ButtonStyle.Success);
const threadEmbed = new Discord.EmbedBuilder()
.setColor("Red")
.setTitle("Physics Help")
.setDescription(`
Make sure to follow the rules and guidelines of the server. <#1310725282357055518>
If you need help with a physics problem, please provide the problem and any work you have done so far.
If you need help with a concept, please provide the concept you need help with.
Remember to be respectful and patient with others.
Ask your question and someone will help you as soon as possible.
Click the button below to confirm that you have read and understood the rules.
`)
.setTimestamp()
const row = new Discord.ActionRowBuilder().addComponents(confirm);
setTimeout(() => { threadChannel.send({ embeds: [threadEmbed], components: [row] }); }, ms("2s"));
setTimeout(async() => {
await sendTimeOutMessage(client, threadChannel, "1310717935588868206", "physics");
}, ms("30m"));
}
async function biologyHelpChannel(Discord: any, client: BotClient, threadChannel: any) {
const confirm = new Discord.ButtonBuilder()
.setCustomId('btn-rule-agree')
.setLabel('I Agree')
.setStyle(Discord.ButtonStyle.Success);
const threadEmbed = new Discord.EmbedBuilder()
.setColor("Red")
.setTitle("Biology Help")
.setDescription(`
Make sure to follow the rules and guidelines of the server. <#1310725282357055518>
If you need help with a biology problem, please provide the problem and any work you have done so far.
If you need help with a concept, please provide the concept you need help with.
Remember to be respectful and patient with others.
Ask your question and someone will help you as soon as possible.
Click the button below to confirm that you have read and understood the rules.
`)
.setTimestamp()
const row = new Discord.ActionRowBuilder().addComponents(confirm);
setTimeout(() => { threadChannel.send({ embeds: [threadEmbed], components: [row] }); }, ms("2s"));
setTimeout(async() => {
await sendTimeOutMessage(client, threadChannel, "1310719093996785705", "biology");
}, ms("30m"));
}
export default async(Discord: any, client: BotClient, threadChannel: any) => {
let parent = threadChannel.parent;
switch (parent.name) {
case "math-help":
await mathHelpChannel(Discord, client, threadChannel);
break;
case "programming-help":
await programmingHelpChannel(Discord, client, threadChannel);
break;
case "high-school-chemistry":
await chemistryHelpChannel(Discord, client, threadChannel);
break;
case "general-chemistry":
await chemistryHelpChannel(Discord, client, threadChannel);
break;
case "physics-help":
await physicsHelpChannel(Discord, client, threadChannel);
break;
case "biology-help":
await biologyHelpChannel(Discord, client, threadChannel);
break;
default:
break;
}
}

View File

@@ -0,0 +1,11 @@
import BotClient from "../../libs/BotClient";
export default async(Discord: any, client: BotClient, queue: any, song: any) => {
let addSong = new Discord.EmbedBuilder()
.setDescription(` Your Song has been added \n[${song.name}](${song.url}) - \`[${song.formattedDuration}]\``)
.setThumbnail(song.thumbnail)
await queue.textChannel.send({ embeds: [addSong] })
}

View File

@@ -0,0 +1,10 @@
import BotClient from "../../libs/BotClient";
export default async(Discord: any, client: BotClient, queue: any) => {
const embed = new Discord.EmbedBuilder()
.setDescription(`✅ | **Leave** the voice channel.\nThank you for using ${client?.user?.username}!`)
.setFooter({ text: client?.user?.username, iconURL: client?.user?.displayAvatarURL() });
queue.textChannel.send({ embeds: [embed] });
}

View File

@@ -0,0 +1,11 @@
import BotClient from "../../libs/BotClient";
export default async(Discord: any, client: BotClient, error: any, queue: any, song: any) => {
console.log(error);
const embed = new Discord.EmbedBuilder()
.setDescription(`❌ | There was an Error\n ${error}`)
queue.textChannel.send({ embeds: [embed] })
}

View File

@@ -0,0 +1,10 @@
import BotClient from "../../libs/BotClient";
export default async(Discord: any, client: BotClient, queue: any) => {
let playSong = new Discord.EmbedBuilder()
.setDescription(`No more song in queue`)
queue.textChannel.send({ embeds: [playSong] })
}

View File

@@ -0,0 +1,7 @@
import BotClient from "../../libs/BotClient";
export default async(Discord: any, client: BotClient) => {
// SOMETHING HERE
}

View File

@@ -0,0 +1,12 @@
import BotClient from "../../libs/BotClient";
export default async(Discord: any, client: BotClient, queue: any, song: any) => {
let playSong = new Discord.EmbedBuilder()
.setThumbnail(song.thumbnail)
.setDescription(`Song Playing \n[${song.name}](${song.url}) - \`[${song.formattedDuration}]\``)
.setFooter({ text: `Request by ${song.user.tag}`, iconURL: song.user.displayAvatarURL() });
queue.textChannel.send({ embeds: [playSong] })
}