discord.js 14 port

collapses and dies instantly, exploding into 15 million little piees
This commit is contained in:
Jill 2023-06-11 18:23:57 +03:00
parent d737d519b4
commit fc50b90562
Signed by: oat
GPG Key ID: 33489AA58A955108
20 changed files with 584 additions and 542 deletions

View File

@ -1,6 +1,5 @@
const fs = require("node:fs");
const { REST } = require("@discordjs/rest");
const { Routes } = require("discord-api-types/v9");
const { REST, Routes } = require("discord.js");
const {token} = require('./config.json');
const rest = new REST({ version: "9" }).setToken(token);

View File

@ -1,6 +1,5 @@
const fs = require("node:fs");
const { REST } = require("@discordjs/rest");
const { Routes } = require("discord-api-types/v9");
const { REST, Routes } = require("discord.js");
const { token } = require('./config.json');
const { exec } = require('child_process');

View File

@ -12,9 +12,7 @@
"author": "oatmealine",
"license": "AGPL-3.0",
"dependencies": {
"@discordjs/builders": "^0.13.0",
"@discordjs/rest": "^0.4.1",
"discord.js": "^13.8.0",
"discord.js": "^14.11.0",
"got": "^11.8.3",
"parse-color": "^1.0.0",
"random-seed": "^0.3.0"

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CategoryChannel, CommandInteraction, GuildMember, MessageEmbed, TextChannel } from 'discord.js';
import { CategoryChannel, GuildMember, EmbedBuilder, TextChannel, Interaction, ChannelType, SlashCommandBuilder } from 'discord.js';
const rand = [
'This change has no significance.',
@ -49,8 +48,10 @@ module.exports = {
.setRequired(true)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
const what = interaction.options.getString('what')!;
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
const what = interaction.options.getString('what', true);
let title = `**${member.displayName}** changed the **${what}**`;
let response;
@ -76,15 +77,15 @@ module.exports = {
break;
case 'identity':
response = 'I\'ve changed my nickname in accordance. I hope this identity pleases you.';
await interaction.guild!.me!.setNickname(nicknames[Math.floor(Math.random() * nicknames.length)]);
await interaction.guild!.members.me!.setNickname(nicknames[Math.floor(Math.random() * nicknames.length)]);
break;
case 'location':
case 'position': {
response = 'You do not feel like your surroundings have changed, but rather where you are relative to your surroundings has changed.';
const categories = Array(...interaction.guild!.channels.cache.filter(v => v.type === 'GUILD_CATEGORY').values());
const categories = Array(...interaction.guild!.channels.cache.filter(v => v.type === ChannelType.GuildCategory).values());
const category = categories[Math.floor(Math.random() * categories.length)] as CategoryChannel;
await (interaction.channel as TextChannel).setParent(category);
await (interaction.channel as TextChannel).setPosition(Math.floor(Math.random() * category.children.size));
await (interaction.channel as TextChannel).setPosition(Math.floor(Math.random() * category.children.cache.size));
break;
}
case '04':
@ -94,7 +95,7 @@ module.exports = {
response = rand[Math.floor(Math.random() * rand.length)];
}
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTitle(title)
.setDescription(response)
.setTimestamp();

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, CreateRoleOptions, GuildMember, Message, MessageActionRow, MessageButton, MessageEmbed, TextChannel } from 'discord.js';
import { RoleCreateOptions, GuildMember, Interaction, Message, EmbedBuilder, TextChannel, ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } from 'discord.js';
import { default as parseColor, Color } from 'parse-color';
import { isColorRole, COLOR_ROLE_SEPERATOR } from '../lib/assignableRoles';
@ -19,7 +18,7 @@ async function applyColor(member: GuildMember, color: Color) {
const colorRoleSeperator = await member.guild.roles.fetch(COLOR_ROLE_SEPERATOR);
if (!colorRoleSeperator) console.error('no color role seperator found?!?!');
const roleSettings: CreateRoleOptions = {
const roleSettings: RoleCreateOptions = {
name: color.hex,
color: color.rgb,
hoist: false,
@ -41,13 +40,14 @@ module.exports = {
.addStringOption((option) =>
option.setName('color')
.setDescription('Color to set. Must be a parsable HTML color. Examples include: #ff0000, rgb(50, 0, 0), red, etc.')
.setRequired(true)
)
.addBooleanOption((option) =>
option.setName('preview').setDescription('Preview the color instead of applying it')
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
const color = interaction.options.getString('color');
const preview = interaction.options.getBoolean('preview');
@ -62,22 +62,23 @@ module.exports = {
}
if (preview) {
const embed = new MessageEmbed();
const embed = new EmbedBuilder();
embed.setImage(`https://dummyimage.com/200x200/${parsed.hex.slice(1)}/${parsed.hex.slice(1)}.png`);
embed.setTitle(`Previewing ${parsed.hex}`);
const row = new MessageActionRow().addComponents(
new MessageButton()
.setLabel('Apply')
.setStyle('PRIMARY')
.setCustomId(`apply-color-${parsed.hex}`)
);
const apply = new ButtonBuilder()
.setLabel('Apply')
.setStyle(ButtonStyle.Primary)
.setCustomId(`apply-color-${parsed.hex}`);
const message = (await interaction.reply({
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(apply);
const message = await interaction.reply({
embeds: [embed],
components: [row],
fetchReply: true
})) as Message;
});
const collector = (interaction.channel as TextChannel).createMessageComponentCollector({
filter: (i) => i.message.id === message.id,

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember } from 'discord.js';
import { Interaction, GuildMember, SlashCommandBuilder } from 'discord.js';
import { changeCounterInteraction } from '../lib/counter';
module.exports = {
@ -14,7 +13,9 @@ module.exports = {
.setMinValue(1)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ephemeral: true});
const amount = Math.trunc(interaction.options.getInteger('amount') || 1);
changeCounterInteraction(interaction, member, -amount, false);

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember } from 'discord.js';
import { Interaction, GuildMember, SlashCommandBuilder } from 'discord.js';
import { changeCounterInteraction, getCounter } from '../lib/counter';
module.exports = {
@ -14,7 +13,9 @@ module.exports = {
.setMinValue(1)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ephemeral: true});
const amount = Math.min(Math.trunc(interaction.options.getInteger('amount') || 1), getCounter(true));
changeCounterInteraction(interaction, member, -amount, true);

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember, MessageEmbed } from 'discord.js';
import { GuildMember, EmbedBuilder, SlashCommandBuilder, Interaction } from 'discord.js';
import { writeTmpFile } from '../lib/util';
module.exports = {
@ -15,11 +14,13 @@ module.exports = {
.setMaxValue(512)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
const size = interaction.options.getInteger('size') || 64;
const emojis = member.guild.emojis;
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setDescription(`names: \`${emojis.cache.map(emote => emote.name).join(',')}\``);
const commands = [

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, Guild, GuildMember, Role } from 'discord.js';
import { CommandInteraction, Guild, GuildMember, Interaction, Role, SlashCommandBuilder } from 'discord.js';
import { isColorRole, isPronounRole } from '../lib/assignableRoles';
async function fetchRoleMembers(role: Role) {
@ -26,9 +25,11 @@ module.exports = {
.setName('garbage-collect-roles')
.setDescription('Garbage collect unused roles for colors and pronouns.')
.addBooleanOption((option) => option.setName('dry-run').setDescription('Only show roles that would be deleted.'))
.setDefaultPermission(false),
.setDefaultMemberPermissions('0'),
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
execute: async (interaction: CommandInteraction, member: GuildMember) => {
await interaction.deferReply({
ephemeral: false
});

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember } from 'discord.js';
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { changeCounterInteraction } from '../lib/counter';
module.exports = {
@ -14,7 +13,9 @@ module.exports = {
.setMinValue(1)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ephemeral: true});
const amount = Math.trunc(interaction.options.getInteger('amount') || 1);
changeCounterInteraction(interaction, member, amount, false);

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember } from 'discord.js';
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { changeCounterInteraction } from '../lib/counter';
module.exports = {
@ -14,7 +13,9 @@ module.exports = {
.setMinValue(1)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
if (member.id !== '212481359589933056' && member.id !== '321126371189587968')
return await interaction.reply({
ephemeral: true,

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember, MessageEmbed } from 'discord.js';
import { GuildMember, EmbedBuilder, SlashCommandBuilder, Interaction } from 'discord.js';
const rand = require('random-seed').create();
const results = [
@ -27,8 +26,10 @@ module.exports = {
.addUserOption((option) => option.setName('who').setDescription('Investigate who?').setRequired(true))
.addBooleanOption((option) => option.setName('sheriff').setDescription('Switch to Sheriff-style investigation').setRequired(false)),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
const who = interaction.options.getUser('who')!;
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
const who = interaction.options.getUser('who', true);
const sheriff = interaction.options.getBoolean('sheriff');
let response;
let color;
@ -55,7 +56,7 @@ module.exports = {
}
}
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setDescription(response)
.setAuthor({
name: `${member.displayName} the ${sheriff ? 'Sheriff' : 'Investigator'}`,

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember, Message, User } from 'discord.js';
import { GuildMember, Message, User, SlashCommandBuilder, Interaction } from 'discord.js';
const DEFAULT_EMOJI = '🪙';
const STOP_EMOJI = '⏹️';
@ -47,7 +46,9 @@ module.exports = {
.setMinValue(1)
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
let participants: User[] = [member.user];
const context = interaction.options.getInteger('context') || 3;

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, MessageEmbed } from 'discord.js';
import { EmbedBuilder, Interaction, SlashCommandBuilder } from 'discord.js';
import got from 'got';
const rand = require('random-seed').create();
@ -37,10 +36,12 @@ module.exports = {
.setRequired(true)
),
execute: async (interaction: CommandInteraction) => {
execute: async (interaction: Interaction) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ephemeral: false});
let what = interaction.options.getString('what')!.toLowerCase();
let what = interaction.options.getString('what', true).toLowerCase();
const whatOrig = what;
if (what.startsWith('the ')) what = what.slice(4);
@ -55,10 +56,10 @@ module.exports = {
// @ts-ignore
const thumbURL = Object.values(thumb.query.pages)[0].thumbnail.source;
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTitle(whatOrig)
.setImage(thumbURL)
.setFooter('Image may not always be accurate.')
.setFooter({text: 'Image may not always be accurate.'})
.setTimestamp();
await interaction.followUp({

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, CreateRoleOptions, GuildMember } from 'discord.js';
import { RoleCreateOptions, GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { pronouns, PRONOUN_ROLE_SEPERATOR } from '../lib/assignableRoles';
function extendOption(t: string) {
@ -18,17 +17,19 @@ module.exports = {
.setChoices(...Array.from(pronouns.values()).map(extendOption))
),
execute: async (interaction: CommandInteraction, member: GuildMember) => {
execute: async (interaction: Interaction, member: GuildMember) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({
ephemeral: true
});
const pronoun = interaction.options.getString('pronoun') as string;
const pronoun = interaction.options.getString('pronoun', true);
const pronounRoleSeperator = await member.guild.roles.fetch(PRONOUN_ROLE_SEPERATOR);
if (!pronounRoleSeperator) console.error('no pronoun role seperator found?!?!');
const roleSettings: CreateRoleOptions = {
const roleSettings: RoleCreateOptions = {
name: pronoun,
hoist: false,
mentionable: false,

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction } from 'discord.js';
import { Interaction, SlashCommandBuilder } from 'discord.js';
import { saveSubscriptions, subscriptions, timeAnnouncements } from '../lib/subscriptions';
module.exports = {
@ -12,11 +11,14 @@ module.exports = {
.setChoices(...Object.keys(timeAnnouncements).map(l => ({name: l, value: l})))
.setDescription('The name of the time announcement')
)
.setDefaultPermission(false),
.setDefaultMemberPermissions('0'),
execute: async (interaction: CommandInteraction) => {
execute: async (interaction: Interaction) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ephemeral: true});
const announcementType = interaction.options.getString('type') as string;
const announcementType = interaction.options.getString('type', true);
if (subscriptions[announcementType] && subscriptions[announcementType].includes(interaction.channelId)) {
subscriptions[announcementType] = subscriptions[announcementType].filter(id => id !== interaction.channelId);

View File

@ -1,5 +1,4 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { CommandInteraction, GuildMember, MessageActionRow, MessageButton, Client, Collection, MessageComponentInteraction, MessageSelectMenu, Modal, TextInputComponent, MessageSelectOptionData, MessageComponentType, TextChannel, TextInputStyleResolvable, Message } from 'discord.js';
import { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, Client, Collection, MessageComponentInteraction, StringSelectMenuBuilder, ModalBuilder, TextChannel, TextInputStyle, Message, ButtonStyle, ComponentType, APIButtonComponentWithCustomId, Events, TextInputBuilder, SlashCommandBuilder } from 'discord.js';
import * as fs from 'fs/promises';
const SURVEY_CHANNEL = '983479509376434216';
@ -8,7 +7,7 @@ const GENERAL_CHANNEL = '587108210683412493';
const ephemeral = true;
function extendOptions(opt: string[]): MessageSelectOptionData[] {
function extendOptions(opt: string[]) {
return opt.map(t => ({label: t, value: t.toLowerCase().replace(/[^a-z0-9-]/g, '-')}));
}
@ -22,7 +21,7 @@ const survey = [
{
text: 'Your pronouns?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-pronouns')
.setOptions([
{
@ -55,18 +54,18 @@ const survey = [
text: 'What are your interests/hobbies?',
textResponse: true,
id: 'survey-interests',
style: 'PARAGRAPH'
style: TextInputStyle.Paragraph
},
{
text: 'What do you see in this image?\nhttps://cdn.discordapp.com/attachments/789023763396165633/983471779060281364/unknown.png',
textResponse: true,
id: 'survey-image',
style: 'PARAGRAPH'
style: TextInputStyle.Paragraph
},
{
text: 'Which of the following game genres are you currently interested in?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-genre')
.setOptions([
{
@ -107,7 +106,7 @@ const survey = [
{
text: 'Which of these music artists do you listen to?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-artist')
.setOptions([
{
@ -135,14 +134,14 @@ const survey = [
{
text: 'Did you provide the correct time?',
components: [
new MessageButton().setCustomId('survey-time-correct-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-time-correct-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-time-correct-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-time-correct-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Favorite color?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-color2')
.setOptions([
{
@ -169,7 +168,7 @@ const survey = [
{
text: 'How many amperes have you had pushed into your heart at once in your lifetime?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-heart')
.setOptions([
{
@ -200,22 +199,22 @@ const survey = [
{
text: 'Are you afraid of the dark?',
components: [
new MessageButton().setCustomId('survey-dark-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-dark-no').setLabel('No').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-dark-maybe').setLabel('Maybe').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-dark-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-dark-no').setLabel('No').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-dark-maybe').setLabel('Maybe').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Which of these statements on morality do you most resonate with?\nA. Morality is a science which can be understood. There are inherent moral truths in the world.\nB. There does not exist a moral reality, but only perceptions on what is good or bad.',
components: [
new MessageButton().setCustomId('survey-morality-a').setLabel('A').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-morality-b').setLabel('B').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-morality-a').setLabel('A').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-morality-b').setLabel('B').setStyle(ButtonStyle.Primary)
]
},
{
text: 'How long ago did you last go on a bridge?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-bridge')
.setOptions(extendOptions(['A day ago', 'A week ago', 'A month ago', 'Several months ago', 'A year ago', 'Don\'t remember/Earlier']))
.setMinValues(1)
@ -225,7 +224,7 @@ const survey = [
{
text: 'Are you afraid of death?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-death')
.setOptions(extendOptions(['Yes', 'No', 'Maybe', 'Death is just a step to a different world']))
.setMinValues(1)
@ -241,14 +240,14 @@ const survey = [
{
text: 'You are operating a railroad track.\nA train is rapidly coming towards a track with 5 people strapped to the rails, unable to move. You are able to redirect the train onto another track, which has one person strapped to it. Do you make the switch and kill the one person, or do nothing and let the 5 people die?',
components: [
new MessageButton().setCustomId('survey-railroad1-switch').setLabel('Switch').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-railroad1-no').setLabel('Do not').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-railroad1-switch').setLabel('Switch').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-railroad1-no').setLabel('Do not').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Which region do you live in?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-region')
.setOptions(extendOptions(['Europe', 'Asia', 'North America', 'South America', 'Moscow River', 'Africa', 'Oceania']))
.setMinValues(1)
@ -258,7 +257,7 @@ const survey = [
{
text: 'Select the character you resonate with the most.',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-character')
.setOptions([
{
@ -288,7 +287,7 @@ const survey = [
{
text: 'Which of these statements describe you the best?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-statement')
.setOptions(extendOptions(['Is that a cut on your face, or part of your eye?', 'The gash weaves down as if you cry', 'The pain itself is reason why']))
.setMinValues(1)
@ -298,7 +297,7 @@ const survey = [
{
text: 'When was the last time you experienced a power surge?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-power-surge')
.setOptions(extendOptions(['A day ago', 'A week ago', 'A month ago', 'Several months ago', 'A year ago', 'Don\'t remember/Earlier']))
.setMinValues(1)
@ -308,14 +307,14 @@ const survey = [
{
text: 'Have you ever shown any interest in automobiles and cars?',
components: [
new MessageButton().setCustomId('survey-cars1-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-cars1-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-cars1-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-cars1-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'You are operating a railroad track.\nA person is strapped to the rails unable to move, however there is a fork right before that splits off to a different track with no people. Do you switch to save the person?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-railroad2')
.setOptions([
{
@ -335,29 +334,29 @@ const survey = [
{
text: 'Have you been here before?',
components: [
new MessageButton().setCustomId('survey-been-here-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-been-here-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-been-here-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-been-here-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Please provide your social media accounts.',
textResponse: true,
id: 'survey-socialmedia',
style: 'PARAGRAPH',
style: TextInputStyle.Paragraph,
placeholder: 'Twitter, YouTube, etc. Please provide as many as possible.'
},
{
text: 'Is your refrigerator running?',
components: [
new MessageButton().setCustomId('survey-fridge-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-fridge-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-fridge-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-fridge-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Do you generally feel unsafe in your life?',
noNumber: true,
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-unsafe')
.setOptions(extendOptions(['Yes', 'No', 'Sometimes']))
.setMinValues(1)
@ -367,7 +366,7 @@ const survey = [
{
text: 'train',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-train')
.setOptions(extendOptions(['Option 1', 'Option 2']))
.setMinValues(1)
@ -377,35 +376,35 @@ const survey = [
{
text: 'Do you live on planet Earth?',
components: [
new MessageButton().setCustomId('survey-earth-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-earth-no').setLabel('No').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-earth-maybe').setLabel('Maybe~ ;3').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-earth-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-earth-no').setLabel('No').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-earth-maybe').setLabel('Maybe~ ;3').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Do you own a credit or debit card?',
components: [
new MessageButton().setCustomId('survey-credit-card-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-credit-card-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-credit-card-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-credit-card-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'You are operating a railroad track.\nYou will be alone on your shift this night, with no one to watch, leaving you with a perfect opportunity to strap an explosive on one of the tracks. Do you cause a horrible accident resulting in the deaths of thousands?',
components: [
new MessageButton().setCustomId('survey-railroad3-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-railroad3-option-2').setLabel('Option 2').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-railroad3-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-railroad3-option-2').setLabel('Option 2').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Please click on the button when you\'re finished watching the video.\nhttps://www.youtube.com/watch?v=FsTCet79i2k',
components: [
new MessageButton().setCustomId('survey-finished').setLabel('Done').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-finished').setLabel('Done').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Which of these natural landmarks is your favorite?',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-landmark')
.setOptions(extendOptions(['Darvaza Gas Crater', 'Nazca Lines', 'Bermuda Triangle', 'The Hole']))
.setMinValues(1)
@ -415,34 +414,34 @@ const survey = [
{
text: 'Have you ever shown any interest in automobiles and cars?',
components: [
new MessageButton().setCustomId('survey-cars2-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-cars2-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-cars2-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-cars2-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Are you operating a railroad track?',
components: [
new MessageButton().setCustomId('survey-railroad4-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-railroad4-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-railroad4-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-railroad4-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Please explain why/why not.',
textResponse: true,
id: 'survey-railroad4-why',
style: 'PARAGRAPH'
style: TextInputStyle.Paragraph
},
{
text: 'Were you telling the truth in your previous 2 anwsers?',
components: [
new MessageButton().setCustomId('survey-railroad4-truth-yes').setLabel('Yes').setStyle('PRIMARY'),
new MessageButton().setCustomId('survey-railroad4-truth-no').setLabel('No').setStyle('PRIMARY')
new ButtonBuilder().setCustomId('survey-railroad4-truth-yes').setLabel('Yes').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId('survey-railroad4-truth-no').setLabel('No').setStyle(ButtonStyle.Primary)
]
},
{
text: 'Please rate your experience with this survey.',
components: [
new MessageSelectMenu()
new StringSelectMenuBuilder()
.setCustomId('survey-rating')
.setOptions(extendOptions(['1 ⭐', '2 ⭐⭐', '3 ⭐⭐⭐', '4 ⭐⭐⭐⭐', '5 ⭐⭐⭐⭐⭐']))
.setMinValues(1)
@ -454,41 +453,41 @@ const survey = [
noNumber: true,
textResponse: true,
id: 'survey-mycology',
style: 'PARAGRAPH'
style: TextInputStyle.Paragraph
},
{
text: 'You understand your role in this.',
noNumber: true,
components: [
new MessageButton().setCustomId('survey-closer5').setLabel('Yes, I understand.').setStyle('SUCCESS')
new ButtonBuilder().setCustomId('survey-closer5').setLabel('Yes, I understand.').setStyle(ButtonStyle.Success)
]
},
{
text: 'Do you like mushrooms as a concept?',
noNumber: true,
components: [
new MessageButton().setCustomId('survey-closer6').setLabel('Yes.').setStyle('SUCCESS')
new ButtonBuilder().setCustomId('survey-closer6').setLabel('Yes.').setStyle(ButtonStyle.Success)
]
},
{
text: 'Do you like how mushrooms grow and expand?',
noNumber: true,
components: [
new MessageButton().setCustomId('survey-closer7').setLabel('Yes.').setStyle('SUCCESS')
new ButtonBuilder().setCustomId('survey-closer7').setLabel('Yes.').setStyle(ButtonStyle.Success)
]
},
{
text: 'Would you become a stepping stone for mushrooms to grow and expand?',
noNumber: true,
components: [
new MessageButton().setCustomId('survey-closer8').setLabel('YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES').setStyle('SUCCESS')
new ButtonBuilder().setCustomId('survey-closer8').setLabel('YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES YES').setStyle(ButtonStyle.Success)
]
}
];
interface SurveyResponse {
id: string,
type: MessageComponentType,
type: ComponentType,
value: string | string[] | null,
values: string[] | null,
questionIndex: number,
@ -511,19 +510,19 @@ function pushResponse(resp: Partial<SurveyResponse>, userId: string) {
resp.questionText = question.text;
if (resp.values && question.components) {
const components = question.components as MessageSelectMenu[];
resp.questionOptions = components[0].options.map(o => o.label);
resp.values = resp.values.map(v => components[0].options.find(opt => opt.value === v)?.label || '');
const components = question.components as StringSelectMenuBuilder[];
resp.questionOptions = components[0].options.map(o => o.data.label!);
resp.values = resp.values.map(v => components[0].options.find(opt => opt.data.value! === v)?.data.label! || '');
if (components[0].maxValues === 1) {
if (components[0].data.max_values! === 1) {
resp.value = resp.values[0];
resp.values = undefined;
}
}
if (resp.type === 'BUTTON' && question.components) {
const components = question.components as MessageButton[];
resp.value = components.find(opt => opt.customId === resp.id)?.label;
resp.questionOptions = components.map(o => o?.label!);
if (resp.type === ComponentType.Button && question.components) {
const components = question.components as ButtonBuilder[];
resp.value = components.find(opt => (opt.data as APIButtonComponentWithCustomId).custom_id! === resp.id)?.data.label;
resp.questionOptions = components.map(o => o?.data.label!);
}
}
@ -568,9 +567,9 @@ async function advanceSurvey(userId: string, dontAdvanceProgress = false) {
(await interaction.client.channels.fetch(RESPONSES_CHANNEL) as TextChannel).send({
content: `Recieved a response from <@${userId}>`,
files: [filename],
components: [new MessageActionRow().addComponents(
new MessageButton().setLabel('Approve').setStyle('SUCCESS').setCustomId(`survey-reply-approve-${userId}`),
new MessageButton().setLabel('Deny').setStyle('DANGER').setCustomId(`survey-reply-deny-${userId}`))
components: [new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setLabel('Approve').setStyle(ButtonStyle.Success).setCustomId(`survey-reply-approve-${userId}`),
new ButtonBuilder().setLabel('Deny').setStyle(ButtonStyle.Danger).setCustomId(`survey-reply-deny-${userId}`))
]
});
await interaction.deferReply({
@ -583,15 +582,15 @@ async function advanceSurvey(userId: string, dontAdvanceProgress = false) {
resetProgress(userId);
} else {
let components: (MessageSelectMenu | MessageButton)[] = [];
let components: (StringSelectMenuBuilder | ButtonBuilder)[] = [];
if (question.components) components = question.components;
if (question.textResponse) components.push(
new MessageButton().setCustomId(question.id + '-modal').setLabel('Anwser').setStyle('PRIMARY')
new ButtonBuilder().setCustomId(question.id + '-modal').setLabel('Anwser').setStyle(ButtonStyle.Primary)
);
const msg = await interaction.reply({
content: `${question.noNumber ? '' : `${i}. `}${question.text!.split('\n')[0] === '' ? '' : `**${question.text!.split('\n')[0]}**`}\n${question.text!.split('\n').slice(1).join('\n')}`,
components: components ? ([new MessageActionRow().addComponents(...components)]) : undefined,
components: components ? ([new ActionRowBuilder<StringSelectMenuBuilder | ButtonBuilder>().addComponents(...components)]) : undefined,
ephemeral: ephemeral,
fetchReply: true
});
@ -606,8 +605,8 @@ module.exports = {
.setDescription('Re-create the survey button'),
execute: async (interaction: CommandInteraction) => {
const row = new MessageActionRow().addComponents(
new MessageButton().setCustomId('survey-take').setLabel('Take Survey').setStyle('SECONDARY')
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId('survey-take').setLabel('Take Survey').setStyle(ButtonStyle.Secondary)
);
await interaction.channel!.send({
@ -621,7 +620,7 @@ module.exports = {
},
onClientReady: (bot: Client) => {
bot.on('interactionCreate', async (interaction) => {
bot.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isMessageComponent()) return;
if (interaction.isModalSubmit()) return;
if (!interaction.customId.startsWith('survey-')) return;
@ -643,9 +642,11 @@ module.exports = {
const msg = interaction.message as Message;
await msg.edit({
content: msg.content,
components: [new MessageActionRow().addComponents(
new MessageButton().setCustomId('survey-reply-denied').setLabel(`${member.displayName} denied the application`).setStyle('DANGER').setDisabled(true)
)]
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId('survey-reply-denied').setLabel(`${member.displayName} denied the application`).setStyle(ButtonStyle.Danger).setDisabled(true)
)
]
});
} else {
(await interaction.guild?.members.fetch(id))!.roles.add(member.guild!.roles.cache.find(r => r.name === '✦')!);
@ -657,8 +658,8 @@ module.exports = {
const msg = interaction.message as Message;
await msg.edit({
content: msg.content,
components: [new MessageActionRow().addComponents(
new MessageButton().setCustomId('survey-reply-approved').setLabel(`${member.displayName} approved the application`).setStyle('SUCCESS').setDisabled(true)
components: [new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId('survey-reply-approved').setLabel(`${member.displayName} approved the application`).setStyle(ButtonStyle.Success).setDisabled(true)
)]
});
@ -697,25 +698,21 @@ module.exports = {
}
if (interaction.customId.endsWith('-modal')) {
const modal = new Modal()
const modal = new ModalBuilder()
.setCustomId(interaction.customId)
.setTitle('Fire Pit Survey');
const i = surveyProgress.get(member.id)!;
const question = survey[i];
const input = new TextInputComponent()
const input = new TextInputBuilder()
.setCustomId(question.id!)
.setLabel(question.text!.trim().split('\n')[0].slice(0, 44))
.setStyle((question.style as TextInputStyleResolvable) || 'SHORT')
.setStyle((question.style as TextInputStyle) || TextInputStyle.Short)
.setPlaceholder(question.placeholder || '')
.setRequired(true);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const row = new MessageActionRow().addComponents(input);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(input);
modal.addComponents(row);
interaction.showModal(modal);
} else {
@ -724,7 +721,7 @@ module.exports = {
const resp = {
id: interaction.customId,
type: interaction.componentType,
values: interaction.isSelectMenu() ? interaction.values : undefined
values: interaction.isStringSelectMenu() ? interaction.values : undefined
};
pushResponse(resp, member.id);
@ -732,7 +729,7 @@ module.exports = {
advanceSurvey(member.id);
}
});
bot.on('interactionCreate', interaction => {
bot.on(Events.InteractionCreate, interaction => {
if (!interaction.isModalSubmit()) return;
if (!interaction.member) return;
@ -747,7 +744,7 @@ module.exports = {
const i = surveyProgress.get(member.id)!;
const question = survey[i];
const field = interaction.fields.getField(question.id!);
const field = interaction.fields.getField(question.id!, ComponentType.TextInput);
const resp = {
id: field.customId,
@ -759,7 +756,7 @@ module.exports = {
advanceSurvey(member.id);
});
bot.on('messageCreate', msg => {
bot.on(Events.MessageCreate, msg => {
if (msg.channel.id !== SURVEY_CHANNEL) return;
if (msg.author.id === msg.client.user!.id) return;

View File

@ -1,25 +1,26 @@
import * as Discord from 'discord.js';
import { Client, GatewayIntentBits, Events, Collection, TextChannel } from 'discord.js';
import * as fs from 'fs';
const { token, disableDaytimeAnnouncements } = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
import * as path from 'path';
import { initializeCounter } from './lib/counter';
import { getNextAnnouncementTime, initializeAnnouncements, loadNext, loadSubscriptions, next, saveNext, subscriptions, timeAnnouncements } from './lib/subscriptions';
import { initializeAnnouncements, loadNext, loadSubscriptions } from './lib/subscriptions';
loadNext();
loadSubscriptions();
const bot = new Discord.Client({
const bot = new Client({
intents: [
Discord.Intents.FLAGS.GUILDS,
Discord.Intents.FLAGS.GUILD_MESSAGES,
Discord.Intents.FLAGS.GUILD_VOICE_STATES,
Discord.Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Discord.Intents.FLAGS.GUILD_MEMBERS,
Discord.Intents.FLAGS.DIRECT_MESSAGES
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.MessageContent,
GatewayIntentBits.DirectMessages
],
});
bot.on('ready', async () => {
bot.on(Events.ClientReady, async () => {
initializeCounter(false);
initializeCounter(true);
@ -27,7 +28,7 @@ bot.on('ready', async () => {
initializeAnnouncements(bot);
}
bot.commands = new Discord.Collection();
bot.commands = new Collection();
const cmdFiles = fs.readdirSync(path.join(__dirname, './commands')).filter((file) => file.endsWith('.js'));
for (const file of cmdFiles) {
const cmd = (await import(`./commands/${file}`));
@ -38,7 +39,7 @@ bot.on('ready', async () => {
console.log('jillo online');
});
bot.on('interactionCreate', async (interaction) => {
bot.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isCommand()) return;
const command = interaction.client.commands.get(interaction.commandName);
@ -52,8 +53,8 @@ bot.on('interactionCreate', async (interaction) => {
}
});
bot.on('messageDelete', (msg) => {
console.log(`${msg.author?.username}#${msg.author?.discriminator} in #${msg.channel instanceof Discord.TextChannel ? msg.channel.name : '?'} at ${msg.createdAt.toISOString()}`);
bot.on(Events.MessageDelete, (msg) => {
console.log(`${msg.author?.username}#${msg.author?.discriminator} in #${msg.channel instanceof TextChannel ? msg.channel.name : '?'} at ${msg.createdAt.toISOString()}`);
console.log(`${msg.content}`);
});

View File

@ -1,4 +1,4 @@
import { Client, CommandInteraction, GuildMember, MessageEmbed, TextChannel } from 'discord.js';
import { Client, CommandInteraction, GuildMember, EmbedBuilder, TextChannel } from 'discord.js';
import * as fsp from 'fs/promises';
import { exists, getSign } from './util';
@ -107,12 +107,17 @@ export async function updateCounter(bot: Client, cream: boolean) {
export async function announceCounterUpdate(bot: Client, member: GuildMember, delta: number, cream: boolean) {
const channel = await bot.channels.fetch(getChannel(cream)) as TextChannel;
const embed = new MessageEmbed()
.setAuthor(`${member.user.username}#${member.user.discriminator}`, member.user.displayAvatarURL())
const embed = new EmbedBuilder()
.setAuthor({
name: `${member.user.username}#${member.user.discriminator}`,
iconURL: member.user.displayAvatarURL()
})
.setDescription(`**${member.toString()}** has ${delta > 0 ? 'increased' : 'decreased'} the counter by **${Math.abs(delta)}**.`)
.setColor(member.displayColor)
.setTimestamp()
.setFooter(`[${getEmoji(cream)}] x${getCounter(cream)}`);
.setFooter({
text: `[${getEmoji(cream)}] x${getCounter(cream)}`
});
await channel.send({
embeds: [embed]