the first commit

This commit is contained in:
adrianvic 2023-09-21 14:51:06 -03:00
commit d5920470cc
18 changed files with 1887 additions and 0 deletions

24
LICENSE.txt Normal file
View file

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

1
README.md Normal file
View file

@ -0,0 +1 @@
# Haruma

25
commands/bot/about.js Normal file
View file

@ -0,0 +1,25 @@
const { SlashCommandBuilder } = require('discord.js');
const { EmbedBuilder } = require('discord.js');
const fs = require('fs');
module.exports = {
data: new SlashCommandBuilder()
.setName(`about`)
.setDescription(`About the bot`),
async execute(interaction) {
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
const botAvatarURL = interaction.client.user.displayAvatarURL();
// Create an embed with the app name, version, and codename from package.json
const responseEmbed = new EmbedBuilder()
.setTitle(`${packageJson.name} *${packageJson.codename}*\n(${packageJson.version}) `)
.setThumbnail(botAvatarURL)
.setDescription(`I'm ${packageJson.name}, click me on the command menu to see what I can do.`)
.setFooter({ text: 'Originally made by 天くま (tenkuma) - Thanks for keeping the credits ;)' });
// interaction.reply() to reply with a ephemeral message
await interaction.reply({ embeds: [responseEmbed], ephemeral: true });
},
};

12
commands/bot/ping.js Normal file
View file

@ -0,0 +1,12 @@
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute(interaction) {
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
await interaction.reply(`Pong, ${nickname}!`);
},
};

50
commands/misc/lyrics.js Normal file
View file

@ -0,0 +1,50 @@
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { getLyrics } = require('genius-lyrics-api') ;
module.exports = {
data: new SlashCommandBuilder()
.setName('lyrics')
.setDescription('Search for song lyrics')
.addStringOption(option =>
option.setName('artist')
.setDescription('Artist name')
.setRequired(true))
.addStringOption(option =>
option.setName('title')
.setDescription('Song title')
.setRequired(true)),
async execute(interaction) {
const artist = interaction.options.getString('artist');
const title = interaction.options.getString('title');
// Ephemeral message saying the bot is thinking
await interaction.deferReply();
// Use getLyrics to get the lyrics
try {
const lyrics = await getLyrics({
apiKey: 'yourGeniusAPIKey', // Change to your Genius key
title: title,
artist: artist,
});
if (lyrics) {
// Embed with the lyrics
const { EmbedBuilder } = require('discord.js');
const embed = new EmbedBuilder()
.setAuthor({ name: artist })
.setTitle(title)
.setDescription(lyrics)
.setFooter({text : 'Made with Genius API'})
// Send the embed
await interaction.followUp({ content: 'Here is the lyric:', ephemeral: false, embeds: [embed] });
} else {
await interaction.followUp('Could not find the lyric.');
}
} catch (error) {
console.error('Error while searching for the lyric:', error);
await interaction.followUp('Error while searching for the lyric.');
}
},
};

31
commands/misc/myname.js Normal file
View file

@ -0,0 +1,31 @@
const { SlashCommandBuilder, ChannelType } = require(`discord.js`)
const { EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName(`myname`)
.setDescription(`Change your nickname`)
.addStringOption(option =>
option.setName('name')
.setDescription('What is your new nickname?')
.setRequired(true)),
async execute(interaction) {
const nick = interaction.options.getString(`name`)
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
if (interaction.guild) {
try {
await interaction.member.setNickname(nick);
interaction.reply({ content: `Your new nickname is **${nickname}**!`, ephemeral: true });
} catch (error) {
console.error(error);
interaction.reply({ content: `Something went wrong`, ephemeral: true });
}
} else {
interaction.reply({ content: 'Try this in a server', ephemeral: true });
}
},
}

74
commands/mod/ban.js Normal file
View file

