Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
bc497c7dea |
|||
|
d7b8e706b8 |
|||
|
7791fa5654 |
|||
|
9796e9245a |
|||
|
62b8ebb4cf |
|||
|
62fbb445e2 |
|||
|
1f48a896a5 |
|||
|
94d1b0f297 |
|||
|
cafcc007c1 |
|||
|
af4c42009c |
|||
|
f1f9e3aaa3 |
|||
|
4aaf72e4b4 |
|||
|
69872ba0d1 |
|||
|
7dab688298 |
|||
|
|
3ee2a80201 |
||
|
8655f279f9 |
|||
|
aa10d6bc27 |
|||
|
3d674f12e0 |
|||
|
0a8df28a94 |
|||
|
|
f78f4648d0 |
||
|
|
7f0029d9f9 |
||
|
|
681eca87e0 |
||
|
|
914aceeb44 |
||
|
|
dc7b49d255 |
||
|
|
c1d942e204 |
||
|
|
c53b707163 |
||
|
|
9dcc7adab4 |
13 changed files with 670 additions and 478 deletions
103
commands/info/mc.js
Normal file
103
commands/info/mc.js
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
// 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 user = message.guild.members.cache.get(info);
|
||||||
let guildPfp = user.avatarURL({format: 'png', dynamic: true, size: 4096});
|
let guildPfp = user.avatarURL({format: 'png', dynamic: true, size: 4096});
|
||||||
let globalPfp = user.user.avatarURL({format: 'png', dynamic: true, size: 4096});
|
let globalPfp = user.user.avatarURL({format: 'png', dynamic: true, size: 4096});
|
||||||
let sendText = `Global pfp:\n${globalPfp}`;
|
let sendText = `${globalPfp}`;
|
||||||
if(guildPfp != null){
|
if(guildPfp != null){
|
||||||
sendText = `${sendText}\nGuild pfp:\n${guildPfp}`;
|
sendText = `Global pfp${sendText}\nGuild pfp:\n${guildPfp}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.channel.send(sendText)
|
message.channel.send(sendText)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ module.exports = {
|
||||||
{name: "Server Name", value: message.guild.name, inline: false},
|
{name: "Server Name", value: message.guild.name, inline: false},
|
||||||
{name: "Created", value: convertDateToISOString(message.guild.createdAt), inline: false},
|
{name: "Created", value: convertDateToISOString(message.guild.createdAt), inline: false},
|
||||||
{name: "Members", value: message.guild.memberCount.toString(), inline: false},
|
{name: "Members", value: message.guild.memberCount.toString(), inline: false},
|
||||||
|
{name: "Channels", value: message.guild.channels.channelCountWithoutThreads.toString(), inline: false},
|
||||||
|
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -87,11 +87,13 @@ module.exports = {
|
||||||
if(sendText.embed != null){
|
if(sendText.embed != null){
|
||||||
let parse = parseMention(message.author.id, message.guild)
|
let parse = parseMention(message.author.id, message.guild)
|
||||||
let user = message.guild.members.cache.get(parse);
|
let user = message.guild.members.cache.get(parse);
|
||||||
|
if(!sendText.embed.data.color){
|
||||||
let roleColor = 15788778;
|
let roleColor = 15788778;
|
||||||
if (user.roles.color) {
|
if (user.roles.color) {
|
||||||
roleColor = user.roles.color.color;
|
roleColor = user.roles.color.color;
|
||||||
}
|
}
|
||||||
sendText.embed.setColor(roleColor);
|
sendText.embed.setColor(roleColor);
|
||||||
|
}
|
||||||
message.channel.send({embeds :[sendText.embed]})
|
message.channel.send({embeds :[sendText.embed]})
|
||||||
}else{
|
}else{
|
||||||
message.channel.send(sendText.text.replaceAll("<prefix>", prefix));
|
message.channel.send(sendText.text.replaceAll("<prefix>", prefix));
|
||||||
|
|
|
||||||
28
commands/misc/ig.js
Normal file
28
commands/misc/ig.js
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
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,6 +1,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'say',
|
name: 'say',
|
||||||
description: 'Repeats arguments',
|
description: 'Repeats arguments',
|
||||||
|
admin: true,
|
||||||
execute({message, args}) {
|
execute({message, args}) {
|
||||||
|
|
||||||
if(args.length == 0)
|
if(args.length == 0)
|
||||||
|
|
|
||||||
28
commands/misc/x.js
Normal file
28
commands/misc/x.js
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
906
package-lock.json
generated
906
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zuzak/owo": "^1.14.1",
|
"@zuzak/owo": "^1.14.1",
|
||||||
"discord.js": "^14.21.0",
|
"discord.js": "^14.21.0",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^17.2.1",
|
||||||
"seedrandom": "^3.0.5",
|
"seedrandom": "^3.0.5",
|
||||||
"sqlite3": "^5.1.6"
|
"sqlite3": "^5.1.6"
|
||||||
},
|
},
|
||||||
|
|
@ -21,6 +21,6 @@
|
||||||
"license": "UNLICENSE",
|
"license": "UNLICENSE",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"jest": "^30.0.3"
|
"jest": "^30.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,11 @@ const getNickname = require("../getNickname");
|
||||||
const parseMention = require("../parseMention");
|
const parseMention = require("../parseMention");
|
||||||
const getFmUsername = require("./getFmUsername");
|
const getFmUsername = require("./getFmUsername");
|
||||||
const {EmbedBuilder} = require('discord.js');
|
const {EmbedBuilder} = require('discord.js');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const { writeFile } = require('node:fs/promises')
|
||||||
|
const executeCommand = require('../executeCommand');
|
||||||
|
const { Readable } = require('node:stream')
|
||||||
|
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
module.exports = async function (userID, guild) {
|
module.exports = async function (userID, guild) {
|
||||||
|
|
@ -58,10 +63,22 @@ module.exports = async function (userID, guild) {
|
||||||
sendText.text = tracks.errorMsg;
|
sendText.text = tracks.errorMsg;
|
||||||
return sendText;
|
return sendText;
|
||||||
}
|
}
|
||||||
|
let coverDir = path.resolve(process.cwd(), 'data', 'covers');
|
||||||
|
let color = "#C27D0E"
|
||||||
|
const directory = path.resolve(coverDir, Math.floor(new Date).toString())
|
||||||
|
fs.mkdirSync(directory, {recursive: true})
|
||||||
|
const coverFile = path.resolve(directory, "cover")
|
||||||
|
let downloadResult = await downloadImage(tracks[0].cover, coverFile);
|
||||||
|
if(downloadResult.value === ERROR_CODES.SUCCESS){
|
||||||
|
const commandArgs = [`${coverFile}.${downloadResult.ext}`, "-resize", "1x1", "txt:-"]
|
||||||
|
let res = executeCommand("magick", commandArgs);
|
||||||
|
if(!res.error) color = res.output.split("\n")[1].split(" ")[3].slice(0,7);
|
||||||
|
|
||||||
|
}
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setAuthor({name: `Now playing - ${nickname}`, iconURL: user.user.avatarURL({ dynamic: true, size: 4096 })})
|
.setAuthor({name: `Now playing - ${nickname}`, iconURL: user.user.avatarURL({ dynamic: true, size: 4096 })})
|
||||||
.setThumbnail(tracks[0].cover)
|
.setThumbnail(tracks[0].cover)
|
||||||
.setColor(15780145)
|
.setColor(color)
|
||||||
.addFields({
|
.addFields({
|
||||||
name: `${isCurrentScrobble}:`, value: `${tracks[0].song}\n **${tracks[0].artist} • ** ${tracks[0].album}`
|
name: `${isCurrentScrobble}:`, value: `${tracks[0].song}\n **${tracks[0].artist} • ** ${tracks[0].album}`
|
||||||
},)
|
},)
|
||||||
|
|
@ -71,8 +88,31 @@ module.exports = async function (userID, guild) {
|
||||||
},)
|
},)
|
||||||
}
|
}
|
||||||
sendText.embed = embed;
|
sendText.embed = embed;
|
||||||
|
fs.rmSync(`${directory}`, {recursive: true})
|
||||||
} else {
|
} else {
|
||||||
sendText.text = "You haven't set your last.fm username yet. Use `<prefix>fm set <lastfm_username>` to set it.";
|
sendText.text = "You haven't set your last.fm username yet. Use `<prefix>fm set <lastfm_username>` to set it.";
|
||||||
}
|
}
|
||||||
return sendText;
|
return sendText;
|
||||||
}
|
}
|
||||||
|
const ERROR_CODES = {
|
||||||
|
SUCCESS: 0,
|
||||||
|
HTTP_ERROR: 1,
|
||||||
|
NOT_IMAGE: 2,
|
||||||
|
FETCH_ERROR: 3
|
||||||
|
}
|
||||||
|
async function downloadImage(url, downloadPath) {
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await fetch(url);
|
||||||
|
} catch (error) {
|
||||||
|
return {value: ERROR_CODES.FETCH_ERROR, errorMessage: error.cause?.message || error.message};
|
||||||
|
}
|
||||||
|
if(!res.ok) return {value: ERROR_CODES.HTTP_ERROR, errorMessage: res.status.toString()};
|
||||||
|
const contentType = res.headers.get('content-type');
|
||||||
|
|
||||||
|
if(!contentType || !contentType.startsWith("image")) return {value: ERROR_CODES.NOT_IMAGE, errorMessage: contentType || "No content-type header"};
|
||||||
|
const fileExt = contentType.split("/")[1]
|
||||||
|
const stream = Readable.fromWeb(res.body)
|
||||||
|
await writeFile(`${downloadPath}.${fileExt}`, stream);
|
||||||
|
return {value: ERROR_CODES.SUCCESS, errorMessage: "", ext: fileExt};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,8 @@ module.exports = async function (userID, option, guild, compatibility=false) {
|
||||||
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettopalbums&user=${lastfmUsername}&period=${option[0]}&api_key=${process.env.LAST_FM_API_KEY}&format=json`)
|
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettopalbums&user=${lastfmUsername}&period=${option[0]}&api_key=${process.env.LAST_FM_API_KEY}&format=json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
for(let i = 0; i < 10; i++){
|
const maxIterations = data.topalbums.album.length >= 10 ? 10 : data.topalbums.album.length;
|
||||||
|
for(let i = 0; i < maxIterations; i++){
|
||||||
let album = {}
|
let album = {}
|
||||||
let currentAlbum = data.topalbums.album[i];
|
let currentAlbum = data.topalbums.album[i];
|
||||||
album.artist = currentAlbum.artist.name;
|
album.artist = currentAlbum.artist.name;
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,8 @@ module.exports = async function (userID, option, guild, compatibility=false) {
|
||||||
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=${lastfmUsername}&period=${option[0]}&api_key=${process.env.LAST_FM_API_KEY}&format=json`)
|
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=${lastfmUsername}&period=${option[0]}&api_key=${process.env.LAST_FM_API_KEY}&format=json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
for(let i = 0; i < 10; i++){
|
const maxIterations = data.topartists.artist.length >= 10 ? 10 : data.topartists.artist.length;
|
||||||
|
for(let i = 0; i < maxIterations; i++){
|
||||||
let artist = {}
|
let artist = {}
|
||||||
let currentArtist = data.topartists.artist[i];
|
let currentArtist = data.topartists.artist[i];
|
||||||
artist.name = currentArtist.name;
|
artist.name = currentArtist.name;
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ module.exports = async function (userID, option, guild, compatibility=false) {
|
||||||
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettoptracks&user=${lastfmUsername}&period=${option[0]}&api_key=${apiKey}&format=json`)
|
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettoptracks&user=${lastfmUsername}&period=${option[0]}&api_key=${apiKey}&format=json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
for(let i = 0; i < 10; i++){
|
const maxIterations = data.toptracks.track.length >= 10 ? 10 : data.toptracks.track.length;
|
||||||
|
for(let i = 0; i < maxIterations; i++){
|
||||||
let track = {}
|
let track = {}
|
||||||
let currentTrack = data.toptracks.track[i];
|
let currentTrack = data.toptracks.track[i];
|
||||||
track.artist = currentTrack.artist.name;
|
track.artist = currentTrack.artist.name;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue