Compare commits
42 changed files with 1503 additions and 3355 deletions
7
.github/workflows/CI.yml
vendored
7
.github/workflows/CI.yml
vendored
|
|
@ -2,9 +2,6 @@ name: CI
|
|||
|
||||
on: [push]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
CI:
|
||||
runs-on: node
|
||||
|
|
@ -16,6 +13,6 @@ jobs:
|
|||
with:
|
||||
node-version: 'latest'
|
||||
- name: install dependencies
|
||||
run: npm ci
|
||||
run: npm install
|
||||
- name: run tests
|
||||
run: npm test
|
||||
run: npm test
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
const savePresence = require("../../util/savePresence");
|
||||
const setPresence = require("../../util/setPresence");
|
||||
|
||||
module.exports = {
|
||||
|
|
@ -11,20 +10,12 @@ module.exports = {
|
|||
,"Updates once a minute if custom variables are used."
|
||||
,""
|
||||
,"Custom Variables:"
|
||||
,"${guilds},${prefix},${uptime},{members}"],
|
||||
,"${guilds},${prefix},${uptime}"],
|
||||
admin: true,
|
||||
execute({message, client, args, prefix}) {
|
||||
let forceUpdate = false;
|
||||
if(args.length > 1 && args[0] === "force") {
|
||||
forceUpdate = true;
|
||||
args.shift();
|
||||
}
|
||||
if(args.length < 1){
|
||||
message.channel.send(`You need at least two arguments for this command, see \`${prefix}help setpresence\``)
|
||||
return;
|
||||
}
|
||||
execute({message, client, args, globalPrefix}) {
|
||||
const savePresence = require("../../util/savePresence");
|
||||
let presenceType = args[0].toLocaleUpperCase();
|
||||
let sendText = "Presence has been set.";
|
||||
let sendText = "Updated presence";
|
||||
|
||||
switch (presenceType) {
|
||||
case "PLAY":
|
||||
|
|
@ -55,11 +46,8 @@ module.exports = {
|
|||
const firstArg = args[0].length + 1;
|
||||
let temp = args.join(" ");
|
||||
let presenceText = temp.slice(firstArg, temp.length)
|
||||
setPresence({presenceText: presenceText,presenceType: presenceType, client: client, globalPrefix: globalPrefix});
|
||||
savePresence(presenceType, presenceText, client);
|
||||
if(forceUpdate)
|
||||
setPresence({presenceText, presenceType, client})
|
||||
else
|
||||
sendText = `${sendText} It will update <t:${Math.floor((client.lastPresenceUpdate + 60000) / 1000)}:R>`
|
||||
}
|
||||
message.channel.send(sendText);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
const calculateReloaded = require("../../util/calculateReloaded");
|
||||
const executeCommand = require("../../util/executeCommand");
|
||||
const reloadCommands = require("../../util/reloadCommands");
|
||||
|
||||
module.exports = {
|
||||
|
|
@ -28,12 +27,10 @@ module.exports = {
|
|||
let commitCount = stdout.split(/\r\n|\r|\n/).length - 1
|
||||
sendText = `${sendText}\n\nLatest commits (${commitCount}):\n${stdout}`
|
||||
if(sendText.length >= 2000){
|
||||
sendText = sendText.slice(1955)
|
||||
sendText.slice(1955)
|
||||
sendText = `${sendText}\n... Message is too long to show everything`
|
||||
}
|
||||
message.channel.send(sendText)
|
||||
const githash = executeCommand(`git`, ["rev-parse", "--short", "HEAD"]);
|
||||
client.githash = githash.error ? "N/A" : githash.output;
|
||||
if (err) console.log(stderr)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
const sqlite3 = require('sqlite3').verbose();
|
||||
|
||||
module.exports = {
|
||||
name: 'whitelist',
|
||||
description: 'Whitelist a command in a specific server, or for a user.',
|
||||
admin: true,
|
||||
async execute({message, args, prefix, client}) {
|
||||
if(args.length < 3){
|
||||
message.channel.send(`You need to supply the command and guild that you want to whitelist\n\`${prefix}whitelist <user|guild> <command> <user_id|guild_id>\``);
|
||||
return;
|
||||
}
|
||||
let option = args[0];
|
||||
let command = args[1];
|
||||
let guildOrUser = args[2];
|
||||
|
||||
if(option === "guild" || option === "server"){
|
||||
if(guildOrUser === "this") guildOrUser = message.guild.id;
|
||||
const whitelistedCommands = client.whitelist.guild.get(guildOrUser);
|
||||
if(whitelistedCommands && whitelistedCommands.includes(command)){
|
||||
message.channel.send("Command is already whitelisted in that server.")
|
||||
return;
|
||||
}
|
||||
// TODO: First check if the bot has access to that guild before whitelisting.
|
||||
const databasePath = 'data/database.db'
|
||||
const db = new sqlite3.Database(databasePath)
|
||||
let err = false;
|
||||
await new Promise((resolve, reject)=>{
|
||||
db.run(`INSERT INTO guild_whitelist (
|
||||
guildId,
|
||||
command,
|
||||
dateAdded
|
||||
) VALUES (?, ?, ?)`,
|
||||
[
|
||||
guildOrUser,
|
||||
command,
|
||||
new Date().getTime()
|
||||
], function (error) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
err = true;
|
||||
resolve();
|
||||
}else{
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
db.close();
|
||||
if(!err){
|
||||
if(whitelistedCommands){
|
||||
whitelistedCommands.push(command);
|
||||
client.whitelist.guild.set(guildOrUser, whitelistedCommands);
|
||||
}else {
|
||||
client.whitelist.guild.set(guildOrUser, command);
|
||||
}
|
||||
message.channel.send(`"${command}" has been whitelisted in that server.`)
|
||||
|
||||
} else message.channel.send("Could not whitelist the server with that command. Check the logs.")
|
||||
return;
|
||||
}else if (option === "user"){
|
||||
const whitelistedCommands = client.whitelist.user.get(guildOrUser);
|
||||
if(whitelistedCommands && whitelistedCommands.includes(command)){
|
||||
message.channel.send("Command is already whitelisted for that user.")
|
||||
return;
|
||||
}
|
||||
const databasePath = 'data/database.db'
|
||||
const db = new sqlite3.Database(databasePath)
|
||||
let err = false;
|
||||
await new Promise((resolve, reject)=>{
|
||||
db.run(`INSERT INTO user_whitelist (
|
||||
userId,
|
||||
command,
|
||||
dateAdded
|
||||
) VALUES (?, ?, ?)`,
|
||||
[
|
||||
guildOrUser,
|
||||
command,
|
||||
new Date().getTime()
|
||||
], function (error) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
err = true;
|
||||
resolve();
|
||||
}else{
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
db.close();
|
||||
if(!err){
|
||||
if(whitelistedCommands){
|
||||
whitelistedCommands.push(command);
|
||||
client.whitelist.user.set(guildOrUser, whitelistedCommands);
|
||||
}else {
|
||||
client.whitelist.user.set(guildOrUser, command);
|
||||
}
|
||||
message.channel.send(`"${command}" has been whitelisted for ${guildOrUser}.`)
|
||||
|
||||
} else message.channel.send("Could not whitelist the server with that command. Check the logs.")
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: Add ability to remove server from whitelist.
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
const {EmbedBuilder} = require('discord.js');
|
||||
const getCreationDate = require('../../util/getCreationDate');
|
||||
const getGuildInfo = require('../../util/getGuildInfo');
|
||||
const getGuildCount = require('../../util/getGuildCount');
|
||||
|
||||
|
||||
|
||||
|
|
@ -8,28 +8,15 @@ module.exports = {
|
|||
name: 'botinfo',
|
||||
description: 'Shows information about the bot',
|
||||
execute({message, client, prefix}) {
|
||||
let guildInfo = getGuildInfo(client)
|
||||
let descriptionArr = [`Name: ${client.user.username}`,
|
||||
`Prefix: ${prefix}`,
|
||||
`Total Servers: ${guildInfo.guildCount}`,
|
||||
`Total Members: ${guildInfo.totalMembers} (${guildInfo.uniqueMemberCount} unique)`,
|
||||
`Total Commands: ${client.commands.size}`,
|
||||
`Creation Date: ${getCreationDate(client)}`,
|
||||
`Source: [Click Here](https://github.com/SileNce5k/discord_bot)`,
|
||||
`Current Version: ${client.githash}`
|
||||
]
|
||||
|
||||
let description = "";
|
||||
descriptionArr.forEach(desc => {
|
||||
description += `${desc}\n`;
|
||||
})
|
||||
|
||||
let guildCount = getGuildCount(client)
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(15780145)
|
||||
.setTitle("Information about bot")
|
||||
.setTimestamp()
|
||||
.setAuthor({name: client.user.username, iconURL: client.user.avatarURL({ format: 'png', dynamic: true, size: 2048 })})
|
||||
.setDescription(description)
|
||||
.addFields({
|
||||
name: "General info", value: `Name: ${client.user.username}\nPrefix: ${prefix}\nTotal Servers: ${guildCount}\nTotal Commands: ${client.commands.size}\nCreation Date: ${getCreationDate(client)}\nSource: [Click Here](https://github.com/SileNce5k/discord_bot)`,
|
||||
},)
|
||||
|
||||
message.channel.send({embeds :[embed]})
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ module.exports = {
|
|||
description: 'Returns guild names',
|
||||
admin: true,
|
||||
execute({message, client}) {
|
||||
let guildNames = client.guilds.cache
|
||||
.sort((a, b) => b.memberCount - a.memberCount)
|
||||
.map(guild => `${guild.name} (${guild.memberCount} members)`)
|
||||
.join("\n");
|
||||
let guildNames = "";
|
||||
client.guilds.cache.each(guild => {
|
||||
guildNames = guildNames + guild.name + "\n";
|
||||
});
|
||||
message.channel.send(guildNames)
|
||||
}
|
||||
};
|
||||
|
|
@ -13,6 +13,7 @@ module.exports = {
|
|||
execute({ message, args, prefix, client }) {
|
||||
let commands = ""
|
||||
let commandFiles = getSubdirFiles('commands/')
|
||||
let x = false;
|
||||
let fieldName = `Page [[page]]/${Math.round(client.commands.size / 10)}`;
|
||||
let iteration = 0;
|
||||
let num_in_args = false;
|
||||
|
|
@ -31,6 +32,7 @@ module.exports = {
|
|||
fieldName = fieldName.replace("[[page]]", page);
|
||||
const max_commands = iteration + 10;
|
||||
|
||||
if (x) return;
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(15780145)
|
||||
|
|
@ -58,7 +60,6 @@ module.exports = {
|
|||
start++;
|
||||
}
|
||||
}else if(args[0] === command.name){
|
||||
fieldName = "Description";
|
||||
commands = commands + `${prefix}${command.name}\n`
|
||||
embed.setTitle(command.name.charAt(0).toUpperCase() + command.name.slice(1))
|
||||
if(command.moreHelp){
|
||||
|
|
@ -66,6 +67,7 @@ module.exports = {
|
|||
commands = commands + `${element}\n`
|
||||
});
|
||||
} else {
|
||||
fieldName = "Description";
|
||||
commands = commands + `${command.description}`;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
// Code is taken from https://github.com/stphnduvall/mcstatus/blob/master/src/index.ts
|
||||
// and converted to pure js.
|
||||
|
||||
const net = require('net')
|
||||
const { EmbedBuilder } = require('discord.js');
|
||||
|
||||
module.exports = {
|
||||
name: 'mc',
|
||||
description: 'get minecraft server information',
|
||||
hidden: true,
|
||||
needsWhitelist: true,
|
||||
async execute({ message, args }) {
|
||||
let host = "";
|
||||
let port = 25565;
|
||||
if (args[0]) host = args[0];
|
||||
|
||||
if (host.includes(":")) {
|
||||
port = host.replace(/.+(?:\:)/g, "");
|
||||
host = host.match(/.+(?:\:)/g, "")[0].replace(":", "");
|
||||
}
|
||||
if(host === "") return message.channel.send("No host provided")
|
||||
let info = await getMinecraftServerInfo(host, port);
|
||||
if (info) {
|
||||
const embed = new EmbedBuilder()
|
||||
embed.setColor("#ee7939")
|
||||
embed.setTimestamp()
|
||||
embed.addFields(
|
||||
{ name: "ping", value: info.ping.toString(), inline: false },
|
||||
{ name: "Player Count", value: info.playercount.toString(), inline: false },
|
||||
{ name: "Max Players", value: info.maxPlayers.toString(), inline: false },
|
||||
{ name: "MOTD", value: info.motd, inline: false },
|
||||
)
|
||||
|
||||
message.channel.send({ embeds: [embed] });
|
||||
} else {
|
||||
message.channel.send("Something went wrong\nThe minecraft server is likely not reachable from the discord bot")
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
async function getMinecraftServerInfo(host, port = 25565) {
|
||||
let serverInfo = {
|
||||
ping: undefined,
|
||||
maxPlayers: undefined,
|
||||
version: undefined,
|
||||
playercount: undefined,
|
||||
motd: undefined
|
||||
}
|
||||
|
||||
let startTime = new Date();
|
||||
let data;
|
||||
let ping;
|
||||
serverInfo = await new Promise((resolve) => {
|
||||
const client = net.connect({ host, port }, () => {
|
||||
ping = Math.round(new Date().getMilliseconds() - startTime.getMilliseconds());
|
||||
|
||||
let buff = Buffer.from([0xFE, 0x01]);
|
||||
client.write(buff);
|
||||
|
||||
})
|
||||
let error = false;
|
||||
client.on('data', (d) => {
|
||||
data = d.toString()
|
||||
client.destroy();
|
||||
|
||||
})
|
||||
client.once('error', (error) => {
|
||||
console.error(error)
|
||||
error = true;
|
||||
})
|
||||
client.once('connectionAttemptFailed', (ip) => {
|
||||
console.error("in attempt failed")
|
||||
error = true;
|
||||
})
|
||||
|
||||
client.once('connectionAttemptTimeout', (ip) => {
|
||||
console.error("in attempt timeout")
|
||||
error = true;
|
||||
})
|
||||
client.on('close', () => {
|
||||
if (!error) {
|
||||
let _serverInfo = data?.split('\x00\x00\x00');
|
||||
|
||||
if (!_serverInfo) {
|
||||
console.log("Something went wrong.")
|
||||
resolve(serverInfo)
|
||||
}
|
||||
serverInfo.version = _serverInfo[2].replace(/\u0000/g, '')
|
||||
serverInfo.motd = _serverInfo[3].replace(/\u0000/g, '')
|
||||
serverInfo.playercount = Number(_serverInfo[4].replace(/\u0000/g, ''))
|
||||
serverInfo.maxPlayers = Number(_serverInfo[5].replace(/\u0000/g, ''))
|
||||
serverInfo.ping = Number(ping)
|
||||
resolve(serverInfo)
|
||||
} else {
|
||||
resolve(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
return serverInfo
|
||||
}
|
||||
|
|
@ -16,9 +16,9 @@ module.exports = {
|
|||
let user = message.guild.members.cache.get(info);
|
||||
let guildPfp = user.avatarURL({format: 'png', dynamic: true, size: 4096});
|
||||
let globalPfp = user.user.avatarURL({format: 'png', dynamic: true, size: 4096});
|
||||
let sendText = `${globalPfp}`;
|
||||
let sendText = `Global pfp:\n${globalPfp}`;
|
||||
if(guildPfp != null){
|
||||
sendText = `Global pfp${sendText}\nGuild pfp:\n${guildPfp}`;
|
||||
sendText = `${sendText}\nGuild pfp:\n${guildPfp}`;
|
||||
}
|
||||
|
||||
message.channel.send(sendText)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ module.exports = {
|
|||
{name: "Server Name", value: message.guild.name, inline: false},
|
||||
{name: "Created", value: convertDateToISOString(message.guild.createdAt), inline: false},
|
||||
{name: "Members", value: message.guild.memberCount.toString(), inline: false},
|
||||
{name: "Channels", value: message.guild.channels.channelCountWithoutThreads.toString(), inline: false},
|
||||
|
||||
|
||||
])
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs')
|
||||
|
||||
const executeCommand = require('../../util/executeCommand');
|
||||
module.exports = {
|
||||
name: 'dl',
|
||||
description: 'Download a video',
|
||||
moreHelp: [
|
||||
"Usage: <prefix>dl <url>"
|
||||
],
|
||||
async execute({message, args}) {
|
||||
const downloadsDir = path.resolve(process.cwd(), 'data', 'downloads', Date.now().toString());
|
||||
const cookieFilepath = path.resolve(process.cwd(), 'data', 'cookies.txt')
|
||||
if(!fs.existsSync(cookieFilepath)) {
|
||||
message.channel.send("Some dependencies are needed for the command to work properly. Please let the bot's owner know.")
|
||||
return;
|
||||
}
|
||||
fs.mkdirSync(downloadsDir, {recursive: true});
|
||||
|
||||
let url;
|
||||
|
||||
if(args.length > 0){
|
||||
if(args[0].charAt(0) === '<' && args[0].charAt(args[0].length - 1) === '>'){
|
||||
args[0] = args[0].slice(1, args[0].length - 1)
|
||||
}
|
||||
try {
|
||||
url = new URL(args[0]);
|
||||
url = url.href;
|
||||
} catch (error) {
|
||||
this.cleanUp(downloadsDir);
|
||||
message.channel.send("Could not parse the provided argument as a URL.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.cleanUp(downloadsDir);
|
||||
return message.channel.send("You have to provide a URL in an argument.")
|
||||
}
|
||||
|
||||
const originalMessage = await message.channel.send("Downloading video...")
|
||||
|
||||
if(executeCommand("yt-dlp", [url, "-P", downloadsDir, "--cookies", cookieFilepath]).error){
|
||||
originalMessage.edit("An error occurred when downloading the video.");
|
||||
this.cleanUp(downloadsDir);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let files = fs.readdirSync(downloadsDir);
|
||||
if(files.length < 1) {
|
||||
this.cleanUp(downloadsDir);
|
||||
originalMessage.edit("Something went wrong when downloading the video.")
|
||||
return;
|
||||
}
|
||||
const filename = files[0];
|
||||
|
||||
await originalMessage.edit({
|
||||
content: null,
|
||||
files: [{
|
||||
attachment: path.resolve(downloadsDir, filename)
|
||||
}]})
|
||||
|
||||
this.cleanUp(downloadsDir);
|
||||
|
||||
|
||||
},
|
||||
|
||||
cleanUp(downloadsDir){
|
||||
fs.rmSync(downloadsDir, {force: true, recursive: true});
|
||||
},
|
||||
|
||||
}
|
||||
|
|
@ -4,12 +4,6 @@ const getCurrentCover = require("../../util/lastfm/getCurrentCover");
|
|||
const getTopTracks = require("../../util/lastfm/getTopTracks");
|
||||
const help = require("../info/help");
|
||||
const parseMention = require("../../util/parseMention");
|
||||
const roast = require("../../util/lastfm/roast");
|
||||
const getTopArtists = require("../../util/lastfm/getTopArtists");
|
||||
const getTopAlbums = require("../../util/lastfm/getTopAlbums");
|
||||
const {EmbedBuilder} = require('discord.js');
|
||||
const getNickname = require('../../util/getNickname');
|
||||
const isWhitelisted = require("../../util/isWhitelisted");
|
||||
module.exports = {
|
||||
name: 'fm',
|
||||
description: 'Last fm commands. See `<prefix>help fm` for more info.',
|
||||
|
|
@ -17,11 +11,8 @@ module.exports = {
|
|||
"They behave the same (for example: `<prefix>fmtt` and `<prefix>fm tt`)",
|
||||
"Set username: `<prefix>fmset <lastfm_username>`",
|
||||
"Get current scrobble: `<prefix>fm`",
|
||||
"Get top artists `<prefix>fmas`",
|
||||
"Get top albums: `<prefix>fmabl`",
|
||||
"Get top tracks: `<prefix>fmtt`",
|
||||
"Get album cover for current scrobble: `<prefix>fmcover`",
|
||||
"Get a roast from an LLM using your top artists and albums: `<prefix>fmroast`"
|
||||
],
|
||||
async execute({ message, args, prefix, client }) {
|
||||
let sendText = {text: "Something went wrong.", embed: null};
|
||||
|
|
@ -37,46 +28,9 @@ module.exports = {
|
|||
args.shift();
|
||||
sendText = await getTopTracks(message.author.id, args, message.guild);
|
||||
break;
|
||||
case "topalbums":
|
||||
case "topalbum":
|
||||
case "abl":
|
||||
args.shift();
|
||||
sendText = await getTopAlbums(message.author.id, args, message.guild)
|
||||
break;
|
||||
case "topartists":
|
||||
case "topartist":
|
||||
case "ta":
|
||||
case "as":
|
||||
args.shift();
|
||||
sendText = await getTopArtists(message.author.id, args, message.guild);
|
||||
break;
|
||||
case "cover":
|
||||
sendText = await getCurrentCover(message.author.id, message.guild);
|
||||
break;
|
||||
case "roast":
|
||||
const commandName = "fmroast"
|
||||
if(!isWhitelisted.isWhitelisted(commandName, client.whitelist, message.guild.id, message.author.id, isWhitelisted.whitelistTypes.EITHER)) {
|
||||
message.channel.send("fmroast has not been whitelisted for you or this server.")
|
||||
return;
|
||||
}
|
||||
let topArtists = await getTopArtists(message.author.id, ["yearly"], message.guild, true);
|
||||
let topAlbums = await getTopAlbums(message.author.id, ["yearly"], message.guild, true);
|
||||
message.channel.sendTyping();
|
||||
let result = await roast(topArtists, topAlbums);
|
||||
|
||||
let parse = parseMention(message.author.id, message.guild)
|
||||
let user = message.guild.members.cache.get(parse);
|
||||
let nickname = getNickname(user, message.guild)
|
||||
if (nickname == null) {
|
||||
nickname = user.user.username;
|
||||
}
|
||||
const possesive = nickname.at(nickname.length - 1) === "s" ? "'" : "'s"
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: `${nickname}${possesive} AI roast`, iconURL: user.user.avatarURL({ dynamic: true, size: 4096 })})
|
||||
.setColor(15780145)
|
||||
.setDescription(result);
|
||||
sendText.embed = embed;
|
||||
break;
|
||||
default:
|
||||
sendText.text = `${args[0]} is not a valid subcommand.\nSee \`${prefix}help fm\` for more info.`;
|
||||
break;
|
||||
|
|
@ -87,16 +41,14 @@ module.exports = {
|
|||
if(sendText.embed != null){
|
||||
let parse = parseMention(message.author.id, message.guild)
|
||||
let user = message.guild.members.cache.get(parse);
|
||||
if(!sendText.embed.data.color){
|
||||
let roleColor = 15788778;
|
||||
if (user.roles.color) {
|
||||
roleColor = user.roles.color.color;
|
||||
}
|
||||
sendText.embed.setColor(roleColor);
|
||||
let roleColor = 15788778;
|
||||
if (user.roles.color) {
|
||||
roleColor = user.roles.color.color;
|
||||
}
|
||||
sendText.embed.setColor(roleColor);
|
||||
message.channel.send({embeds :[sendText.embed]})
|
||||
}else{
|
||||
message.channel.send(sendText.text.replaceAll("<prefix>", prefix));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
module.exports = {
|
||||
name: 'ig',
|
||||
description: 'Replaces Instagram links with kkinstagram and deletes the original message',
|
||||
execute({message, args}) {
|
||||
const noUrlErr = "You need to provide an Instagram link to use this command."
|
||||
if(args.length < 1) {
|
||||
message.channel.send(noUrlErr);
|
||||
return;
|
||||
}
|
||||
let replacedLink = "";
|
||||
const regex = /(?<=\/)(instagram)\.com/g
|
||||
if(args[0].startsWith("https://") || args[0].startsWith("http://")){
|
||||
replacedLink = args[0].replace(regex, "kkinstagram.com");
|
||||
}
|
||||
if(replacedLink.length === 0 || args[0] === replacedLink){
|
||||
message.channel.send(noUrlErr);
|
||||
return;
|
||||
}
|
||||
message.channel.send(replacedLink);
|
||||
try{
|
||||
message.delete()
|
||||
}catch(err){
|
||||
console.error(`${this.name}: An error occurred while trying to delete the original message.`)
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
module.exports = {
|
||||
name: 'ping',
|
||||
description: 'Just ping.',
|
||||
async execute({message, client}) {
|
||||
let apiLatency = client.ws.ping;
|
||||
const time = process.hrtime.bigint();
|
||||
let initialMessage = await message.channel.send(`Pong.`)
|
||||
const diff = Number(process.hrtime.bigint() - time) * 1e-6;
|
||||
initialMessage.edit(`Pong.\nAPI latency: ${apiLatency} ms\nMessage latency: ${diff.toFixed(0)} ms.`);
|
||||
execute({message, client}) {
|
||||
message.channel.send(`Pong.\n${client.ws.ping}ms`)
|
||||
}
|
||||
};
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
const setServerPrefix = require("../../util/setServerPrefix");
|
||||
const { PermissionsBitField } = require('discord.js');
|
||||
|
||||
module.exports = {
|
||||
name: 'prefix',
|
||||
description: 'Change the prefix of the bot in this server.',
|
||||
execute({ message, client, args, prefix }) {
|
||||
if (!message.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) {
|
||||
if (!message.member.permissions.has('MANAGE_GUILD')) {
|
||||
message.channel.send("You do not have sufficient permissions(MANAGE_GUILD) to change the prefix of this server.")
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
module.exports = {
|
||||
name: 'say',
|
||||
description: 'Repeats arguments',
|
||||
admin: true,
|
||||
execute({message, args}) {
|
||||
|
||||
if(args.length == 0)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,16 @@
|
|||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { writeFile } = require('node:fs/promises')
|
||||
const { Readable } = require('node:stream')
|
||||
const executeCommand = require('../../util/executeCommand');
|
||||
|
||||
|
||||
module.exports = {
|
||||
name: 'tdoss',
|
||||
description: 'Combine picture with tdoss album cover template',
|
||||
async execute({ message, args }) {
|
||||
|
||||
let tdossDir = path.resolve(process.cwd(), 'data', 'tdoss');
|
||||
const tdossTemplate = path.resolve(process.cwd(), 'resources', 'tdoss_template.png');
|
||||
|
||||
const directory = path.resolve(tdossDir, Math.floor(new Date).toString())
|
||||
fs.mkdirSync(directory, {recursive: true})
|
||||
let dataDir = path.resolve(__dirname, '..', '..', 'data');
|
||||
const directory = path.resolve(dataDir, Math.floor(new Date).toString())
|
||||
fs.mkdirSync(directory)
|
||||
|
||||
let url = "";
|
||||
if(message.attachments.size > 0){
|
||||
|
|
@ -25,43 +21,30 @@ module.exports = {
|
|||
url = args[0];
|
||||
}else if(message.reference){
|
||||
let referencedMessage = await message.fetchReference();
|
||||
if(referencedMessage.attachments.size > 0){
|
||||
if(referencedMessage.attachments.size > 0)
|
||||
url = await referencedMessage.attachments.first().url;
|
||||
}
|
||||
else {
|
||||
message.channel.send("The message you replied to doesn't have any attachments.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let lastMessages = await message.channel.messages.fetch({limit: 20, cache: false});
|
||||
let lastMessageWithAttachment = lastMessages.find(m => m.attachments.size > 0);
|
||||
if(!lastMessageWithAttachment){
|
||||
message.channel.send("Couldn't find an image to use this command on.")
|
||||
fs.rmSync(`${directory}`, {recursive: true})
|
||||
return
|
||||
}
|
||||
url = lastMessageWithAttachment.attachments.first().url;
|
||||
|
||||
message.channel.send("You have to provide an image to use this command.\nEither via an attachment or via a link (must be the first argument and start with https://)")
|
||||
fs.rmSync(`${directory}`, {recursive: true})
|
||||
return
|
||||
}
|
||||
// TODO: Download with correct extension.
|
||||
message.channel.sendTyping();
|
||||
let downloadResult = await this.downloadImage(url, path.resolve(directory, "input.png"));
|
||||
if(downloadResult.value != this.ERROR_CODES.SUCCESS){
|
||||
if(downloadResult.value === this.ERROR_CODES.FETCH_ERROR){
|
||||
message.channel.send(`Failed to download the provided image, got error '${downloadResult.errorMessage}'`);
|
||||
}else if (downloadResult.value === this.ERROR_CODES.HTTP_ERROR){
|
||||
message.channel.send(`Failed to download the provided image, got response status '${downloadResult.errorMessage}'`);
|
||||
}else if(downloadResult.value === this.ERROR_CODES.NOT_IMAGE){
|
||||
message.channel.send(`The provided url was not an image.`)
|
||||
}
|
||||
const curlCommand = `curl "${url}" -o ${directory}/input.png`;
|
||||
|
||||
if (this.executeCommand(curlCommand).error === true) {
|
||||
message.channel.send("Something went wrong during the download.\nTry again and if it keeps happening, contact the owner of the bot.")
|
||||
fs.rmSync(`${directory}`, {recursive: true})
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const commandArgs = [tdossTemplate, "(", `${directory}/input.png`, "-resize", "800x800^", "-gravity", "center", "-extent", "1000x1000", ")", "-compose", "dst-over", "-composite", `${directory}/tdoss_result.png`]
|
||||
if (executeCommand("magick", commandArgs).error === true) {
|
||||
const command = `magick ${dataDir}/tdoss_template.png \\( ${directory}/input.png -resize 800x800^ -gravity center -extent 1000x1000 \\) -compose dst-over -composite ${directory}/tdoss_result.png`;
|
||||
if (this.executeCommand(command).error === true) {
|
||||
message.channel.send("Something went wrong during image manipulation.\nTry again and if it keeps happening, contact the owner of the bot.")
|
||||
fs.rmSync(`${directory}`, {recursive: true})
|
||||
return
|
||||
|
|
@ -75,26 +58,21 @@ module.exports = {
|
|||
await message.channel.send({files: [final_image]})
|
||||
fs.rmSync(`${directory}`, {recursive: true})
|
||||
},
|
||||
// https://stackoverflow.com/a/77210219
|
||||
async downloadImage(url, path) {
|
||||
let res;
|
||||
|
||||
|
||||
executeCommand(command) {
|
||||
console.log("Executing:", command)
|
||||
try {
|
||||
res = await fetch(url);
|
||||
const output = execSync(command, { encoding: 'utf-8' })
|
||||
if (output.length != 0)
|
||||
console.log(output)
|
||||
} catch (error) {
|
||||
return {value: this.ERROR_CODES.FETCH_ERROR, errorMessage: error.cause?.message || error.message};
|
||||
console.error(`Error executing ${command.split(" ")[0]} command:`, error);
|
||||
return { error: true };
|
||||
}
|
||||
if(!res.ok) return {value: this.ERROR_CODES.HTTP_ERROR, errorMessage: res.status.toString()};
|
||||
const contentType = res.headers.get('content-type');
|
||||
if(!contentType || !contentType.startsWith("image")) return {value: this.ERROR_CODES.NOT_IMAGE, errorMessage: contentType || "No content-type header"};
|
||||
const stream = Readable.fromWeb(res.body)
|
||||
await writeFile(path, stream);
|
||||
return {value: this.ERROR_CODES.SUCCESS, errorMessage: ""};
|
||||
},
|
||||
ERROR_CODES: {
|
||||
SUCCESS: 0,
|
||||
HTTP_ERROR: 1,
|
||||
NOT_IMAGE: 2,
|
||||
FETCH_ERROR: 3
|
||||
return { error: false };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ const parseTime = require('../../util/timer/parseTime');
|
|||
const showTimer = require('../../util/timer/showTimer');
|
||||
module.exports = {
|
||||
name: "timer",
|
||||
description: "Set a timer for a date or time duration.",
|
||||
description: "Set a timer for a time in minutes.",
|
||||
moreHelp: ["Usage:"
|
||||
,"`<prefix>timer [add|create] <time_in_minutes> <message_to_send>`"
|
||||
,"`<prefix>timer <time>(d|h|m|s|t) <message_to_send>`"
|
||||
,"`<prefix>timer <future_date> <message_to_send>`"
|
||||
,"`<prefix>timer <time_in_minutes> <message_to_send>`"
|
||||
,"`<prefix>timer edit <timer_id> <new_time_in_minutes> <new_message_to_send>` (not implemented)"
|
||||
,"`<prefix>timer [delete|remove] <timer_id>`"
|
||||
,"`<prefix>timer show <timer_id>`"
|
||||
|
|
@ -18,8 +18,7 @@ module.exports = {
|
|||
switch (args[0]) {
|
||||
case "add":
|
||||
case "create":
|
||||
args.shift()
|
||||
sendText = await createTimer(message, args);
|
||||
sendText = await createTimer(message, args, false);
|
||||
break;
|
||||
case "edit":
|
||||
sendText = "not implemented yet"
|
||||
|
|
@ -38,8 +37,8 @@ module.exports = {
|
|||
sendText = "Please specify a time, and a message to send after the timer has finished";
|
||||
break;
|
||||
}
|
||||
if(!isNaN(parseTime(args[0], Math.floor(new Date() / 1000))) || !isNaN(Date.parse(args[0])))
|
||||
sendText = await createTimer(message, args);
|
||||
if(!isNaN(parseTime(args[0], Math.floor(new Date() / 1000))))
|
||||
sendText = await createTimer(message, args, true);
|
||||
break;
|
||||
}
|
||||
message.channel.send(sendText);
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
module.exports = {
|
||||
name: 'x',
|
||||
description: 'Replaces X/Twitter links with fxtwitter and deletes the original message',
|
||||
execute({message, args}) {
|
||||
const noUrlErr = "You need to provide an X or twitter link to use this command."
|
||||
if(args.length < 1) {
|
||||
message.channel.send(noUrlErr);
|
||||
return;
|
||||
}
|
||||
let replacedLink = "";
|
||||
const regex = /(?<=\/)(x|twitter)\.com/g
|
||||
if(args[0].startsWith("https://") || args[0].startsWith("http://")){
|
||||
replacedLink = args[0].replace(regex, "fxtwitter.com");
|
||||
}
|
||||
if(replacedLink.length === 0 || args[0] === replacedLink){
|
||||
message.channel.send(noUrlErr);
|
||||
return;
|
||||
}
|
||||
message.channel.send(replacedLink);
|
||||
try{
|
||||
message.delete()
|
||||
}catch(err){
|
||||
console.error(`${this.name}: An error occurred while trying to delete the original message.`)
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
3585
package-lock.json
generated
3585
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue