Skip to content

Commit

Permalink
feat: quoi feur (#52)
Browse files Browse the repository at this point in the history
Co-authored-by: Peïo Thibault <[email protected]>
Co-authored-by: Manu <[email protected]>
  • Loading branch information
3 people committed Jan 5, 2024
1 parent 60f7513 commit 5b58999
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 2 deletions.
12 changes: 10 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# SETUP
DISCORD_TOKEN=
DISCORD_CLIENT_ID=
DISCORD_GUILD_ID=
COOL_LINKS_CHANNEL_ID=

# DB
REDIS_URL=
PAGE_SUMMARIZER_BASE_URL=

# CHANNELS
BLABLA_CHANNEL_ID=
COOL_LINKS_CHANNEL_ID=

# API
PAGE_SUMMARIZER_BASE_URL=
1 change: 1 addition & 0 deletions src/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface Cache<Entries extends Record<string, any>> {
interface CacheEntries {
lobbyId: string;
channels: string[];
quoiFeurChannels: string[];
}

class CacheImpl implements Cache<CacheEntries> {
Expand Down
6 changes: 6 additions & 0 deletions src/helpers/regex.helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const socialNetworksUrlRegex = new RegExp(
'^(https?://)?(www.)?(facebook.com|fb.me|twitter.com|vxtwitter.com|instagram.com|linkedin.com|youtube.com|youtu.be|pinterest.com|snapchat.com|tiktok.com)/[a-zA-Z0-9.-/?=&#_]+$',
);
const punctuationRegex = /[.,!?]/g;
const emojiRegex = /(\p{Extended_Pictographic}|\p{Emoji_Component})/gu;

export const isASocialNetworkUrl = (url: string): boolean => {
return socialNetworksUrlRegex.test(url);
};

export const removePunctuation = (text: string) => text.replaceAll(punctuationRegex, '');
export const removeEmoji = (text: string) => text.replaceAll(emojiRegex, '');
2 changes: 2 additions & 0 deletions src/modules/modules.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { coolLinksManagement } from './coolLinksManagement/coolLinksManagement.module';
import { fart } from './fart/fart.module';
import { patternReplace } from './patternReplace/patternReplace.module';
import { quoiFeur } from './quoiFeur/quoiFeur.module';
import { voiceOnDemand } from './voiceOnDemand/voiceOnDemand.module';

export const modules = {
fart,
voiceOnDemand,
coolLinksManagement,
patternReplace,
quoiFeur,
};
126 changes: 126 additions & 0 deletions src/modules/quoiFeur/quoiFeur.helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
ChannelType,
type ChatInputCommandInteraction,
Client,
Guild,
type Message,
Role,
} from 'discord.js';

import { cache } from '../../core/cache';
import { removeEmoji, removePunctuation } from '../../helpers/regex.helper';

const ONE_MINUTE = 1 * 60 * 1000;
const MUTED_ON_COUBEH = 'Muted on Coubeh';

const quoiDetectorRegex = /\bquoi\s*$/i;
const endWithQuoi = (text: string) => quoiDetectorRegex.test(removeEmoji(removePunctuation(text)));

const reactWithFeur = async (message: Message) => {
await message.react('🇫');
await message.react('🇪');
await message.react('🇺');
await message.react('🇷');
};

const reactWithCoubeh = async (message: Message) => {
await message.react('🇨');
await message.react('🇴');
await message.react('🇺');
await message.react('🇧');
await message.react('🇪');
await message.react('🇭');
await message.react('🔇');

const mutedRole = message.guild?.roles.cache.find((r) => r.name === MUTED_ON_COUBEH);

if (!mutedRole?.id) return;

await message.member?.roles.add(mutedRole.id);

setTimeout(() => {
message.member?.roles.remove(mutedRole.id).catch(console.error);
}, ONE_MINUTE * 5);
};

export const reactOnEndWithQuoi = async (message: Message) => {
if (!endWithQuoi(message.content)) return;

const channelIds = await cache.get('quoiFeurChannels', []);
const channelHasGame = channelIds.find((channelId) => channelId === message.channelId);
if (!channelHasGame) return;

const probability = 1 / 20;

Math.random() <= probability ? await reactWithCoubeh(message) : await reactWithFeur(message);
};

export const createRoleMutedOnCoubeh = async (guild: Guild | null): Promise<Role> => {
if (!guild) {
throw new Error('Guild is null in createRoleMutedByBot');
}
const existingMutedByBot = guild.roles.cache.find((role) => role.name === MUTED_ON_COUBEH);

return (
existingMutedByBot ??
guild.roles.create({
name: MUTED_ON_COUBEH,
})
);
};

export const deleteRoleMutedOnCoubeh = async (client: Client<true>): Promise<void> => {
const guilds = await client.guilds.fetch().then((guilds) => guilds.map((guild) => guild.fetch()));
const roles = await Promise.all(guilds).then((guilds) =>
guilds.map((guild) => guild.roles.cache.find((role) => role.name === MUTED_ON_COUBEH)),
);

for (const role of roles) {
if (!role) continue;
await role.delete();
}
};

export const addQuoiFeurToChannel = async (interaction: ChatInputCommandInteraction) => {
const channel = interaction.channel;
if (!channel || !channel.isTextBased() || channel.type !== ChannelType.GuildText) return;

const channels = await cache.get('quoiFeurChannels', []);
if (channels.includes(channel.id)) {
await interaction.reply('Quoi-feur is already enabled in this channel');
return;
}

const role = await createRoleMutedOnCoubeh(interaction.guild);
await channel.permissionOverwrites.create(role, {
SendMessages: false,
CreatePublicThreads: false,
CreatePrivateThreads: false,
SendMessagesInThreads: false,
SendTTSMessages: false,
AttachFiles: false,
});
await cache.set('quoiFeurChannels', [...channels, channel.id]);
await interaction.reply('Quoi-feur enabled in this channel');
};

export const removeQuoiFeurFromChannel = async (interaction: ChatInputCommandInteraction) => {
const channel = interaction.channel;
if (!channel || !channel.isTextBased() || channel.type !== ChannelType.GuildText) return;

const channels = await cache.get('quoiFeurChannels', []);
if (!channels.includes(channel.id)) {
await interaction.reply('Quoi-feur is not enabled in this channel');
return;
}

const role = interaction.guild?.roles.cache.find((r) => r.name === MUTED_ON_COUBEH);
if (role) {
await channel.permissionOverwrites.delete(role);
}
await cache.set(
'quoiFeurChannels',
channels.filter((channelId) => channelId !== channel.id),
);
await interaction.reply('Quoi-feur disabled in this channel');
};
35 changes: 35 additions & 0 deletions src/modules/quoiFeur/quoiFeur.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { SlashCommandBuilder } from 'discord.js';

import type { BotModule } from '../../types/bot';
import {
addQuoiFeurToChannel,
deleteRoleMutedOnCoubeh,
reactOnEndWithQuoi,
removeQuoiFeurFromChannel,
} from './quoiFeur.helpers';

export const quoiFeur: BotModule = {
slashCommands: [
{
schema: new SlashCommandBuilder()
.setName('quoi-feur')
.setDescription('Manage quoi-feur game in the channel')
.addSubcommand((subcommand) =>
subcommand.setName('add').setDescription('Add the quoi-feur game to the channel'),
)
.addSubcommand((subcommand) =>
subcommand.setName('remove').setDescription('Remove the quoi-feur game from the channel'),
)
.toJSON(),
handler: {
add: addQuoiFeurToChannel,
remove: removeQuoiFeurFromChannel,
},
},
],
eventHandlers: {
// unmute everyone in every server on bot restart
ready: deleteRoleMutedOnCoubeh,
messageCreate: reactOnEndWithQuoi,
},
};

0 comments on commit 5b58999

Please sign in to comment.