forked from Elijah/AudioBot
313 lines
10 KiB
JavaScript
313 lines
10 KiB
JavaScript
|
// This is the old version of the bot, written by DarkOK, and is kept here for archival purposes.
|
||
|
// It no longer works due to discord api changes, hence the rewrite.
|
||
|
|
||
|
|
||
|
const Discord = require('discord.js-v11'); // update this you lazy prick and rewrite the bot
|
||
|
const client = new Discord.Client();
|
||
|
const {execSync, exec, spawnSync, spawn} = require('child_process');
|
||
|
|
||
|
var token = ""; // token used for authentication to discord
|
||
|
|
||
|
var ownerIds = []; // user ids of people that can eval, change servers to non-whitelisted ones, etc
|
||
|
|
||
|
var pf = "cvm!"; // command prefix
|
||
|
var vncServers = [
|
||
|
"localhost:5900"
|
||
|
]; // servers that appears in the list, and ones that people don't need admin to switch to (first item in array is default server)
|
||
|
// (if this is public, keep this as the one (Hm i should really make all VMs use one broadcast for all servers to fix this))
|
||
|
|
||
|
// dont modify
|
||
|
var vncServer = vncServers[0];
|
||
|
var vncName = "";
|
||
|
|
||
|
// especially dont modify these
|
||
|
var arecord;
|
||
|
var broadcast;
|
||
|
var bp={txt:"",type:"",status:""};
|
||
|
|
||
|
function changeStatus(txt, type, status) {
|
||
|
bp.txt = txt;
|
||
|
bp.type = type ? type : "LISTENING";
|
||
|
bp.status = status ? status : "online";
|
||
|
|
||
|
if (bp.txt != txt || bp.type != type || bp.status != status) {
|
||
|
client.user.setPresence({
|
||
|
activity: {
|
||
|
name: pf + "help" + " | " + bp.txt,
|
||
|
type: bp.type
|
||
|
},
|
||
|
status: bp.status
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
function startStream() {
|
||
|
console.log("Connecting to " + vncServer);
|
||
|
|
||
|
changeStatus("Connecting");
|
||
|
|
||
|
exec("./name " + vncServer, (error, stdout, stderr) => {
|
||
|
if (error) {
|
||
|
//vncName = "Failed to get VM name";
|
||
|
console.log("Error getting VM name: " + error.message);
|
||
|
} else {
|
||
|
vncName = stdout;
|
||
|
console.log("VNC name: " + vncName);
|
||
|
changeStatus(vncName);
|
||
|
};
|
||
|
});
|
||
|
|
||
|
arecord = spawn('./audio', [vncServer]);
|
||
|
|
||
|
arecord.stderr.setEncoding("utf8");
|
||
|
arecord.stderr.on("data", data => {
|
||
|
console.log(data);
|
||
|
});
|
||
|
|
||
|
arecord.on("close", code => {
|
||
|
console.log("Audio process exited with " + code);
|
||
|
setTimeout(()=>{
|
||
|
startStream();
|
||
|
for (var a of client.voice.connections.values()) {
|
||
|
a.play(broadcast);
|
||
|
}
|
||
|
}, 2000);
|
||
|
});
|
||
|
|
||
|
broadcast = client.voice.createBroadcast();
|
||
|
broadcast.play(
|
||
|
arecord.stdout.on("data", data => {
|
||
|
return data;
|
||
|
}),
|
||
|
{
|
||
|
type: "converted",
|
||
|
volume: false,
|
||
|
highWaterMark: 1
|
||
|
}
|
||
|
);
|
||
|
};
|
||
|
|
||
|
client.login(token);
|
||
|
|
||
|
client.on("ready", ()=>{
|
||
|
console.log(`Logged in as: ${client.user.tag} (ID: ${client.user.id})`);
|
||
|
console.log(`Prefix is: ${pf}`);
|
||
|
console.log(`Currently in ${Array.from(client.guilds.cache.values()).length} servers\n`);
|
||
|
|
||
|
startStream();
|
||
|
});
|
||
|
|
||
|
client.on("error", async err => {
|
||
|
console.log("An error occurred: " + err.message);
|
||
|
});
|
||
|
|
||
|
// HURR NO GOOD COMMAND HANDLER HURR DURR
|
||
|
client.on("message", async message => {
|
||
|
if (!message.guild) return;
|
||
|
if (!message.member) return;
|
||
|
if (message.member.id == client.user.id) return;
|
||
|
// i could put it in the same one if i want to BUT I CANT BE BOTHERED
|
||
|
|
||
|
var args = message.content.split(' ');
|
||
|
var cmd = args.shift();
|
||
|
|
||
|
//console.log(`[Message] <${message.author.tag} in ${message.guild.name}> ${message.content}`);
|
||
|
|
||
|
if (cmd.startsWith(pf)) {
|
||
|
cmd = cmd.slice(pf.length).toLowerCase();
|
||
|
console.log(`[Command] <${message.author.tag} in #${message.channel.name}@${message.guild.name}> ${message.content}`);
|
||
|
switch (cmd) {
|
||
|
|
||
|
case "play":
|
||
|
case "join":
|
||
|
case "connect":
|
||
|
if (message.member.voice.channel) {
|
||
|
message.member.voice.channel.join().then(connection => {
|
||
|
connection.play(broadcast);
|
||
|
message.reply("joined");
|
||
|
}).catch(err =>{
|
||
|
message.reply("an error occurred while trying to join the voice channel: `" + err.message + '`');
|
||
|
console.log(err.message);
|
||
|
});
|
||
|
} else {
|
||
|
message.reply("join a voice channel");
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "stop":
|
||
|
case "leave":
|
||
|
case "disconnect":
|
||
|
if (message.member.voice.channel) {
|
||
|
message.member.voice.channel.leave();
|
||
|
message.reply("left");
|
||
|
} else {
|
||
|
message.reply("join a voice channel so I know where to leave");
|
||
|
// i can probably make it not do it this way but Cannot Be Bothered
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "eval":
|
||
|
if (ownerIds.includes(message.member.id)) {
|
||
|
try {
|
||
|
//console.log("Evaluating " + args.join(' '));
|
||
|
var evalOutput = eval(args.join(' '));
|
||
|
//var evalOutputChunks = evalOutput.match(/.{1,1950}/g);
|
||
|
message.reply("```\n" + evalOutput + "\n```");
|
||
|
//for (var i = 0; i < evalOutputChunks.length; i++) {
|
||
|
// message.channel.send(`Part ${i + 1} of ${evalOutputChunks.length}` + "```\n" + evalOutputChunks[i] + "\n```");
|
||
|
//}
|
||
|
console.log(evalOutput);
|
||
|
} catch (err) {
|
||
|
message.reply("fuck!\n```\n" + err.stack + "\n```");
|
||
|
}
|
||
|
} else {
|
||
|
message.reply("you need to be in the owner list");
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "rs":
|
||
|
case "restartstream":
|
||
|
if (ownerIds.includes(message.member.id)) {
|
||
|
arecord.kill("SIGTERM");
|
||
|
console.log("Terminated the audio process");
|
||
|
message.reply("terminated the audio process");
|
||
|
} else {
|
||
|
message.reply("you need to be in the owner list");
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "ss":
|
||
|
case "setserver":
|
||
|
// to do: maybe I could make it so each server can choose which VM in the list it plays audio from, instead of using the same broadcast
|
||
|
// (although maybe still use broadcasts for multiple connections to the same server, for optimisation, and less connections to the same server)
|
||
|
if (vncServers.includes(args[0]) || ownerIds.includes(message.member.id)) {
|
||
|
if (args[0] != undefined) {
|
||
|
vncServer = args[0];
|
||
|
arecord.kill("SIGTERM");
|
||
|
console.log("Set the VNC server to " + args[0] + " and terminated the audio process");
|
||
|
message.reply("set the VNC server to `" + args[0] + "` and terminated the audio process");
|
||
|
} else {
|
||
|
message.reply("specify a server you dumb fuck");
|
||
|
};
|
||
|
} else {
|
||
|
message.reply("you need to be in the owner list to connect to VNC servers not in the VNC server list (check `" + pf + "list`)");
|
||
|
// having the ability for anybody to connect to literally any host + tcp port maybe isn't a good idea
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "cs":
|
||
|
case "currentserver":
|
||
|
if (ownerIds.includes(message.member.id)) {
|
||
|
message.reply(`\nIP: \`${vncServer}\`\nName: \`${vncName}\``);
|
||
|
} else {
|
||
|
message.reply("you need to be in the owner list");
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "list":
|
||
|
var vmlist = "VM List:\n";
|
||
|
vncServers.forEach(server => {
|
||
|
var vmname = spawnSync("./name", [server], {timeout: 2000});
|
||
|
if (!vmname.status && vmname.stdout) {
|
||
|
vmlist += `\`${server}\` - **${vmname.stdout}**\n`;
|
||
|
} else {
|
||
|
vmlist += `\`${server}\` - Failed to get name\n`;
|
||
|
};
|
||
|
});
|
||
|
if (vmlist.length < 2000) message.reply(vmlist);
|
||
|
else message.reply("VM list is too big to fit in a message (oops!)");
|
||
|
break;
|
||
|
|
||
|
case "guilds":
|
||
|
if (ownerIds.includes(message.member.id)) {
|
||
|
let guildsOnEachPage = 10;
|
||
|
let guildsTmp = Array.from(client.guilds.cache.values());
|
||
|
let pageCount = Math.ceil(guildsTmp.length / guildsOnEachPage);
|
||
|
|
||
|
if (args[0] == "all") {
|
||
|
for (var i = 1; i <= pageCount; ++i) {
|
||
|
let guildList = `Guild list - __**Page ${i}/${pageCount}**__:\n`;
|
||
|
|
||
|
guildsTmp.slice((i * guildsOnEachPage) - guildsOnEachPage, (i * guildsOnEachPage)).forEach(guild => {
|
||
|
guildList += `**\`${guild.name}\`** - owned by ${guild.ownerID}, with ${guild.memberCount} users ${client.voice.connections.has(guild.id) ? `__**[Voice connected, ${Array.from(client.voice.connections.get(guild.id).channel.members).length} users]**__` : ""}\n`; // obese as shit holy FUCK
|
||
|
});
|
||
|
|
||
|
if (guildList.length < 2000) message.channel.send(guildList);
|
||
|
else message.reply("Guild list is too big to fit in a message (oops!)");
|
||
|
};
|
||
|
} else {
|
||
|
let page = isNaN(parseInt(args[0])) ? 1 : parseInt(args[0]);
|
||
|
let guildList = `Guild list - __**Page ${page}/${pageCount}**__:\n`;
|
||
|
|
||
|
guildsTmp.slice((page * guildsOnEachPage) - guildsOnEachPage, (page * guildsOnEachPage)).forEach(guild => {
|
||
|
guildList += `**\`${guild.name}\`** - owned by ${guild.ownerID}, with ${guild.memberCount} users ${client.voice.connections.has(guild.id) ? `__**[Voice connected, ${Array.from(client.voice.connections.get(guild.id).channel.members).length} users]**__` : ""}\n`; // obese as shit holy FUCK
|
||
|
});
|
||
|
|
||
|
if (guildList.length < 2000) message.channel.send(guildList);
|
||
|
else message.reply("Guild list is too big to fit in a message (oops!)");
|
||
|
};
|
||
|
} else {
|
||
|
message.reply("you need to be in the owner list");
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case "stats":
|
||
|
let uptimeSeconds = (client.uptime / 1000);
|
||
|
let botStats = "Bot stats:\n";
|
||
|
botStats += "**Server count**: " + Array.from(client.guilds.cache).length + '\n';
|
||
|
botStats += "**Voice connection count**: " + Array.from(client.voice.connections).length + '\n';
|
||
|
|
||
|
botStats += "**Bot uptime**: ";
|
||
|
botStats += Math.floor(uptimeSeconds / 86400) + " days, ";
|
||
|
uptimeSeconds %= 86400;
|
||
|
botStats += Math.floor(uptimeSeconds / 3600) + " hrs, ";
|
||
|
uptimeSeconds %= 3600;
|
||
|
botStats += Math.floor(uptimeSeconds / 60) + " mins, ";
|
||
|
botStats += Math.floor(uptimeSeconds % 60) + " secs\n";
|
||
|
|
||
|
botStats += "**Current VM name**: `" + vncName + "`\n";
|
||
|
|
||
|
if (botStats.length < 2000) message.reply(botStats);
|
||
|
else message.reply("stats are too big to fit in a message (oops!)");
|
||
|
// i should probably calculate how big the mention part is too, but this somewhat works for now
|
||
|
break;
|
||
|
|
||
|
case "about":
|
||
|
message.reply("this uses DarkOK's own QEMU_VNC_Audio->Discord bot");
|
||
|
break;
|
||
|
|
||
|
case "invite":
|
||
|
message.reply(`my invite URL is: https://discord.com/oauth2/authorize?client_id=${client.user.id}&permissions=36703232&scope=bot`);
|
||
|
break;
|
||
|
|
||
|
case "help":
|
||
|
message.reply(
|
||
|
"Command list:\n" +
|
||
|
`**${pf}join** - Join a voice channel\n` +
|
||
|
`**${pf}leave** - Leave a voice channel\n` +
|
||
|
`**${pf}invite** - Sends the invite URL for the bot\n` +
|
||
|
`**${pf}stats** - Display some statistics about the bot\n` +
|
||
|
'\n' +
|
||
|
"and that's about it\n" +
|
||
|
"sometimes audio just stops working, try making the bot leave and rejoin the voice channel to see if it solves the issue\n" +
|
||
|
"this bot is relatively unstable as of now, expect crashes/things not working\n\n" +
|
||
|
"contact? dark@darkok.xyz"
|
||
|
);
|
||
|
// really shitty but it's the best I can do since there's no proper command handler
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
});
|
||
|
|
||
|
client.on("guildCreate", async guild => {
|
||
|
console.log(`[Server Joined] ${guild.name} - ${guild.memberCount} members, ID: ${guild.id}`);
|
||
|
});
|
||
|
|
||
|
client.on("guildDelete", async guild => {
|
||
|
console.log(`[Server Left] ${guild.name} - ${guild.memberCount} members, ID: ${guild.id}`);
|
||
|
});
|
||
|
|
||
|
process.on("unhandledRejection", async err => {
|
||
|
console.error("Unhandled promise rejection:", err);
|
||
|
});
|