@ -0,0 +1,74 @@
const { SlashCommandBuilder } = require('discord.js');
const { EmbedBuilder } = require('discord.js');
const { PermissionsBitField } = require('discord.js')
module.exports = {
data: new SlashCommandBuilder()
.setName('remove')
.setDescription('Remove/Ban someone from this server')
.addBooleanOption(option =>
option.setName('silent')
.setDescription('Only you will see the command result')
.setRequired(true))
.addStringOption(option =>
option.setName('type')
.setRequired(true)
.addChoices(
{ name: 'Kick', value: 'kick' },
{ name: 'Ban', value: 'ban' },
))
.addUserOption(option =>
option.setName('user')
.setDescription('User to remove')
.setRequired(true))
.addStringOption(option =>
option.setName('reason')
.setDescription('Removal reason')
.setMaxLength(500)
.setRequired(false)),
async execute(interaction) {
const banned = interaction.options.getUser('user');
const reason = interaction.options.getString('reason');
const type = interaction.options.getString('type');
const silent = interaction.options.getBoolean('silent');
const banEmbed = new EmbedBuilder();
if (type === 'ban') {
banEmbed.setTitle(`${banned.username} was banned`);
if (reason) {
banEmbed.setDescription(`Reason: ${reason}`);
}
}
else (type === 'kick')
{
banEmbed.setTitle(`${banned.username} was removed`);
if (reason) {
banEmbed.setDescription(`Reason: ${reason}`);
}
}
if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) {
return interaction.reply({ content: `Wait! You does not have enough permissions...`, ephemeral: true });
}
try {
if (type === 'ban') {
await interaction.guild.members.ban(banned, { reason });
} else if (type === 'kick') {
await interaction.guild.members.kick(banned, { reason });
}
interaction.reply({ embeds: [banEmbed], ephemeral: silent });
} catch (error) {
console.error(error);
// Check for specific error code '50013' (Missing Permissions)
if (error.code === 50013) {
interaction.reply({ content: `Strange... I do not have enough permissions (API 50013).`, ephemeral: true });
} else {
interaction.reply({ content: `There was an error while processing the action. (API ${error.code})`, ephemeral: true });
}
}
},
};

41
commands/mod/nuke.js Normal file
View file

@ -0,0 +1,41 @@
const { SlashCommandBuilder } = require('discord.js');
const { PermissionsBitField } = require('discord.js')
module.exports = {
data: new SlashCommandBuilder()
.setName('nuke')
.setDescription('Delete messages')
.addIntegerOption(option =>
option.setName('number')
.setDescription('How many messages?')
.setMaxValue(50)
.setMinValue(1)
.setRequired(true)),
async execute(interaction) {
const number = interaction.options.getInteger('number');
try {
// Check permissions
if (
!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)
) {
return await interaction.reply({ content: 'Error: missing permissions', ephemeral: true });
}
// Defer the action
await interaction.deferReply({ ephemeral: false });
// Delete the messages
await interaction.channel.bulkDelete(number);
// Delay
await new Promise(resolve => setTimeout(resolve, 8000));
// Answer
await interaction.followUp({ content: `${number} messages were deleted`});
} catch (error) {
console.error(error);
await interaction.followUp({ content: 'Unknown error.', ephemeral: true });
}
}
}

View file

@ -0,0 +1,24 @@
const { SlashCommandBuilder, ChannelType } = require(`discord.js`);
const { EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName(`die`)
.setDescription(`You die in roleplay`)
.addStringOption(option =>
option.setName('reason')
.setDescription('Why?')
.setMaxLength(256)
.setRequired(true)),
async execute(interaction) {
const why = interaction.options.getString('reason')
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
const responseEmbed = new EmbedBuilder()
.setTitle(`${nickname} died...`)
.setDescription("..." + why)
interaction.reply({ embeds: [responseEmbed] });
},
}

View file

@ -0,0 +1,30 @@
const { SlashCommandBuilder, ChannelType } = require(`discord.js`)
const { EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName(`do`)
.setDescription(`Indicates an action in roleplay`)
.addStringOption(option =>
option.setName('what')
.setDescription('What you gonna do?')
.setMaxLength(256)
.setRequired(true))
.addStringOption(option =>
option.setName('extra')
.setDescription('Describe the action')
.setMaxLength(4000)),
async execute(interaction) {
const action = interaction.options.getString('what')
const desc = interaction.options.getString(`extra`)
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
const responseEmbed = new EmbedBuilder()
.setTitle(`${nickname} ` + action + "...")
.setFooter({ text: `No one was killed or died` })
if (desc != null) {responseEmbed.setDescription("..." + desc)};
interaction.reply({ embeds: [responseEmbed] });
},
}

View file

@ -0,0 +1,27 @@
const { SlashCommandBuilder, ChannelType } = require(`discord.js`)
const { EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName(`go`)
.setDescription(`Go to a channel in roleplay`)
.addChannelOption(option =>
option.setName('channel')
.setDescription('Where you wanna go?')
.setRequired(true)),
async execute(interaction) {
const chan = interaction.options.getChannel(`channel`)
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
const exitEmbed = new EmbedBuilder()
.setAuthor({ name: nickname })
.setDescription(`Went to <#${chan.id}>`)
const cameEmbed = new EmbedBuilder()
.setAuthor({ name: nickname })
.setDescription(`Came from <#${chan.id}>`)
interaction.reply({ embeds: [exitEmbed] });
chan.send({ embeds: [cameEmbed] });
},
}

