Skip to content

Commit

Permalink
mostly added support for voice broadcast
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardMcSorley committed Nov 9, 2018
1 parent 129f236 commit 3cfd8ae
Showing 18 changed files with 1,988 additions and 208 deletions.
275 changes: 181 additions & 94 deletions discord-server.js
Original file line number Diff line number Diff line change
@@ -1,125 +1,212 @@
const Discord = require('discord.js');
const naverAPI = require('./naver-api');
const io = require('./next-server').io;
const db = require('./firebase/index');
const Discord = require("discord.js");
const naverAPI = require("./resources/naver-api");
const io = require("./next-server").io;
const db = require("./firebase/index");
const ytdl = require("ytdl-core");
const util = require("util");
const constants = require("./utils/constants");
const format = require("./utils/format-text");
const webhooks = require("./webhooks/index");
const bot = new Discord.Client({
disableEveryone: true,
disabledEvents: ['TYPING_START']
disableEveryone: true,
disabledEvents: ["TYPING_START"]
});

// Catch Errors before they crash the app.
process.on('uncaughtException', (err) => {
const errorMsg = err.stack.replace(new RegExp(`${__dirname}/`, 'g'), './');
console.error('Uncaught Exception: ', errorMsg);
// process.exit(1); //Eh, should be fine, but maybe handle this?
bot.login(process.env.KOREAN_DICT_BOT_DISCORD_TOKEN);
const broadcastState = {
broadcast: bot.createVoiceBroadcast(),
paused: false,
currentAudio: null,
currentInfo: null,
time: null
};
broadcastState.broadcast.on("subscribe", dispatcher => {
console.log("New broadcast subscriber!");
});

process.on('unhandledRejection', err => {
console.error('Uncaught Promise Error: ', err);
// process.exit(1); //Eh, should be fine, but maybe handle this?
broadcastState.broadcast.on("unsubscribe", dispatcher => {
console.log("Channel unsubscribed from broadcast :(");
});

bot.login(process.env.KOREAN_DICT_BOT_DISCORD_TOKEN);
broadcastState.broadcast.on("end", () => playNextSong());
broadcastState.broadcast.on("error", () => playNextSong());

const util = require('util');
const constants = require('./constants.js');
const format = require('./format-text');
// use fire for admin purposes, in discord use !define eval fire('restart') to restart the server
const fire = action => {
const { spawn } = require("child_process");
switch (action) {
case "restart":
const subprocess = spawn(process.argv[0], process.argv.slice(1), { // spawn new process
detached: true,
stdio: ["ignore"]
});
subprocess.unref();
fire("shutdown"); // close this process
return "restarting";
case "shutdown":
process.exit();
return "shutdown";
case "skip": // run end on broadcast should playNextSong()
broadcastState.broadcast.end();
return "skipping";
case "pause": // pause broadcast
broadcastState.broadcast.pause();
return "pausing";
case "resume": // resume broadcast
broadcastState.broadcast.resume();
return "resuming";
default:
return "please provide an action";
}
};

const message = async message => { // on message event
let options = constants.GET_DEFAULT_MESSAGE_OPTIONS();
const prefix = constants.GET_DISCORD_PREFIX(message.content);
if (message.author.bot || message.system) { // Ignore bots
return
}
if (prefix) { // Message includes your prefix, not DM
return messageHasPrefix(message, options);
} else if (constants.isDM(message, bot)) { // Catch DM
return messageHasDM(message, options);
} else if (constants.isMention(message, bot)) { // Catch @Mentions
return messageHasMention(message, options);
}
const message = async message => {
// on message event
if (message.author.bot || message.system) {
// Ignore bots
return;
}
let options = constants.GET_DEFAULT_MESSAGE_OPTIONS();
const prefix = constants.GET_DISCORD_PREFIX(message.content);
if (prefix) {
// Message includes your prefix, not DM
return messageHasPrefix(message, options);
} else if (constants.isDM(message, bot)) {
// Catch DM
return messageHasDM(message, options);
} else if (constants.isMention(message, bot)) {
// Catch @Mentions
return messageHasMention(message, options);
}
return;
};

const ready = async () => {
bot.user.setActivity("Looking up words!");
playNextSong();
const channel = bot.channels.get(process.env.INITIAL_VOICE_CHANNEL); //hardcoded for now
connectToBroadcast(channel);
console.log(
`Bot is online!\n${bot.users.size} users, in ${
bot.guilds.size
} servers connected.`
);
};
const connectToBroadcast = channel => {
if (!channel) return console.error("The channel does not exist!");
// join channel
channel
.join()
.then(connection => connection.playBroadcast(broadcastState.broadcast))
.catch(err => console.log("could not join audio channel", err));
};

const playNextSong = async () => {
const audio = await getNextAudio();
if (audio === null) {
playNextSong(); // try again
} else {
playAudioToBroadcast(audio);
}
};

const getNextAudio = async () => {
let queue = await db.getPlaylistFromDB();
if (queue === null) {
return null;
}
// add currentAudio to end of queue
const currentAudio = queue.shift(); // remove from list
queue.push(currentAudio); // add currnetAudio to end of queue
await webhooks.updatePlaylist(queue); // update list
return currentAudio;
};

const playAudioToBroadcast = audio => {
const stream = ytdl(audio, { filter: "audioonly" });
broadcastState.broadcast.playStream(stream);
};

const ready = () => {
bot.user.setActivity('Looking up words!'); //you can set a default game
console.log(`Bot is online!\n${bot.users.size} users, in ${bot.guilds.size} servers connected.`);
}
const messageHasDM = (message, options) => {
options.embed.description = constants.HELPER_TEXT;
return message.channel.send(options);
options.embed.description = constants.HELPER_TEXT;
return message.channel.send(options);
};

const messageHasMention = (message, options) => {
options.embed.description = constants.HELPER_TEXT;
return message.channel.send(options);
options.embed.description = constants.HELPER_TEXT;
return message.channel.send(options);
};

const messageHasPrefix = async (message, options) => {
const prefix = constants.GET_DISCORD_PREFIX(message.content);
const prefixIndex = message.content.indexOf(prefix);
const msg = message.content.slice(prefixIndex + prefix.length); // slice of the prefix on the message
let args = msg.split(" "); // break the message into part by spaces
const cmd = args[0].toLowerCase(); // set the first word as the command in lowercase just in case
args.shift(); // delete the first word from the args
const translation = await naverAPI.getTranslation(msg); // try to lookup in dictionary'
await db.sendTermToDB(msg)
io.emit("newTerm")
if (message.channel.type === 'dm') { // Direct Message
if(cmd === 'who' || cmd === 'whoami' || msg === 'whoru' ){ // Talk about yourself maybe
return;
}
}

// Make sure this command always checks for you. YOU NEVER WANT ANYONE ELSE TO USE THIS COMMAND
if (cmd === "eval" && message.author.id === process.env.KOREAN_DICT_BOT_DISCORD_OWNER) { // < checks the message author's id to owners
const code = args.join(" ");
return evalCmd(message, code);
}
else if (translation) {
const url = constants.DICTIONARY_LINK + encodeURIComponent(msg);
const formatedItems = translation.map(format.formatDictionaryItem);
const formatedString = formatedItems.join("\n");
options.embed.fields = constants.NAVER_FIELDS(url);
options.embed.description = `${formatedString}`;
options.embed.title = format.NAVER_TITLE(translation, msg);
return message.channel.send(options);
}

else { // if the command doesn't match anything
options.embed.description = constants.CONFUSED_COMAND;
message.channel.send(options);
return;
const prefix = constants.GET_DISCORD_PREFIX(message.content);
const prefixIndex = message.content.indexOf(prefix);
const msg = message.content.slice(prefixIndex + prefix.length); // slice of the prefix on the message
let args = msg.split(" "); // break the message into part by spaces
const cmd = args[0].toLowerCase(); // set the first word as the command in lowercase just in case
args.shift(); // delete the first word from the args
const translation = await naverAPI.getTranslation(msg); // try to lookup in dictionary'
await db.sendTermToDB(msg);
io.emit("newTerm");
if (message.channel.type === "dm") {
// Direct Message
if (cmd === "who" || cmd === "whoami" || msg === "whoru") {
// Talk about yourself maybe
return;
}
}

// Make sure this command always checks for you. YOU NEVER WANT ANYONE ELSE TO USE THIS COMMAND
if (
cmd === "eval" &&
message.author.id === process.env.KOREAN_DICT_BOT_DISCORD_OWNER
) {
// < checks the message author's id to owners
const code = args.join(" ");
return evalCmd(message, code);
} else if (translation) {
const url = constants.DICTIONARY_LINK + encodeURIComponent(msg);
const formatedItems = translation.map(format.formatDictionaryItem);
const formatedString = formatedItems.join("\n");
options.embed.fields = constants.NAVER_FIELDS(url);
options.embed.description = `${formatedString}`;
options.embed.title = format.NAVER_TITLE(translation, msg);
return message.channel.send(options);
} else {
// if the command doesn't match anything
options.embed.description = constants.CONFUSED_COMAND;
message.channel.send(options);
return;
}
};

function evalCmd(message, code) {
if (message.author.id !== process.env.KOREAN_DICT_BOT_DISCORD_OWNER) return;
try {
let evaled = eval(code);
if (typeof evaled !== "string")
evaled = util.inspect(evaled);
message.channel.send(clean(evaled), { code: "xl" });
} catch (err) {
message.channel.send(`\`ERROR\` \`\`\`xl\n${clean(err)}\n\`\`\``);
}
if (message.author.id !== process.env.KOREAN_DICT_BOT_DISCORD_OWNER) return;
try {
let evaled = eval(code);
if (typeof evaled !== "string") evaled = util.inspect(evaled);
message.channel.send(clean(evaled), { code: "xl" });
} catch (err) {
message.channel.send(`\`ERROR\` \`\`\`xl\n${clean(err)}\n\`\`\``);
}
}

function clean(text) {
if (typeof (text) !== 'string') {
text = util.inspect(text, { depth: 0 });
}
text = text
.replace(/`/g, '`' + String.fromCharCode(8203))
.replace(/@/g, '@' + String.fromCharCode(8203))
.replace(process.env.KOREAN_DICT_BOT_DISCORD_TOKEN, 'mfa.VkO_2G4Qv3T--NO--lWetW_tjND--TOKEN--QFTm6YGtzq9PH--4U--tG0') //Don't let it post your token
return text;
if (typeof text !== "string") {
text = util.inspect(text, { depth: 0 });
}
text = text
.replace(/`/g, "`" + String.fromCharCode(8203))
.replace(/@/g, "@" + String.fromCharCode(8203))
.replace(
process.env.KOREAN_DICT_BOT_DISCORD_TOKEN,
"mfa.VkO_2G4Qv3T--NO--lWetW_tjND--TOKEN--QFTm6YGtzq9PH--4U--tG0"
); //Don't let it post your token
return text;
}

bot.on("ready", ready);
bot.on("message", message);
bot.on("error", console.log);
bot.on("disconnect", console.log);
bot.on("resume", console.log);
bot.on("warn", console.log);
bot.on("error", e => console.log("botOnError", e));
bot.on("disconnect", e => console.log("botOnDisconnect", e));
bot.on("resume", e => console.log("botOnResume", e));
bot.on("warn", e => console.log("botOnWarn", e));
4 changes: 2 additions & 2 deletions firebase/firebase.js
Original file line number Diff line number Diff line change
@@ -7,9 +7,9 @@ const config = {
databaseURL: process.env.FIREBASE_DATABASE_URL
};

firebase.initializeApp(config);
admin.initializeApp(config);

const database = firebase.database();
const database = admin.database();

exports.firebase = firebase;
exports.database = database;
46 changes: 43 additions & 3 deletions firebase/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const firebase = require('./firebase');
const db = firebase.database;
const DBResource = process.env.NODE_ENV === 'development'? `TestKoreanDictionaryTerms` : 'KoreanDictionaryTerms';
const DBResource = process.env.NODE_ENV === 'development' ? `TestKoreanDictionaryTerms` : 'KoreanDictionaryTerms';
const videoInfoDBResource = process.env.NODE_ENV === 'development' ? `TestKoreanListeningPracticePlaylistInfo` : 'KoreanListeningPracticePlaylistInfo';
const videoPlaylistDBResource = process.env.NODE_ENV === 'development' ? `TestKoreanListeningPracticePlaylist` : 'KoreanListeningPracticePlaylist';

module.exports.sendTermToDB = async (term) => {
const dbRef = await db.ref(`${DBResource}`);
@@ -9,7 +11,7 @@ module.exports.sendTermToDB = async (term) => {
//already exists, add
const oldValue = await snapshot.child(term).val().count
return await dbRef.child(term)
.update({count: oldValue + 1});
.update({ count: oldValue + 1 });
} else {
return await dbRef.child(term)
.set({ count: 1 });
@@ -26,5 +28,43 @@ module.exports.getTermsFromDB = async () => {
module.exports.resetTermsOnDB = async () => {
const dbRef = db.ref(`${DBResource}`);
dbRef
.set({});
.set({});
}

module.exports.sendVideoInfoToDB = async (videoInfo) => {
const dbRef = await db.ref(`${videoInfoDBResource}`);
return await dbRef.once('value', async function (snapshot) {
return await dbRef.child(videoInfo.videoId)
.set(videoInfo);
});
}

module.exports.updateVideoPlaylist = async (playlist) => {
const dbRef = await db.ref(`${videoPlaylistDBResource}`);
return await dbRef.once('value', async function (snapshot) {
return await dbRef
.set(playlist);
});
}

module.exports.getVideoInfoFromDB = async (videoInfo) => {
const dbRef = await db.ref(`${videoInfoDBResource}`);
return await dbRef.once('value', async function (snapshot) {
return await dbRef.child(videoInfo.videoId)
.set(videoInfo);
});
}

module.exports.getPlaylistFromDB = async () => {
const dbRef = await db.ref(`${videoPlaylistDBResource}`);
const snapshot = await dbRef.once('value');
const value = snapshot.val();
return value;
}

module.exports.getPlaylistInfoFromDB = async () => {
const dbRef = await db.ref(`${videoInfoDBResource}`);
const snapshot = await dbRef.once('value');
const value = snapshot.val();
return value;
}
Loading

0 comments on commit 3cfd8ae

Please sign in to comment.