feat: added option to make joel shut the fuck up
This commit is contained in:
47
src/commands/definitions/blacklist-mention.ts
Normal file
47
src/commands/definitions/blacklist-mention.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Blacklist mention command
|
||||
*/
|
||||
|
||||
import { SlashCommandBuilder, PermissionFlagsBits } from "discord.js";
|
||||
import type { Command } from "../types";
|
||||
import { userRepository } from "../../database";
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("blacklist-mention")
|
||||
.setDescription("Blacklist a user (or yourself) from being randomly mentioned by Joel")
|
||||
.setDMPermission(false)
|
||||
.addUserOption((option) =>
|
||||
option
|
||||
.setName("user")
|
||||
.setDescription("The user to blacklist (requires Manage Guild permission if not yourself)")
|
||||
.setRequired(false)
|
||||
),
|
||||
category: "utility",
|
||||
execute: async (interaction) => {
|
||||
const targetUser = interaction.options.getUser("user") || interaction.user;
|
||||
|
||||
// If trying to blacklist someone else, check permissions
|
||||
if (targetUser.id !== interaction.user.id) {
|
||||
const member = await interaction.guild?.members.fetch(interaction.user.id);
|
||||
if (!member?.permissions.has(PermissionFlagsBits.ManageGuild)) {
|
||||
await interaction.reply({
|
||||
content: "You need the Manage Guild permission to blacklist other users.",
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await userRepository.setOptOut(targetUser.id, true);
|
||||
|
||||
await interaction.reply({
|
||||
content: targetUser.id === interaction.user.id
|
||||
? "You have been successfully blacklisted from random mentions."
|
||||
: `Successfully blacklisted <@${targetUser.id}> from random mentions.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
||||
47
src/commands/definitions/unblacklist-mention.ts
Normal file
47
src/commands/definitions/unblacklist-mention.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Unblacklist mention command
|
||||
*/
|
||||
|
||||
import { SlashCommandBuilder, PermissionFlagsBits } from "discord.js";
|
||||
import type { Command } from "../types";
|
||||
import { userRepository } from "../../database";
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("unblacklist-mention")
|
||||
.setDescription("Remove a user (or yourself) from the random mention blacklist")
|
||||
.setDMPermission(false)
|
||||
.addUserOption((option) =>
|
||||
option
|
||||
.setName("user")
|
||||
.setDescription("The user to unblacklist (requires Manage Guild permission if not yourself)")
|
||||
.setRequired(false)
|
||||
),
|
||||
category: "utility",
|
||||
execute: async (interaction) => {
|
||||
const targetUser = interaction.options.getUser("user") || interaction.user;
|
||||
|
||||
// If trying to unblacklist someone else, check permissions
|
||||
if (targetUser.id !== interaction.user.id) {
|
||||
const member = await interaction.guild?.members.fetch(interaction.user.id);
|
||||
if (!member?.permissions.has(PermissionFlagsBits.ManageGuild)) {
|
||||
await interaction.reply({
|
||||
content: "You need the Manage Guild permission to unblacklist other users.",
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await userRepository.setOptOut(targetUser.id, false);
|
||||
|
||||
await interaction.reply({
|
||||
content: targetUser.id === interaction.user.id
|
||||
? "You have been successfully removed from the random mention blacklist."
|
||||
: `Successfully removed <@${targetUser.id}> from the random mention blacklist.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
||||
@@ -131,8 +131,8 @@ export const config: BotConfig = {
|
||||
mentionCooldown: 24 * 60 * 60 * 1000, // 24 hours
|
||||
mentionProbability: 0.001,
|
||||
spontaneousSchedulerEnabled: getBooleanEnvOrDefault("BOT_SPONTANEOUS_SCHEDULER_ENABLED", true),
|
||||
spontaneousSchedulerMinIntervalMs: parseInt(getEnvOrDefault("BOT_SPONTANEOUS_MIN_INTERVAL_MS", String(45 * 60 * 1000))),
|
||||
spontaneousSchedulerMaxIntervalMs: parseInt(getEnvOrDefault("BOT_SPONTANEOUS_MAX_INTERVAL_MS", String(180 * 60 * 1000))),
|
||||
spontaneousSchedulerMinIntervalMs: parseInt(getEnvOrDefault("BOT_SPONTANEOUS_MIN_INTERVAL_MS", String(2 * 24 * 60 * 60 * 1000))), // 2 days
|
||||
spontaneousSchedulerMaxIntervalMs: parseInt(getEnvOrDefault("BOT_SPONTANEOUS_MAX_INTERVAL_MS", String(7 * 24 * 60 * 60 * 1000))), // 7 days
|
||||
},
|
||||
web: {
|
||||
port: parseInt(getEnvOrDefault("WEB_PORT", "3000")),
|
||||
|
||||
1
src/database/drizzle/0007_peaceful_juggernaut.sql
Normal file
1
src/database/drizzle/0007_peaceful_juggernaut.sql
Normal file
@@ -0,0 +1 @@
|
||||
SELECT 1;
|
||||
@@ -39,6 +39,11 @@ export const userRepository = {
|
||||
});
|
||||
},
|
||||
|
||||
async getOptedOutUserIds(): Promise<string[]> {
|
||||
const results = await db.select({ id: users.id }).from(users).where(eq(users.opt_out, 1));
|
||||
return results.map((r) => r.id);
|
||||
},
|
||||
|
||||
async addMembership(userId: string, guildId: string): Promise<void> {
|
||||
await db
|
||||
.insert(membership)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import type { Message } from "discord.js";
|
||||
import { config } from "../../core/config";
|
||||
import { createLogger } from "../../core/logger";
|
||||
import { userRepository } from "../../database";
|
||||
|
||||
const logger = createLogger("Features:Mentions");
|
||||
|
||||
@@ -22,8 +23,9 @@ export async function getRandomMemberMention(
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
const members = await message.guild.members.fetch({ limit: 100 });
|
||||
const optedOutUsers = await userRepository.getOptedOutUserIds();
|
||||
|
||||
const excludedSet = new Set(excludedUserIds);
|
||||
const excludedSet = new Set([...excludedUserIds, ...optedOutUsers]);
|
||||
const validMembers = members.filter(
|
||||
(member) => !member.user.bot && !excludedSet.has(member.id)
|
||||
);
|
||||
|
||||
@@ -7,16 +7,18 @@ import { eq } from "drizzle-orm";
|
||||
import type { BotClient } from "../../core/client";
|
||||
import { config } from "../../core/config";
|
||||
import { createLogger } from "../../core/logger";
|
||||
import { db } from "../../database";
|
||||
import { db, userRepository } from "../../database";
|
||||
import { botOptions } from "../../database/schema";
|
||||
import { getAiService } from "../../services/ai";
|
||||
|
||||
const logger = createLogger("Features:Joel:SpontaneousCron");
|
||||
|
||||
const SPONTANEOUS_TOPICS = [
|
||||
"a weird thought",
|
||||
"a funny joke",
|
||||
"a chaotic world update",
|
||||
"an unhinged shower thought",
|
||||
"a completely unsolicited aggressive life advice",
|
||||
"a bizarre threat that makes no sense",
|
||||
"a weirdly specific and insulting observation",
|
||||
"a chaotic question that demands an answer",
|
||||
] as const;
|
||||
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
@@ -151,7 +153,10 @@ function isWritableTextChannel(channel: unknown, client: BotClient): channel is
|
||||
async function getRandomGuildMemberMention(guild: Guild): Promise<string | null> {
|
||||
try {
|
||||
const members = await guild.members.fetch({ limit: 200 });
|
||||
const eligible = members.filter((member) => !member.user.bot);
|
||||
const optedOutUsers = await userRepository.getOptedOutUserIds();
|
||||
const excludedSet = new Set(optedOutUsers);
|
||||
|
||||
const eligible = members.filter((member) => !member.user.bot && !excludedSet.has(member.id));
|
||||
|
||||
const randomMember = eligible.random();
|
||||
if (!randomMember) {
|
||||
@@ -172,12 +177,14 @@ async function generateNonsense(): Promise<string | null> {
|
||||
|
||||
const response = await ai.generateResponse(
|
||||
`Write one short Discord message containing ${topic}.`,
|
||||
`You are Joel posting an unsolicited random message.
|
||||
`You are Joel, an unhinged, aggressive, and chaotic Discord bot. You are randomly pinging a user to say something completely unsolicited.
|
||||
Rules:
|
||||
- Mention nothing about being an AI
|
||||
- 1-2 sentences, max 220 characters
|
||||
- Funny or absurd tone
|
||||
- No lists, no hashtags`
|
||||
- The message should make the user think "wtf did he just say?"
|
||||
- Be aggressive, insulting, or bizarrely threatening, but in a humorous, absurd way (not extremely fucked up or genuinely disturbing).
|
||||
- Use your signature unhinged personality (swearing is fine, but keep it funny).
|
||||
- Mention nothing about being an AI.
|
||||
- 1-2 sentences, max 220 characters.
|
||||
- No lists, no hashtags, no greetings.`
|
||||
);
|
||||
|
||||
const text = response.text.trim().replace(/\s+/g, " ");
|
||||
|
||||
Reference in New Issue
Block a user