Skip to content

Commit

Permalink
2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
BluDood committed Oct 27, 2022
0 parents commit f955cea
Show file tree
Hide file tree
Showing 38 changed files with 1,786 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
package-lock.json
old/
databases/*
config.json
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# BluBot

A self-hosted Discord bot with various moderation features and fun commands. Features a simple CLI and setup script for easy management.

## Features

- Automatic moderation
- Censor list (deprecated by Discord AutoMod?)
- Phish protection (powered by phish.sinking.yachts)
- Moderation
- Ban, kick, timeout members
- Purge messages by channel and/or user
- Lock channels
- Logging
- Any moderation action
- Deleted and edited messages
- Automatic moderation actions
- Misc
- Get user avatar
- Define a word using Urban Dictionary
- Neofetch-like status command
- Ping command
- Your Mom jokes (powered by yomomma.info)
- Setup
- Guided setup with customization options
- CLI
- Simple CLI with ASCII art and uptime command (more coming soon)

## Setup

0. Install NodeJS
1. Clone this repository
2. Run `npm run setup` and follow the steps
3. Run `npm install` to install dependencies
4. Run `npm start` to start the bot

## Screenshots

### Direct Messages

![](assets/dms.png)

### Logs

![](assets/logs.png)

### Neofetch command (Discord ANSI support)

![](assets/neofetch.png)

### CLI

![](assets/cli.png)

## Support

Want to request a new feature or report a bug?

[Join my Discord Server](https://blnk.ga/dc)
or
[send me an email](mailto:[email protected])!
Binary file added assets/cli.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/dms.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/neofetch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions commands/avatar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { SlashCommandBuilder } = require('@discordjs/builders')
const {
customization: { accent }
} = require('../config.json')

module.exports = {
data: new SlashCommandBuilder()
.setName('avatar')
.setDescription("Get your or another user's avatar")
.addUserOption(option =>
option.setName('target').setDescription('User to show avatar for')
),
async execute(interaction) {
const user = interaction.options.getUser('target') || interaction.user
const avatar = format => user.avatarURL({ format })
interaction.reply({
embeds: [
{
title: `${user.username}'s avatar`,
description: `Download as [png](${avatar('png')}), [jpeg](${avatar(
'jpeg'
)}) or [webp](${avatar('webp')}).`,
color: accent,
image: {
url: avatar('png')
}
}
]
})
}
}
76 changes: 76 additions & 0 deletions commands/ban.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { SlashCommandBuilder } = require('@discordjs/builders')
const {
customization: { accent }
} = require('../config.json')
const checkUserPerms = require('../utils/checkUserPerms')
const directMessage = require('../utils/directMessage')
const log = require('../utils/log')

module.exports = {
data: new SlashCommandBuilder()
.setName('ban')
.setDescription('Ban a member.')
.addUserOption(option =>
option.setName('target').setDescription('User to ban').setRequired(true)
)
.addStringOption(option =>
option.setName('reason').setDescription('Reason for the ban')
)
.addNumberOption(option =>
option.setName('deletedays').setDescription('Days to delete messages')
),
async execute(interaction) {
if (!checkUserPerms(interaction))
return interaction.reply({
content: 'You do not have permission to do that!',
ephemeral: true
})
const target = interaction.options.getUser('target')
const reason = interaction.options.getString('reason') || 'N/A'
const days = interaction.options.getNumber('deletedays') || 0
const member = await interaction.guild.members
.fetch({ user: target, force: true })
.catch(() => null)
if (!member)
return interaction.reply({
content: "I can't find that user!",
ephemeral: true
})
if (!member.bannable)
return interaction.reply({
content: "I can't ban that user!",
ephemeral: true
})
await interaction.reply({
embeds: [
{
title: `${target.tag} banned.`,
color: accent
}
],
ephemeral: true
})
const dm = await directMessage(interaction.guild, target, 'ban', {
reason,
moderator: {
id: interaction.user.id
}
})
if (!dm)
await interaction.followUp({
content: 'I could not message that user!',
ephemeral: true
})
await member.ban(target, { days: days, reason: reason })
log(interaction.guild, 'ban', {
target: {
id: target.id,
tag: target.tag
},
moderator: {
id: interaction.user.id
},
reason
})
}
}
93 changes: 93 additions & 0 deletions commands/censor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const { SlashCommandBuilder } = require('@discordjs/builders')
const {
customization: { accent }
} = require('../config.json')
const fs = require('fs')
const checkUserPerms = require('../utils/checkUserPerms')

module.exports = {
data: new SlashCommandBuilder()
.setName('censor')
.setDescription('Configure censored words')
.addSubcommand(subcommand =>
subcommand
.setName('add')
.setDescription('Add a censored word')
.addStringOption(option =>
option
.setName('word')
.setDescription('The word to censor')
.setRequired(true)
)
)
.addSubcommand(subcommand =>
subcommand
.setName('remove')
.setDescription('Remove a censored word')
.addStringOption(option =>
option
.setName('word')
.setDescription('The word to remove')
.setRequired(true)
)
)
.addSubcommand(subcommand =>
subcommand.setName('list').setDescription('List all censored words')
),
async execute(interaction) {
const word = interaction.options.getString('word')?.toLowerCase()
if (!checkUserPerms(interaction))
return interaction.reply({
content: 'You do not have permission to do that!',
ephemeral: true
})

if (interaction.options.getSubcommand() === 'add') {
const censored = JSON.parse(fs.readFileSync('./databases/censored.json'))
if (censored.map(c => c.word).includes(word))
return await interaction.reply({
content: 'This word is already censored!',
ephemeral: true
})
censored.push({
user: interaction.user.id,
word
})
fs.writeFileSync('./databases/censored.json', JSON.stringify(censored))
await interaction.reply({
content: `Censored the word ${word}!`,
ephemeral: true
})
} else if (interaction.options.getSubcommand() === 'remove') {
const censored = JSON.parse(fs.readFileSync('./databases/censored.json'))
const found = censored.find(c => c.word === word)
if (!found)
return await interaction.reply({
content: 'This word is not censored!',
ephemeral: true
})
const index = censored.indexOf(found)
censored.splice(index, 1)
fs.writeFileSync('./databases/censored.json', JSON.stringify(censored))
await interaction.reply({
content: `Removed censor for the word ${word}!`,
ephemeral: true
})
} else if (interaction.options.getSubcommand() === 'list') {
const censored = JSON.parse(fs.readFileSync('./databases/censored.json'))
await interaction.reply({
embeds: [
{
title: 'Censored words',
color: accent,
fields: censored.map(c => ({
name: c.word,
value: `Added by <@${c.user}>`
}))
}
],
ephemeral: true
})
} else return interaction.reply('Invalid option.')
}
}
30 changes: 30 additions & 0 deletions commands/checkPerms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { SlashCommandBuilder } = require('@discordjs/builders')
const {
customization: { accent }
} = require('../config.json')
const checkUserPerms = require('../utils/checkUserPerms')

module.exports = {
data: new SlashCommandBuilder()
.setName('check')
.setDescription('Check if are allowed to moderate using this bot.'),
async execute(interaction) {
if (checkUserPerms(interaction))
return interaction.reply({
embeds: [
{
title: `You are allowed to moderate using this bot!`,
color: accent
}
]
})
return interaction.reply({
embeds: [
{
title: `You are not allowed to moderate using this bot.`,
color: accent
}
]
})
}
}
38 changes: 38 additions & 0 deletions commands/define.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const { SlashCommandBuilder } = require('@discordjs/builders')
const {
customization: { accent }
} = require('../config.json')
const axios = require('axios').default

module.exports = {
data: new SlashCommandBuilder()
.setName('define')
.setDescription('Define a word with Urban Dictionary!')
.addStringOption(option =>
option
.setName('query')
.setDescription('Word to search for')
.setRequired(true)
),
async execute(interaction) {
// my api ;)
const api = 'https://urbanapi.up.railway.app'
const query = interaction.options.getString('query')
interaction.deferReply()
const res = await axios
.get(`${api}/define/${query}`, {
validateStatus: false
})
.catch(() => null)
if (!res?.data?.success)
return interaction.editReply('An error has occured!')
if (res.status === 404)
return interaction.editReply('Could not find that word!')
const embed = {
color: accent,
title: res.data.result[0].word,
description: res.data.result[0].description
}
return interaction.editReply({ embeds: [embed] })
}
}
Loading

0 comments on commit f955cea

Please sign in to comment.