View file

@ -0,0 +1,28 @@
const { SlashCommandBuilder, ChannelType } = require(`discord.js`)
const { EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName(`kill`)
.setDescription(`Kill someone in roleplay`)
.addUserOption(option =>
option.setName('who')
.setRequired(true))
.addStringOption(option =>
option.setName('reason')
.setDescription('How?')
.setMaxLength(4000)
.setRequired(true)),
async execute(interaction) {
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
const dead = interaction.options.getUser('who')
const desc = interaction.options.getString(`reason`)
const responseEmbed = new EmbedBuilder()
.setTitle(`${nickname} killed someone:`)
.setDescription(`<@${dead.id}> died ${desc}`)
interaction.reply({ embeds: [responseEmbed] });
},
}

View file

@ -0,0 +1,22 @@
const { SlashCommandBuilder, ChannelType } = require(`discord.js`)
const { EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName(`t`)
.setDescription(`Indicates a thought in roleplay`)
.addStringOption(option =>
option.setName('what')
.setRequired(true)),
async execute(interaction) {
const desc = interaction.options.getString(`what`)
const member = interaction.guild.members.cache.get(interaction.user.id);
const nickname = member.nickname;
const responseEmbed = new EmbedBuilder()
.setTitle(`${nickname} is thinking:`)
.setDescription(desc)
interaction.reply({ embeds: [responseEmbed] });
},
}

5
config.js Normal file
View file

@ -0,0 +1,5 @@
module.exports = {
token: 'YOUR TOKEN GOES HERE',
clientId: 'YOUR CLIENT ID GOES HERE',
guildId: 'YOUR GUILD GOES HERE'
};

47
deploy-commands.js Normal file
View file

@ -0,0 +1,47 @@
const { REST, Routes } = require('discord.js');
const { clientId, guildId, token } = require('./config.js');
const fs = require('node:fs');
const path = require('node:path');
const commands = [];
// Grab all the command files from the commands directory you created earlier
const foldersPath = path.join(__dirname, 'commands');
const commandFolders = fs.readdirSync(foldersPath);
for (const folder of commandFolders) {
// Grab all the command files from the commands directory you created earlier
const commandsPath = path.join(foldersPath, folder);
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
if ('data' in command && 'execute' in command) {
commands.push(command.data.toJSON());
} else {
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
}
// Construct and prepare an instance of the REST module
const rest = new REST().setToken(token);
// and deploy your commands!
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands in the guild with the current set (change guild to your guild id)
// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(
Routes.applicationGuildCommands(clientId, guildId),
{ body: commands },
);
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();

174
index.js Normal file
View file

