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,252 @@
import BotCommand from "../../libs/BotCommand";
import BotClient from "../../libs/BotClient";
import { ChatInputCommandInteraction, MessageFlags } from "discord.js";
export default class BirthdayCommand extends BotCommand {
constructor() {
super("bday", "Birthday Command", "/bday");
this.data.addSubcommand(subcommand =>
subcommand.setName("set")
.setDescription("Set your birthday")
.addNumberOption(option =>
option.setName("day")
.setDescription("Your birthday day (1-31)")
.setRequired(true)
)
.addNumberOption(option =>
option.setName("month")
.setDescription("Your birthday month (1-12)")
.setRequired(true)
)
.addStringOption(option =>
option.setName("timezone")
.setDescription("Your timezone (e.g., 'EST', GMT+2, etc.)")
.setRequired(false)
)
);
this.data.addSubcommand(subcommand =>
subcommand.setName("get")
.setDescription("Get your birthday")
.addUserOption(option =>
option.setName("user")
.setDescription("The user whose birthday you want to get")
.setRequired(false)
)
);
this.data.addSubcommand(subcommand =>
subcommand.setName("remove")
.setDescription("Remove your birthday")
);
this.data.addSubcommand(subcommand =>
subcommand.setName("list")
.setDescription("List all birthdays")
);
}
dateToEpooch(day: number, month: number, timezone?: string): number {
const now = new Date();
const currentYear = now.getFullYear();
let birthdayDate = new Date(currentYear, month - 1, day, 0, 0, 0, 0);
if (birthdayDate < now) {
birthdayDate = new Date(currentYear + 1, month - 1, day, 0, 0, 0, 0);
}
if (timezone) {
const offsetHours = this.getTimezoneOffset(timezone);
birthdayDate.setHours(birthdayDate.getHours() - offsetHours);
}
return Math.floor(birthdayDate.getTime() / 1000);
}
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
}
async setCommand(Discord: any, client: BotClient, interaction: ChatInputCommandInteraction): Promise<any> {
const day = interaction.options.getNumber("day")!;
const month = interaction.options.getNumber("month")!;
let timezone = interaction.options.getString("timezone");
timezone = timezone ? timezone.trim() : null;
timezone = timezone ? timezone.toLowerCase() : null;
// Validate timezone format to lowercase alphanumeric and special characters
if (timezone && !/^[a-zA-Z0-9+_-]+$/.test(timezone)) {
return interaction.reply({
content: "Invalid timezone format. Please use alphanumeric characters, plus (+), underscore (_), or hyphen (-).",
flags: MessageFlags.Ephemeral
});
}
if (isNaN(day) || isNaN(month)) {
return interaction.reply({
content: "Invalid date provided. Please ensure the day and month are numbers.",
flags: MessageFlags.Ephemeral
});
}
if (day < 1 || day > 31 || month < 1 || month > 12) {
return interaction.reply({
content: "Invalid date provided. Please ensure the day is between 1-31 and the month is between 1-12.",
flags: MessageFlags.Ephemeral
});
}
client.config.setBday(interaction.user.id, { day, month, timezone: timezone || undefined });
return interaction.reply({
content: `Your birthday has been set to ${day}/${month} ${timezone ? `in timezone ${timezone}` : ''}.\nYour next birthday will be on <t:${this.dateToEpooch(day, month, timezone || undefined)}:D>.`,
flags: MessageFlags.Ephemeral
});
}
async getCommand(Discord: any, client: BotClient, interaction: ChatInputCommandInteraction): Promise<any> {
const user = interaction.options.getUser("user") || interaction.user;
const bday = client.config.getBday(user.id);
if (!bday) {
return interaction.reply({
content: `\`${user.username}\` has not set a birthday.`,
flags: MessageFlags.Ephemeral
});
}
const timezone = bday.timezone ? ` in timezone ${bday.timezone}` : '';
return interaction.reply({
content: `
\`${user.username}\`'s birthday is set to ${bday.month}/${bday.day}${timezone}.\nYour next birthday will be on <t:${this.dateToEpooch(bday.day, bday.month, bday.timezone)}:D>.
`,
flags: MessageFlags.Ephemeral
});
}
async removeCommand(Discord: any, client: BotClient, interaction: ChatInputCommandInteraction): Promise<any> {
const user = interaction.user;
const bday = client.config.getBday(user.id);
if (!bday) {
return interaction.reply({
content: `\`${user.username}\`, you have not set a birthday to remove.`,
flags: MessageFlags.Ephemeral
});
}
client.config.removeBday(user.id);
return interaction.reply({
content: `\`${user.username}\`, your birthday has been removed.`,
flags: MessageFlags.Ephemeral
});
}
async listCommand(Discord: any, client: BotClient, interaction: ChatInputCommandInteraction): Promise<any> {
const bdays = client.config.getBdays();
if (!bdays || Object.keys(bdays).length === 0) {
return interaction.reply({
content: "No birthdays have been set yet.",
flags: MessageFlags.Ephemeral
});
}
// Upcoming birthdays
let response = "";
const today = new Date();
const upcoming = Object.entries(bdays).map(([userId, bday]) => {
const nextBirthday = new Date(today.getFullYear(), bday.month - 1, bday.day);
if (nextBirthday < today) {
nextBirthday.setFullYear(today.getFullYear() + 1); // Move to next year if birthday has passed
}
return { userId, bday, nextBirthday };
}).sort((a, b) => a.nextBirthday.getTime() - b.nextBirthday.getTime());
// Filter out birthdays that are more than 30 days away
const thirtyDaysFromNow = new Date(today);
thirtyDaysFromNow.setDate(today.getDate() + 30);
const filteredUpcoming = upcoming.filter(b => b.nextBirthday <= thirtyDaysFromNow);
if (filteredUpcoming.length === 0) {
response = "No upcoming birthdays within the next 30 days.";
return interaction.reply({
content: response,
flags: MessageFlags.Ephemeral
});
}
for (const { userId, bday, nextBirthday } of upcoming) {
const user = await client.users.fetch(userId);
response += `\`${user.username}\`: <t:${Math.floor(nextBirthday.getTime() / 1000)}:D>\n`;
}
if (upcoming.length === 0) {
response = "No upcoming birthdays.";
}
const embed = new Discord.EmbedBuilder()
.setTitle("Upcoming Birthdays")
.setDescription(response)
.setColor("Blue")
.setTimestamp();
return interaction.reply({
embeds: [embed],
flags: MessageFlags.Ephemeral
});
}
override async execute(Discord: any, client: BotClient, interaction: ChatInputCommandInteraction): Promise<any> {
const subcommand = interaction.options.getSubcommand();
switch (subcommand) {
case "set":
return this.setCommand(Discord, client, interaction);
case "get":
return this.getCommand(Discord, client, interaction);
case "remove":
return this.removeCommand(Discord, client, interaction);
case "list":
return this.listCommand(Discord, client, interaction);
default:
return interaction.reply({
content: "Unknown subcommand.",
flags: MessageFlags.Ephemeral
});
}
}
}