@ -0,0 +1,174 @@
// Importing stuff
const fs = require('node:fs');
const path = require('node:path');
const { Client, Collection, Events, GatewayIntentBits, ActivityType } = require('discord.js');
// Defines client
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMembers,
]
})
// Load the commands
console.log("[STARTUP] Loading commands")
client.commands = new Collection();
const foldersPath = path.join(__dirname, 'commands');
const commandFolders = fs.readdirSync(foldersPath);
for (const folder of commandFolders) {
const commandsPath = path.join(foldersPath, folder);
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
// Set a new item in the Collection with the key as the command name and the value as the exported module
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
} else {
console.log(`[COMMANDS] The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
console.log("[STARTUP] Finished loading commands")
}
// Adds the message to the log when the bot starts
client.on ('ready', () => {
console.log('[STARTUP] The bot is on!')
})
// Get any message
client.on('messageCreate', message => {
if (message.author.bot) {
return;
}
// Check if it's something you want to reply and replies
if (message.content.toLowerCase().includes('theFirstWord') || message.content.toLowerCase().includes('theSecondWord') && message.content.toLowerCase().includes('fofa')) {
message.reply('^v-v^');
}
// Get slash command
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
// Command = command name
const command = interaction.client.commands.get(interaction.commandName);
// If there's no command matching the user input log an error
if (!command) {
console.error(`[ERR] No command matching ${interaction.commandName} was found.`);
return;
}
// Try to execute the given command
try {
await command.execute(interaction);
} catch (error) {
console.error(error);
}
});
// Automatically changes the activity to something you want
const activities_list = [
// The song list (you can delete this and change to anything you want
"Blackout by Breathe Carolina",
"I.D.G.A.F by Breathe Carolina",
"MTC by S3RL",
"Pika Girl by S3RL",
"Everytime We Touch by Cascada",
"Because The Night by Cascada",
"Bad Boy by Cascada",
"Chemical by Breathe Carolina",
"União Flasco by Luckhaos",
"Polaroid by YunLi",
"Wooly by Breathe Carolina",
"That's Classy by Breathe Carolina",
"O Funeral Da Irônia by Luckhaos",
"Sakura by YunLi",
"Será by YunLi",
"Pudim Amassado by Gato Galáctico",
"Quem Quer Subir by MC V.V",
"The Pretender by Foo Fighters",
"WIFI by Breathe Carolina",
"With or Without You by Breathe Carolina",
"With or Without You by U2",
"Good Feeling by Flo Rida",
"Walking With Angels by The Autobiography",
"Coca Zero by YunLi",
"We're All The Pirate Bay (Hybrid Remix) by Montt Mardie",
"How Do You Do by Boom",
"Dog Nightmare by Jack Stauber",
"Buttercup bu Jack Stauber",
"Baby Hotline by Jack Stauber",
"To Your Beat by S3RL",
"Better Off Alone by S3RL",
"Make Me Wanna by S3RL", // 1
"L'amour Toujour by Gigi D'agostino",
"C'est Beau La Bourgueoise by Discobitch",
"Bla Bla Bla by Gigi D'agostino",
"Discord by The Living Tombstones",
"Eu não faço sad songs, faço desabafos by D$ Luqi",
"Lucid Dreams by Juice WRLD",
"Moonlight by XXXTentacion",
"Falling Down (Feat. XXXTentacion) by Lil Peep",
"Save This by Lil Peep",
"I Wonder by Kayne West",
"All The Girls Are The Same by Juice WRLD",
"Wishing Well by Juice World",
"Legends Never Die by League Of Legends",
"Phoenix by League Of Legends",
"Let Me Die by Lil Happy Lil Sad",
"She Was My Universe by DempseyRollBoy",
"In My Bones by Sadgods",
"Call Me Maybe by Carly Rae Jespen",
"Maps by Maroon 5",
"Memories by Maroon 5",
"I Don't Wanna Know by Maroon 5",
"Sugar by Maroon 5",
"Girls Like You by Maroon 5",
"Misery by Maroon 5",
"This Love by Maroon 5",
"One More Night by Maroon 5",
"She Will Be Loved by Maroon 5",
"Moves Like Jagger by Maroon 5",
"Animals by Maroon 5",
"One & Only by Oliver Tree",
"Miss You by Oliver Tree",
"Thnks Fr Th Mmrs by Fall Out Boy",
"Centuries by Fall Out Boy",
"Valsa by YunLi",
"Glória Aos Avestruzes by Amdré Young",
"Sono Que Eu Perdi (Demo) by YunLi",
"Acabou by YunLi",
"Saudades Eu Até Sinto (Demo) by YunLi",
"Dói Demais (Demo) by YunLi",
"Playback (Demo) by YunLi",
"Lista De Favoritos (Demo) by YunLi",
"Sprinter Trueno by YunLi",
];
client.on('ready', () => {
// Sets the first status
console.log("[STARTUP] Setting up statuses")
const index = Math.floor(Math.random() * (activities_list.length - 1) + 1); // // Random number between 1 and the length of the array .
client.user.setActivity(activities_list[index], { type: ActivityType.Listening }); // sets bot's activities to one of the phrases in the arraylist.
console.log("[STARTUP] Setting the first random status")
// Changes the status after some time
setInterval(() => {
const index = Math.floor(Math.random() * (activities_list.length - 1) + 1); // Random number between 1 and the length of the array .
client.user.setActivity(activities_list[index], { type: ActivityType.Listening }); // Set the activity from the random number, you can isolate this to change to anything you want
// Change type to any other ActivityType you want
// Log the change
console.log("[LOG] Changing activity")
}, 200000);
});
// Log the bot in (put your token on config.js if you`re getting any error
client.config = require('./config');
client.login(client.config.token);

1249
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

23
package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "haruma",
"version": "2.4.0",
"description": "A Discord bot to help you with roleplay",
"main": "index.js",
"codename": "Pandora",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"discord",
"bot",
"roleplay"
],
"author": "tenkuma.",
"license": "MIT",
"dependencies": {
"discord.js": "^14.13.0",
"dotenv": "^16.3.1",
"genius-lyrics-api": "^3.2.0",
"node-fetch": "^3.3.2"
}
}