diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..468725e --- /dev/null +++ b/.eslintrc @@ -0,0 +1,8 @@ +{ + "parser": "babel-eslint", + "extends": "airbnb", + "rules": { + "indent": ["error", "tab"], + "react/jsx-indent-props": ["error", "tab"], + } +} diff --git a/.gitignore b/.gitignore index cf17d5f..4516ee9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules .env npm-debug.log .DS_Store +designs diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index d2ccaf6..0000000 --- a/.jscsrc +++ /dev/null @@ -1,78 +0,0 @@ -{ - "disallowSpacesInNamedFunctionExpression": { - "beforeOpeningRoundBrace": true - }, - "disallowSpacesInFunctionDeclaration": { - "beforeOpeningRoundBrace": true - }, - "disallowSpacesInsideBrackets": true, - "disallowEmptyBlocks": true, - "disallowSpacesInCallExpression": true, - "disallowSpacesInsideArrayBrackets": true, - "disallowSpacesInsideParentheses": true, - "disallowQuotedKeysInObjects": true, - "disallowSpaceAfterObjectKeys": true, - "disallowSpaceAfterPrefixUnaryOperators": true, - "disallowSpaceBeforePostfixUnaryOperators": true, - "disallowSpaceBeforeBinaryOperators": [ - "," - ], - "disallowMixedSpacesAndTabs": true, - "disallowTrailingWhitespace": true, - "requireTrailingComma": { "ignoreSingleLine": true }, - "requireSpaceAfterComma": true, - "disallowYodaConditions": true, - "disallowKeywords": [ "with" ], - "disallowKeywordsOnNewLine": ["else"], - "disallowMultipleLineBreaks": true, - "disallowMultipleLineStrings": true, - "disallowMultipleVarDecl": true, - "disallowSpaceBeforeComma": true, - "disallowSpaceBeforeSemicolon": true, - "disallowSpacesInsideTemplateStringPlaceholders": true, - "requireSpaceBeforeBlockStatements": true, - "requireParenthesesAroundIIFE": true, - "requireSpacesInAnonymousFunctionExpression": { - "beforeOpeningRoundBrace": true, - "allExcept": ["shorthand"] - }, - "requireSpacesInConditionalExpression": true, - "requireBlocksOnNewline": 1, - "requireCommaBeforeLineBreak": true, - "requireSpaceBeforeBinaryOperators": true, - "requireSpaceAfterBinaryOperators": true, - "requireCamelCaseOrUpperCaseIdentifiers": true, - "requireDollarBeforejQueryAssignment": true, - "requireLineFeedAtFileEnd": true, - "requireCapitalizedConstructors": true, - "requireDotNotation": true, - "requireSpacesInForStatement": true, - "requireSpacesInsideObjectBrackets": "all", - "requireSpaceBetweenArguments": true, - "requireCurlyBraces": [ - "do" - ], - "requireSpaceAfterKeywords": [ - "if", - "else", - "for", - "while", - "do", - "switch", - "case", - "return", - "try", - "catch", - "typeof" - ], - "requirePaddingNewLinesBeforeLineComments": { - "allExcept": "firstAfterCurly" - }, - "requirePaddingNewLinesAfterBlocks": true, - "requireSemicolons": true, - "safeContextKeyword": "_this", - "validateLineBreaks": "LF", - "validateQuoteMarks": { "mark": "'", "escape": true, "ignoreJSX": true }, - "validateIndentation": "\t", - "maximumLineLength": 100 -} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ae87375 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM dkarchmervue/fluent-ffmpeg + +# Quick NPM Installs +ADD ./package.json /app/package.json +RUN cd /app && npm install + +# Add our App +ADD . /app + +WORKDIR /app diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..5b7a342 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +web: ./node_modules/.bin/babel-node --presets es2015 -- ./server.js +worker: ./node_modules/.bin/babel-node --presets es2015 -- ./bot.js diff --git a/Readme.md b/Readme.md index 584f8de..287608c 100644 --- a/Readme.md +++ b/Readme.md @@ -16,13 +16,17 @@ Next you'll want to clone this and then add a `.env` file to the root of the clo DISCORD_TOKEN= LEAGUE_APIKEY= LEAGUE_LOCATION= +TWITTER_CONSUMER_KEY= +TWITTER_CONSUMER_SECRET= +TWITTER_ACCESS_TOKEN= +TWITTER_ACCESS_TOKEN_SECRET= ``` You'll want to fill these in with your own values. Once that's all sorted you can then run `npm install` to install the dependencies for the bot and webserver. -When that's all sorted you should be able to run `npm run start:bot` to start the bot or `npm run start:web` to start the websever on http://localhost:5000. For making the bot join a server you'll want to login as the user the bot will act as first and then join the server first (an easier way should be on the way soon!). +When that's all sorted you should be able to run `npm run start:bot` to start the bot or `npm run start:web` to start the websever on http://localhost:5000. ### Bot Modules @@ -30,10 +34,8 @@ Each command the bot uses is it's own file in `/modules` if you're adding new mo ### Contributing -I'll gladly accept any help or pointers you want to give, if you're going to do a pull request it'll be nice if you can follow the eslint for the javascript. It's pretty much just airbnb's javascript guide with tabs instead of spaces. +I try to keep to [Airbnb's Javascript Standards](https://github.com/airbnb/javascript) where possible using the [.eslintrc](https://github.com/tomopagu/disbott/blob/discordie/.eslintrc) file in the root of disbott. I'm happy to have any help or suggestions where possible, just stick a PR on the Repo! #### Why the disbott rather than disbot -Funny story, I broke the first disbot user. For some reason it remains connected to discord but remains unresponsive to any message whatsoever. I can't send anything as that user when logged into the discord client myself. No idea on the reason why for it still. - -If you do happen to know why, please let me know! +Funny story, I broke the first disbot user. For some reason it remained connected to discord but remains unresponsive to any message whatsoever. I couldn't send anything as that user when logged into the discord client myself. This was way before the bots we have today so disbot probably could work but the disbott name has kinda stuck. diff --git a/bot.js b/bot.js index 1d639b5..f5633e6 100644 --- a/bot.js +++ b/bot.js @@ -1,11 +1,10 @@ import { Config } from './config'; -import _ from 'underscore'; -import S from 'string'; -import DiscordClient from 'discord.io'; +import Discordie from 'discordie'; +const client = new Discordie({ autoReconnect: true }); // Modules -import { about, help, info, ping } from './modules/utils'; +import * as util from './modules/utils'; import league from './modules/lol/index'; @@ -14,91 +13,92 @@ import soundFileupload from './modules/sound/modules/fileupload'; import management from './modules/management/index'; +import poll from './modules/poll/index'; + +import { messagecountCommand, messageCountLog } from './modules/messagecount'; + import remindme from './modules/remindme/index'; import remindmeCommand from './modules/remindme/command'; -import lastseen from './modules/lastseen/index'; -import lastseenCommand from './modules/lastseen/command'; +// import lastseen from './modules/lastseen/index'; +// import lastseenCommand from './modules/lastseen/command'; import twitter from './modules/twitter/index'; import { chunder } from './modules/silly'; -var bot = new DiscordClient({ - token: Config.discord.token, -}); - -bot.sendMessages = function (ID, messageArr, interval) { - var callback = []; - var resArr = []; - var len = messageArr.length; - typeof (arguments[2]) === 'function' ? callback = arguments[2] : callback = arguments[3]; - if (typeof (interval) !== 'number') interval = 1000; - - function _sendMessages() { - setTimeout(function () { - if (messageArr[0]) { - bot.sendMessage({ - to: ID, - message: messageArr.shift(), - }, function (res) { - resArr.push(res); - if (resArr.length === len) if (typeof (callback) === 'function') callback(resArr); - }); - - _sendMessages(); - } - }, interval); - } +export function bot() { + client.connect({ + token: Config.discord.token, + }); - _sendMessages(); -}; + client.Dispatcher.on('GATEWAY_READY', () => { + console.log('Connected as: ' + client.User.id + ' - ' + client.User.username); // eslint-disable-line -bot.connect(); + client.User.setGame({ + name: '@disbott help for cmd!', + }); -bot.on('ready', function () { - console.log(bot.username + ' - (' + bot.id + ')'); - bot.setPresence({ - game: 'Hacking Simulator 2k16', + // Start the logging functions + remindme(client); + // lastseen(client); }); - // Start the logging function - remindme(bot); - lastseen(bot); -}); + client.Dispatcher.on('MESSAGE_CREATE', e => { + messageCountLog(e); -bot.on('message', function (user, userID, channelID, message, rawEvent) { - var wasMentioned = _.findWhere(rawEvent.d.mentions, { id: bot.id }); + const wasMentioned = client.User.isMentioned(e.message); - if (wasMentioned && userID !== bot.id) { - message = S(message).chompLeft('<@' + bot.id + '> ').s; + if (wasMentioned && e.message.author.id !== client.User.id) { + const message = e.message.content.replace(`<@${client.User.id}> `, ''); - try { - ping(bot, channelID, message); - help(Config, bot, channelID, message); - about(Config, bot, channelID, message); - info(Config, bot, channelID, message); + try { + util.ping(e, message); + util.help(e, message); + util.about(e, message); + util.info(e, message); + util.deleteMessages(e, message); - // kill(bot, channelID, message); + // kill(client, channelID, message); - chunder(bot, channelID, message); + chunder(e, message); - league(bot, user, userID, channelID, message); + league(e, message); - sound(Config, bot, channelID, message, rawEvent); + sound(client, e, message); - management(Config, bot, channelID, message, rawEvent); + management(e, message); - remindmeCommand(bot, user, userID, channelID, message); - lastseenCommand(bot, user, userID, channelID, message); + poll(e, message); - twitter(bot, channelID, message); - } catch (e) { - console.log(e); + remindmeCommand(e, message); + + messagecountCommand(e, message); + + // lastseenCommand(client, user, userID, channelID, message); + + twitter(e, message); + } catch (error) { + console.log(error); // eslint-disable-line + } } - } - // soundFileupload is a little different to other commands so it has to be put here - // Currently it'll accept any mp3, I'd like it to only be mp3's dm'd to it - soundFileupload(bot, channelID, rawEvent); -}); + // soundFileupload is a little different to other commands so it has to be put here + // Currently it'll accept any mp3 messaged to it + soundFileupload(e); + }); + + client.Dispatcher.on('VOICE_CHANNEL_JOIN', e => { + util.userHasJoinedVoiceChannel(e); + }); + + client.Dispatcher.on('DISCONNECTED', e => { + console.log(e); // eslint-disable-line + }); +} + +export function botDisconnect() { + client.disconnect(); +} + +bot(); diff --git a/config.js b/config.js index cbd0815..21cc1ed 100644 --- a/config.js +++ b/config.js @@ -1,8 +1,9 @@ require('dotenv').config(); -export var Config = { +export const Config = { discord: { token: process.env.DISCORD_TOKEN, + testerToken: process.env.DISBOTT_TESTER_TOKEN, }, league: { apikey: process.env.LEAGUE_APIKEY, @@ -12,7 +13,7 @@ export var Config = { consumer_key: process.env.TWITTER_CONSUMER_KEY, consumer_secret: process.env.TWITTER_CONSUMER_SECRET, access_token: process.env.TWITTER_ACCESS_TOKEN, - access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET + access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET, }, domain: 'https://disbott.pagu.co', }; diff --git a/modules-todo.md b/modules-todo.md deleted file mode 100644 index b36c403..0000000 --- a/modules-todo.md +++ /dev/null @@ -1,3 +0,0 @@ -# Modules wanted - -- Post memes \ No newline at end of file diff --git a/modules/lol/index.js b/modules/lol/index.js index 4515f5f..f844f0d 100644 --- a/modules/lol/index.js +++ b/modules/lol/index.js @@ -3,10 +3,10 @@ import lolGetSetSummoner from './modules/get-set-summoner'; import lolCurrentGameInfo from './modules/current-game'; import lolRankedStats from './modules/ranked-stats'; -export default function league(bot, user, userID, channelID, message) { - message = message.toLowerCase(); - lolSetSummoner(bot, user, userID, channelID, message); - lolGetSetSummoner(bot, user, userID, channelID, message); - lolCurrentGameInfo(bot, user, userID, channelID, message); - lolRankedStats(bot, user, userID, channelID, message); -}; +export default function league(e, message) { + const lcmessage = message.toLowerCase(); + lolSetSummoner(e, lcmessage); + lolGetSetSummoner(e, lcmessage); + lolCurrentGameInfo(e, lcmessage); + lolRankedStats(e, lcmessage); +} diff --git a/modules/lol/modules/current-game.js b/modules/lol/modules/current-game.js index 96301db..97931c9 100644 --- a/modules/lol/modules/current-game.js +++ b/modules/lol/modules/current-game.js @@ -1,58 +1,52 @@ import { Config } from './../../../config'; import _ from 'underscore'; -var EventEmitter = require('events'); +const EventEmitter = require('events'); import S from 'string'; +const s = S; import moment from 'moment'; -var lolapi = require('lolapi')(Config.league.apikey, Config.league.location); +const lolapi = require('lolapi')(Config.league.apikey, Config.league.location); import { leagueDb } from './util/league-db'; import gameMode from './util/gametype-constant'; import getSummonerIdFunction from './util/get-summoner-id'; -export default function lolCurrentGameInfo(bot, user, userID, channelID, message) { - if (S(message).contains('lolcurrentgame')) { - bot.simulateTyping(channelID, function () { - var splitMessage = message.split('='); - var summonerName = splitMessage[1]; +export default function lolCurrentGameInfo(e, message) { + if (s(message).contains('lolcurrentgame')) { + e.message.channel.sendTyping(); - var getSummonerId = new EventEmitter(); - getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName); + const splitMessage = message.split('='); + const summonerName = splitMessage[1]; + const userID = e.message.author.id; - getSummonerId.on('fail', function (message) { - bot.sendMessage({ - to: channelID, - message: message, - }); - }); + const getSummonerId = new EventEmitter(); + getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName); + + getSummonerId.on('fail', (errMessage) => { + e.message.channel.sendMessage(errMessage); + }); - getSummonerId.on('completed', function (summonerID) { - lolapi.CurrentGame.getBySummonerId(summonerID, function (error, game) { - if (error) { - bot.sendMessage({ - to: channelID, - message: 'ERROR: ' + error + '. Are you in a game?', - }); - } else { - var gameType = gameMode(game); - - var currentLength = moment(game.gameStartTime).toNow(true); - - _.each(game.participants, function (participant) { - if (participant.summonerId === summonerID) { - lolapi.Static.getChampion(participant.championId, function (error, champion) { - var player = _.isString(summonerName) ? summonerName : user; - bot.sendMessage({ - to: channelID, - message: player + ' has been playing ' + champion.name + ' in a ' + gameType + ' Game for ~' + currentLength + '. ' + Config.domain + '/currentgame.html?summonerID=' + summonerID, - }); - }); - } - }); - } - }); + getSummonerId.on('completed', (summonerID) => { + lolapi.CurrentGame.getBySummonerId(summonerID, (error, game) => { + if (error) { + e.message.channel.sendMessage(`ERROR: ${error}. Are you in a game?`); + } else { + const gameType = gameMode(game); + + const currentLength = moment(game.gameStartTime).toNow(true); + + _.each(game.participants, (participant) => { + if (participant.summonerId === summonerID) { + lolapi.Static.getChampion(participant.championId, (err, champion) => { + const player = _.isString(summonerName) ? summonerName : e.message.author.mention; + + e.message.channel.sendMessage(`${player} has been playing ${champion.name} in a ${gameType} Game for ~${currentLength}. ${Config.domain}/currentgame.html?summonerID=' + summonerID`); + }); + } + }); + } }); }); } -}; +} diff --git a/modules/lol/modules/get-set-summoner.js b/modules/lol/modules/get-set-summoner.js index 8ae1d62..6faea16 100644 --- a/modules/lol/modules/get-set-summoner.js +++ b/modules/lol/modules/get-set-summoner.js @@ -1,48 +1,40 @@ import { Config } from './../../../config'; import _ from 'underscore'; -var EventEmitter = require('events'); +const EventEmitter = require('events'); import S from 'string'; +const s = S; -var lolapi = require('lolapi')(Config.league.apikey, Config.league.location); +const lolapi = require('lolapi')(Config.league.apikey, Config.league.location); import { leagueDb } from './util/league-db'; -import gameMode from './util/gametype-constant'; import getSummonerIdFunction from './util/get-summoner-id'; -export default function lolGetSetSummoner(bot, user, userID, channelID, message) { - if (S(message).contains('lolsummoner')) { - bot.simulateTyping(channelID, function () { - var splitMessage = message.split('='); - var summonerName = splitMessage[1]; +export default function lolGetSetSummoner(e, message) { + if (s(message).contains('lolsummoner')) { + e.message.channel.sendTyping(); - var player = _.isString(summonerName) ? summonerName : user; + const splitMessage = message.split('='); + const summonerName = splitMessage[1]; + const userID = e.message.author.id; - var getSummonerId = new EventEmitter(); - getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName); + const player = _.isString(summonerName) ? summonerName : e.message.author.mention; - getSummonerId.on('fail', function (message) { - bot.sendMessage({ - to: channelID, - message: message, - }); - }); + const getSummonerId = new EventEmitter(); + getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName); + + getSummonerId.on('fail', (errMessage) => { + e.message.channel.sendMessage(errMessage); + }); - getSummonerId.on('completed', function (summonerID) { - lolapi.Summoner.get(summonerID, function (error, summoner) { - if (error) { - bot.sendMessage({ - to: channelID, - message: 'ERROR: Could not get summoner', - }); - } else { - bot.sendMessage({ - to: channelID, - message: player + '\'s league account is ' + summoner[summonerID].name, - }); - } - }); + getSummonerId.on('completed', (summonerID) => { + lolapi.Summoner.get(summonerID, (error, summoner) => { + if (error) { + e.message.channel.sendMessage('ERROR: Could not get summoner'); + } else { + e.message.channel.sendMessage(`${player}\'s league account is ${summoner[summonerID].name}`); + } }); }); } -}; +} diff --git a/modules/lol/modules/ranked-stats.js b/modules/lol/modules/ranked-stats.js index 638539d..e37fa77 100644 --- a/modules/lol/modules/ranked-stats.js +++ b/modules/lol/modules/ranked-stats.js @@ -1,67 +1,61 @@ import { Config } from './../../../config'; import _ from 'underscore'; -var EventEmitter = require('events'); +const EventEmitter = require('events'); import S from 'string'; +const s = S; -var lolapi = require('lolapi')(Config.league.apikey, Config.league.location); +const lolapi = require('lolapi')(Config.league.apikey, Config.league.location); import { leagueDb } from './util/league-db'; import getSummonerIdFunction from './util/get-summoner-id'; -export default function rankedStats(bot, user, userID, channelID, message) { - if (S(message).contains('lolrankedstats')) { - bot.simulateTyping(channelID, function () { - var splitMessage = message.split('='); - var summonerName = splitMessage[1]; +export default function rankedStats(e, message) { + if (s(message).contains('lolrankedstats')) { + e.message.channel.sendTyping(); - var getSummonerId = new EventEmitter(); - getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName); + const splitMessage = message.split('='); + const summonerName = splitMessage[1]; + const userID = e.message.author.id; - getSummonerId.on('fail', function (message) { - bot.sendMessage({ - to: channelID, - message: message, - }); - }); - - getSummonerId.on('completed', function (summonerID) { - lolapi.Stats.getRanked(summonerID, null, function (err, stats) { - var player = _.isString(summonerName) ? summonerName : user; - if (err || stats === null) { - bot.sendMessage({ - to: channelID, - message: player + ' is not ranked this season', - }); - } else { - var combinedStatsIndex = _.findIndex(stats.champions, { id: 0 }); - var combinedStats = stats.champions[combinedStatsIndex]; - var winloss = combinedStats.stats.totalSessionsWon + ' wins & ' + combinedStats.stats.totalSessionsLost + ' losses'; + const getSummonerId = new EventEmitter(); + getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName); - var K = combinedStats.stats.totalChampionKills; - var A = combinedStats.stats.totalAssists; - var D = combinedStats.stats.totalDeathsPerSession; - var kda = S((K + (A / 4)) / D).toFloat(3) + ' kda'; + getSummonerId.on('fail', (errMessage) => { + e.message.channel.sendMessage(errMessage); + }); - lolapi.League.getEntriesBySummonerId(summonerID, function (err, leagues) { - if (err || leagues === null) { - bot.sendMessage({ - to: channelID, - message: player + ' is not ranked this season', - }); - } else { - var leaguesIndex = _.findIndex(leagues[summonerID], {queue: 'RANKED_SOLO_5x5'}); - var league = leagues[summonerID][leaguesIndex]; - var rank = league.tier + ' ' + league.entries[0].division; - bot.sendMessages(channelID, [ - player + ' is ranked in ' + rank + ' with ' + winloss + ',', - K + 'kills ' + D + 'deaths ' + A + 'assists with a ' + kda + ' which equates to ' + S(K / D).toFloat(3) + 'KD this season.', - ]); - } - }); - } - }); + getSummonerId.on('completed', (summonerID) => { + lolapi.Stats.getRanked(summonerID, null, (err, stats) => { + const player = _.isString(summonerName) ? summonerName : e.message.author.mention; + if (err || stats === null) { + e.message.channel.sendMessage(`${player} is not ranked this season`); + } else { + const combinedStatsIndex = _.findIndex(stats.champions, { id: 0 }); + const combinedStats = stats.champions[combinedStatsIndex]; + const winloss = `${combinedStats.stats.totalSessionsWon} wins & ${combinedStats.stats.totalSessionsLost} losses`; + + const K = combinedStats.stats.totalChampionKills; + const A = combinedStats.stats.totalAssists; + const D = combinedStats.stats.totalDeathsPerSession; + const kda = `${s((K + (A / 4)) / D).toFloat(3)} kda`; + + lolapi.League.getEntriesBySummonerId(summonerID, (error, leagues) => { + if (error || leagues === null) { + e.message.channel.sendMessage(`${player} is not ranked this season`); + } else { + const leaguesIndex = _.findIndex(leagues[summonerID], { queue: 'RANKED_SOLO_5x5' }); + const league = leagues[summonerID][leaguesIndex]; + const rank = `${league.tier} ${league.entries[0].division}`; + + let rankMessage = `${player} is ranked in ${rank} with ${winloss}\r\n`; + rankMessage += `${K}kills ${D}deaths ${A}assists with a ${kda} which equates to ${s(K / D).toFloat(3)}KD this season.`; + + e.message.channel.sendMessage(rankMessage); + } + }); + } }); }); } -}; +} diff --git a/modules/lol/modules/set-summoner.js b/modules/lol/modules/set-summoner.js index 7038e6e..a25688e 100644 --- a/modules/lol/modules/set-summoner.js +++ b/modules/lol/modules/set-summoner.js @@ -1,49 +1,49 @@ import { Config } from './../../../config'; import S from 'string'; -var lolapi = require('lolapi')(Config.league.apikey, Config.league.location); +const s = S; +const lolapi = require('lolapi')(Config.league.apikey, Config.league.location); import { leagueDb } from './util/league-db'; -export default function lolSetSummoner(bot, user, userID, channelID, message) { - if (S(message).contains('lolsetsummoner')) { - bot.simulateTyping(channelID, function () { - var splitMessage = message.split('='); - var summonerName = splitMessage[1]; +export default function lolSetSummoner(e, message) { + if (s(message).contains('lolsetsummoner')) { + e.message.channel.sendTyping(); - lolapi.Summoner.getByName(summonerName, function (error, summoner) { - if (error) throw error; + const splitMessage = message.split('='); + const summonerName = splitMessage[1]; + const userID = e.message.author.id; - var summonerId = summoner[summonerName].id; - var data = { + lolapi.Summoner.getByName(summonerName, (error, apisummoner) => { + try { + const summonerId = apisummoner[summonerName].id; + const data = { discordUserId: userID, leagueSummonerId: summonerId, }; - if (leagueDb.find({ + leagueDb.find({ discordUserId: userID, - }, function (err, summoner) { - if (S(summoner).isEmpty()) { - leagueDb.insert(data, function (err, newData) { - bot.sendMessage({ - to: channelID, - message: user + ' set ' + summonerName + ' as their league account for disbot.', - }); + }, (err, summoner) => { + if (s(summoner).isEmpty()) { + leagueDb.insert(data, (errorInsert) => { + if (errorInsert) { throw errorInsert; } + e.message.channel.sendMessage(`${e.message.author.mention} set ${summonerName} as their league account for disbott.`); }); } else { leagueDb.update( { discordUserId: userID }, { $set: { leagueSummonerId: summonerId } }, {}, - function (err, numReplaced) { - bot.sendMessage({ - to: channelID, - message: user + ' set ' + summonerName + ' as their league account for disbot.', - }); + (errorUpdate) => { + if (errorUpdate) { throw errorUpdate; } + e.message.channel.sendMessage(`${e.message.author.mention} set ${summonerName} as their updated league account for disbott.`); } ); } - })); - }); + }); + } catch (err) { + e.message.channel.sendMessage('There was an error, are you sure you spelt the summonername right?'); + } }); } -}; +} diff --git a/modules/lol/modules/util/gametype-constant.js b/modules/lol/modules/util/gametype-constant.js index 6bc7cd8..3f39b16 100644 --- a/modules/lol/modules/util/gametype-constant.js +++ b/modules/lol/modules/util/gametype-constant.js @@ -34,4 +34,5 @@ export default function gameMode(game) { return 'Poro King'; } } -}; + return 'error'; +} diff --git a/modules/lol/modules/util/get-summoner-id.js b/modules/lol/modules/util/get-summoner-id.js index d6fe4bb..f18d997 100644 --- a/modules/lol/modules/util/get-summoner-id.js +++ b/modules/lol/modules/util/get-summoner-id.js @@ -1,41 +1,41 @@ -export default function getSummonerIdFunction(S, lolapi, leagueDb, userID, getSummonerId, summonerName) { - if (!S(summonerName).isEmpty()) { - if (S(summonerName).startsWith('<@')) { - userID = S(summonerName).chompLeft('<@').s; - userID = S(userID).chompRight('>').s; - if (leagueDb.find({ - discordUserId: userID, - }, function (err, summoner) { - if (S(summoner).isEmpty()) { +export default function getSummonerIdFunction(s, lolapi, leagueDb, userID, getSummonerId, summonerName) { + if (!s(summonerName).isEmpty()) { + if (s(summonerName).startsWith('<@')) { + let discordUserId = s(summonerName).chompLeft('<@').s; + discordUserId = s(discordUserId).chompRight('>').s; + leagueDb.find({ + discordUserId, + }, (err, summoner) => { + if (s(summoner).isEmpty()) { getSummonerId.emit('fail', 'ERROR: Have they linked their lol account to discord with !lolsetsummoner=[yoursummonername]?'); } else { - var summonerID = summoner[0].leagueSummonerId; + const summonerID = summoner[0].leagueSummonerId; getSummonerId.emit('completed', summonerID); } - })); + }); } else { - lolapi.Summoner.getByName(summonerName, function (error, summoner) { + lolapi.Summoner.getByName(summonerName, (error, summoner) => { if (error) { getSummonerId.emit('fail', 'ERROR: Couldn\'t find a summoner with that name on EUW'); } else { - summonerName = S(summonerName).strip(' ').s; - summonerName = summonerName.toLowerCase(); + let lolSummonerName = s(summonerName).strip(' ').s; + lolSummonerName = lolSummonerName.toLowerCase(); - var summonerId = summoner[summonerName].id; + const summonerId = summoner[summonerName].id; getSummonerId.emit('completed', summonerId); } }); } } else { - if (leagueDb.find({ + leagueDb.find({ discordUserId: userID, - }, function (err, summoner) { - if (S(summoner).isEmpty()) { + }, (err, summoner) => { + if (s(summoner).isEmpty()) { getSummonerId.emit('fail', 'ERROR: Have you linked your league account with !lolsetsummoner=[yoursummonername]?'); } else { - var summonerID = summoner[0].leagueSummonerId; + const summonerID = summoner[0].leagueSummonerId; getSummonerId.emit('completed', summonerID); } - })); - }; -}; + }); + } +} diff --git a/modules/lol/modules/util/league-db.js b/modules/lol/modules/util/league-db.js index e25a162..b1b8c77 100644 --- a/modules/lol/modules/util/league-db.js +++ b/modules/lol/modules/util/league-db.js @@ -1,6 +1,6 @@ import Datastore from 'nedb'; -export var leagueDb = new Datastore({ +export const leagueDb = new Datastore({ filename: './datastores/league.db', autoload: true, }); diff --git a/modules/management/index.js b/modules/management/index.js index b5a0b45..553e804 100644 --- a/modules/management/index.js +++ b/modules/management/index.js @@ -3,15 +3,11 @@ // filename: './datastores/management.db', // autoload: true // }); -import _ from 'underscore'; -import S from 'string'; -import join from './modules/join'; import createTextInvite from './modules/create-text-invite'; import createVoiceInvite from './modules/create-voice-invite'; -export default function management(Config, bot, channelID, message, rawEvent) { - createTextInvite(_, S, bot, channelID, message); - createVoiceInvite(_, S, bot, channelID, message); - join(S, bot, channelID, message); -}; +export default function management(e, message) { + createTextInvite(e, message); + createVoiceInvite(e, message); +} diff --git a/modules/management/modules/create-text-invite.js b/modules/management/modules/create-text-invite.js index 48aba44..8aaf9b4 100644 --- a/modules/management/modules/create-text-invite.js +++ b/modules/management/modules/create-text-invite.js @@ -1,30 +1,28 @@ -export default function createTextInvite(_, S, bot, channelID, message) { - if (S(message).contains('createtextinvite=')) { - var splitMessage = message.split('='); - var inviteChannel = splitMessage[1]; +import _ from 'underscore'; +import S from 'string'; +const s = S; - var currentServerID = bot.serverFromChannel(channelID); +export default function createTextInvite(e, message) { + if (s(message).contains('createtextinvite=')) { + const splitMessage = message.split('='); + const inviteChannel = splitMessage[1]; - _.each(bot.servers, function (server) { - if (server.id === currentServerID) { - _.each(server.channels, function (channel) { - if (channel.type === 'text' && channel.name === inviteChannel) { - var expiresIn = (60 * 60) * 6; // 6hours - bot.createInvite({ - channel: channel.id, - max_age: expiresIn, - temporary: true, - }, function (err, res) { - bot.sendMessages(channelID, [ - 'The following code/link lasts for 6hours', - 'The instant invite code is ' + res.code + '.', - 'And the instant invite link is http://discord.gg/' + res.code, - ]); - }); - } + const server = e.message.channel.guild; + const channels = server.textChannels; + + _.each(channels, (channel) => { + if (channel.name === inviteChannel) { + const expiresIn = (60 * 60) * 6; // 6hours + channel.createInvite({ + max_age: expiresIn, + }).then((res) => { + let inviteMessage = 'The following code/link lasts for 6hours\r\n'; + inviteMessage += `The instant invite code is ${res.code}\r\n`; + inviteMessage += `And the instant invite link is http://discord.gg/${res.code}`; + + e.message.channel.sendMessage(inviteMessage); }); } }); - } }; diff --git a/modules/management/modules/create-voice-invite.js b/modules/management/modules/create-voice-invite.js index aed1130..d1f7407 100644 --- a/modules/management/modules/create-voice-invite.js +++ b/modules/management/modules/create-voice-invite.js @@ -1,30 +1,28 @@ -export default function createVoiceInvite(_, S, bot, channelID, message) { - if (S(message).contains('createvoiceinvite=')) { - var splitMessage = message.split('='); - var inviteChannel = splitMessage[1]; +import _ from 'underscore'; +import S from 'string'; +const s = S; - var currentServerID = bot.serverFromChannel(channelID); +export default function createVoiceInvite(e, message) { + if (s(message).contains('createvoiceinvite=')) { + const splitMessage = message.split('='); + const inviteChannel = splitMessage[1]; - _.each(bot.servers, function (server) { - if (server.id === currentServerID) { - _.each(server.channels, function (channel) { - if (channel.type === 'voice' && channel.name === inviteChannel) { - var expiresIn = (60 * 60) * 6; // 6hours - bot.createInvite({ - channel: channel.id, - max_age: expiresIn, - temporary: true, - }, function (err, res) { - bot.sendMessages(channelID, [ - 'The following code/link lasts for 6hours', - 'The instant invite code is ' + res.code + '.', - 'And the instant invite link is http://discord.gg/' + res.code, - ]); - }); - } + const server = e.message.channel.guild; + const channels = server.voiceChannels; + + _.each(channels, (channel) => { + if (channel.name === inviteChannel) { + const expiresIn = (60 * 60) * 6; // 6hours + channel.createInvite({ + max_age: expiresIn, + }).then((res) => { + let inviteMessage = 'The following code/link lasts for 6hours\r\n'; + inviteMessage += `The instant invite code is ${res.code}\r\n`; + inviteMessage += `And the instant invite link is http://discord.gg/${res.code}`; + + e.message.channel.sendMessage(inviteMessage); }); } }); - } -}; +} diff --git a/modules/management/modules/join.js b/modules/management/modules/join.js deleted file mode 100644 index ce5a8a8..0000000 --- a/modules/management/modules/join.js +++ /dev/null @@ -1,21 +0,0 @@ -export default function join(S, bot, channelID, message) { - if (S(message).contains('join=')) { - var splitMessage = message.split('='); - var code = splitMessage[1]; - - bot.acceptInvite(code, function (err, res) { - console.log(err, res); - if (err) { - bot.sendMessage({ - to: channelID, - message: err + '. Did you mean `sound=' + code + '`?', - }); - } else { - bot.sendMessage({ - to: channelID, - message: 'Joining channel: ' + res.channel.name + ' on ' + res.guild.name, - }); - } - }); - } -}; diff --git a/modules/messagecount.js b/modules/messagecount.js new file mode 100644 index 0000000..c61f244 --- /dev/null +++ b/modules/messagecount.js @@ -0,0 +1,46 @@ +import Datastore from 'nedb'; +export const messagecountDb = new Datastore({ + filename: './datastores/messagecount.db', + autoload: true, +}); + +import S from 'string'; +const string = S; + +export function messagecountCommand(e, message) { + if (string(message).contains('messagecount=')) { + const splitMessage = message.split('= '); + + const username = splitMessage[1]; + let userID = string(username).chompLeft('<@').s; + userID = string(userID).chompRight('>').s; + + messagecountDb.findOne({ + userID, + }, (err, discordUser) => { + e.message.reply(`<@${userID}> has made ${discordUser.messagecount} posts`); + }); + } +} + +export function messageCountLog(e) { + const authorID = e.message.author.id; + messagecountDb.findOne({ userID: authorID }, (err, user) => { + if (user === null) { + // New User + messagecountDb.insert({ + userID: authorID, + messagecount: 1, + }); + } else { + // Update User + const oldMessagecount = user.messagecount; + const newMessagecount = oldMessagecount + 1; + messagecountDb.update({ + userID: authorID, + }, { + $set: { messagecount: newMessagecount }, + }); + } + }); +} diff --git a/modules/poll/index.js b/modules/poll/index.js new file mode 100644 index 0000000..49c6c62 --- /dev/null +++ b/modules/poll/index.js @@ -0,0 +1,13 @@ +const Datastore = require('nedb'); +const pollDb = new Datastore({ + filename: './datastores/poll.db', + autoload: true, +}); + +import startPoll from './modules/start-poll'; +import votePoll from './modules/vote-poll'; + +export default function poll(e, message) { + startPoll(pollDb, e, message); + votePoll(pollDb, e, message); +} diff --git a/modules/poll/modules/poll-result.js b/modules/poll/modules/poll-result.js new file mode 100644 index 0000000..f2cb89b --- /dev/null +++ b/modules/poll/modules/poll-result.js @@ -0,0 +1,28 @@ +export default function pollResult(pollDb, e) { + const time = 60 * 1000; + setTimeout(() => { + pollDb.find({ enabled: true }, (err, result) => { + if (result.length !== 0) { + const poll = result[0]; + const yTotal = poll.result.y; + const nTotal = poll.result.n; + const totalVotes = yTotal + nTotal; + const yPercent = (yTotal / totalVotes) * 100; + const nPercent = (nTotal / totalVotes) * 100; + + e.message.channel.sendMessage(`The poll: ${poll.topic} Results are in:`); + e.message.channel.sendMessage(`Yes: ${yTotal} - ${yPercent}%`); + e.message.channel.sendMessage(`No: ${nTotal} - ${nPercent}%`); + if (yTotal > nTotal) { + e.message.channel.sendMessage('The yeses have it!'); + } else { + e.message.channel.sendMessage('The noes have it!'); + } + + pollDb.remove({}, { multi: true }); + } else { + e.message.message.channel.sendMessage('There was no poll'); + } + }); + }, time); +} diff --git a/modules/poll/modules/start-poll.js b/modules/poll/modules/start-poll.js new file mode 100644 index 0000000..69a8873 --- /dev/null +++ b/modules/poll/modules/start-poll.js @@ -0,0 +1,27 @@ +import pollResult from './poll-result.js'; + +export default function startPoll(pollDb, e, message) { + if (message.indexOf('startpoll') > -1) { + const splitMessage = message.split('='); + const topic = splitMessage[1]; + + pollDb.find({ enabled: true }, (err, result) => { + if (result.length === 0) { + pollDb.insert({ + enabled: true, + topic, + result: { + y: 0, + n: 0, + }, + }, () => { + pollResult(pollDb, e); + + e.message.channel.sendMessage(`Starting Poll for 60s on: ${topic}`); + }); + } else { + e.message.channel.sendMessage('There is already a poll in progress'); + } + }); + } +} diff --git a/modules/poll/modules/vote-poll.js b/modules/poll/modules/vote-poll.js new file mode 100644 index 0000000..bbb377e --- /dev/null +++ b/modules/poll/modules/vote-poll.js @@ -0,0 +1,38 @@ +export default function votePoll(pollDb, e, message) { + if (message.indexOf('votepoll') > -1) { + const splitMessage = message.split('='); + const vote = splitMessage[1]; + + pollDb.find({ enabled: true }, (err, result) => { + if (result.length !== 0) { + const poll = result[0]; + const pollId = poll._id; + if (vote === 'y') { + const newYTotal = poll.result.y + 1; + pollDb.update( + { _id: pollId }, + { $set: { result: { + y: newYTotal, + n: poll.result.n, + } } }, + { multi: true } + ); + } else if (vote === 'n') { + const newNTotal = poll.result.n + 1; + pollDb.update( + { _id: pollId }, + { $set: { result: { + y: poll.result.y, + n: newNTotal, + } } }, + { multi: true } + ); + } else { + e.message.channel.sendMessage('Please only use vote=y or vote=n'); + } + } else { + e.message.channel.sendMessage('There isn\'t a poll in progress'); + } + }); + } +} diff --git a/modules/remindme/command.js b/modules/remindme/command.js index d0d7eb4..a685ff3 100644 --- a/modules/remindme/command.js +++ b/modules/remindme/command.js @@ -1,43 +1,42 @@ import { remindmeDb } from './remindmeDb'; import S from 'string'; +const s = S; import moment from 'moment'; -export default function remindmeCommand(bot, user, userID, channelID, message) { - if (S(message).contains('remindme=')) { - var splitMessage = message.split('='); - var timeAndMessage = splitMessage[1].split(';'); +export default function remindmeCommand(e, message) { + if (s(message).contains('remindme=')) { + const splitMessage = message.split('='); + const timeAndMessage = splitMessage[1].split(';'); - var timeTo = timeAndMessage[0].split('.'); - var countTimeToArray = timeTo.length / 2; - var currentTime = moment(); - var time = moment(); + const timeTo = timeAndMessage[0].split('.'); + const countTimeToArray = timeTo.length / 2; + const currentTime = moment(); + let time = moment(); - for (var i = 0; i < countTimeToArray; i++) { - var amountOfTime = timeTo[i]; - var unitOfTime = timeTo[i + 1]; + for (let i = 0; i < countTimeToArray; i++) { + const amountOfTime = timeTo[i]; + const unitOfTime = timeTo[i + 1]; time = time.add(amountOfTime, unitOfTime); i++; } - var setTime = currentTime.format(); - var remindTime = time.format(); - var timeToNice = time.fromNow(); + const setTime = currentTime.format(); + const remindTime = time.format(); + const timeToNice = time.fromNow(); - var remindMessage = timeAndMessage[1]; + const remindMessage = timeAndMessage[1]; - var data = { - userID: userID, - setTime: setTime, - remindTime: remindTime, - remindMessage: remindMessage, + const data = { + userID: e.message.author.id, + setTime, + remindTime, + remindMessage, }; - remindmeDb.insert(data, function (err, newDoc) { - bot.sendMessage({ - to: channelID, - message: 'I will remind you (<@' + userID + '>) ' + timeToNice + ': ' + remindMessage, - }); + remindmeDb.insert(data, (err) => { + if (err) { throw err; } + e.message.channel.sendMessage(`I will remind you (${e.message.author.mention}) ${timeToNice}: ${remindMessage}`); }); } -}; +} diff --git a/modules/remindme/index.js b/modules/remindme/index.js index 1552d6b..414a6ce 100644 --- a/modules/remindme/index.js +++ b/modules/remindme/index.js @@ -3,18 +3,19 @@ import { remindmeDb } from './remindmeDb'; import _ from 'underscore'; import moment from 'moment'; -export default function remindme(bot) { - setInterval(function () { - remindmeDb.find({ remindTime: moment().format() }, function (err, reminders) { +export default function remindme(client) { + setInterval(() => { + remindmeDb.find({ remindTime: moment().format() }, (err, reminders) => { if (reminders.length > 0) { - _.each(reminders, function (reminder) { - var setTime = moment(reminder.setTime).fromNow(); - bot.sendMessage({ - to: reminder.userID, - message: 'Hi, this is disbott reminding you: ' + reminder.remindMessage + '; from ' + setTime, + _.each(reminders, (reminder) => { + const setTime = moment(reminder.setTime).fromNow(); + + const user = client.Users.find(u => u.id === reminder.userID); + user.openDM().then((channel) => { + channel.sendMessage(`Hi, this is disbott reminding you: ${reminder.remindMessage}; from ${setTime}`); }); }); } }); }, 1000); -}; +} diff --git a/modules/remindme/remindmeDb.js b/modules/remindme/remindmeDb.js index 98add78..d3adee9 100644 --- a/modules/remindme/remindmeDb.js +++ b/modules/remindme/remindmeDb.js @@ -1,5 +1,5 @@ import Datastore from 'nedb'; -export var remindmeDb = new Datastore({ +export const remindmeDb = new Datastore({ filename: './datastores/remindme.db', autoload: true, }); diff --git a/modules/silly.js b/modules/silly.js index 9e07357..e158096 100644 --- a/modules/silly.js +++ b/modules/silly.js @@ -1,9 +1,13 @@ // Chunder -export function chunder(bot, channelID, message) { +// TODO: Implement this +export function setChunder(e, message) { + if (message === 'setchunder=') { + e.message.channel.sendMessage('<@105753535659921408> is the new chunder king!'); + } +} + +export function chunder(e, message) { if (message === 'who is the chunder king?') { - bot.sendMessage({ - to: channelID, - message: '<@105753535659921408> is the chunder king!', - }); + e.message.channel.sendMessage('<@105753535659921408> is the chunder king!'); } -}; +} diff --git a/modules/sound/index.js b/modules/sound/index.js index ed17a72..358a4e6 100644 --- a/modules/sound/index.js +++ b/modules/sound/index.js @@ -1,28 +1,28 @@ -import Datastore from 'nedb'; -var soundDb = new Datastore({ - filename: './datastores/sound.db', - autoload: true, -}); - -import S from 'string'; - -import disconnect from './modules/disconnect'; import joinVoiceChannel from './modules/join-voice-channel'; -import stopSound from './modules/stopsound'; import listSounds from './modules/list-sounds'; import playSound from './modules/play-sound'; -export default function sound(Config, bot, channelID, message, rawEvent) { - soundDb.find({ enabled: true }, function (err, data) { - if (data.length > 0) { - var voiceChannelID = data[0].voiceChannelID; - stopSound(bot, channelID, message, voiceChannelID); - disconnect(soundDb, bot, channelID, message, voiceChannelID); - playSound(S, bot, channelID, message, voiceChannelID); - } else if (S(message).contains('sound=')) { - joinVoiceChannel(Config, soundDb, bot, channelID, message); +export default function sound(client, e, message) { + listSounds(e, message); + + if (!client.VoiceConnections.length) { + if (message === 'vjoin') { + joinVoiceChannel(e, message); + return; + } + } else { + if (message === 'vjoin') { + e.message.reply('disbott is already connected'); + } + + let stopPlaying = false; + + if (message === 'vstop' || message === 'vleave') { + stopPlaying = true; } - }); - listSounds(Config, bot, channelID, message); -}; + playSound(client, e, message, stopPlaying); + + return; + } +} diff --git a/modules/sound/modules/disconnect.js b/modules/sound/modules/disconnect.js deleted file mode 100644 index 4d98040..0000000 --- a/modules/sound/modules/disconnect.js +++ /dev/null @@ -1,13 +0,0 @@ -export default function disconnect(soundDb, bot, channelID, message, voiceChannelID) { - if (message === 'sounddisconnect') { - bot.sendMessage({ - to: channelID, - message: 'Disconnecting from Voice Channel', - }, function () { - bot.leaveVoiceChannel(voiceChannelID); - soundDb.remove({ enabled: true }, { multi: true }, function (err, numRemoved) {}); - - soundDb.remove({ enabled: false }, { multi: true }, function (err, numRemoved) {}); - }); - } -}; diff --git a/modules/sound/modules/fileupload.js b/modules/sound/modules/fileupload.js index 102f757..2dfc80e 100644 --- a/modules/sound/modules/fileupload.js +++ b/modules/sound/modules/fileupload.js @@ -1,47 +1,46 @@ -var fs = require('fs'); -var url = require('url'); -var http = require('http'); -var exec = require('child_process').exec; -var spawn = require('child_process').spawn; +const fs = require('fs'); +const url = require('url'); +const http = require('http'); +// const exec = require('child_process').exec; +// const spawn = require('child_process').spawn; -var DOWNLOAD_DIR = './modules/sound/sounds/'; +const DOWNLOAD_DIR = './modules/sound/sounds/'; -export default function fileupload(bot, channelID, rawEvent) { - if (rawEvent.d.attachments.length > 0) { - var fileUrl = rawEvent.d.attachments[0].url; - var fileExt = rawEvent.d.attachments[0].url.split('.').pop(); +export default function soundFileupload(e) { + if (e.message.isPrivate) { + if (e.message.attachments.length > 0) { + const niceFileName = e.message.attachments[0].filename.split('.').shift(); - // Function to download file using HTTP.get - var downloadFileHttpget = function (fileUrl) { - var options = { - host: url.parse(fileUrl).host, - port: 80, - path: url.parse(fileUrl).pathname, - }; + // Function to download file using HTTP.get + const downloadFileHttpget = (fileUrl) => { + const options = { + host: url.parse(fileUrl).host, + port: 80, + path: url.parse(fileUrl).pathname, + }; - var fileName = url.parse(fileUrl).pathname.split('/').pop(); - var file = fs.createWriteStream(DOWNLOAD_DIR + fileName); + const fileName = url.parse(fileUrl).pathname.split('/').pop(); + const file = fs.createWriteStream(DOWNLOAD_DIR + fileName); - http.get(options, function (res) { - res.on('data', function (data) { - file.write(data); - }).on('end', function () { - file.end(); - bot.sendMessage({ - to: channelID, - message: fileName + ' Uploaded' + http.get(options, (res) => { + res.on('data', (data) => { + file.write(data); + }).on('end', () => { + file.end(); + e.message.channel.sendMessage(`${niceFileName} uploaded!\r\nYou can use \`vplay=${niceFileName}\` to hear it.`); }); }); - }); - }; + }; + + const fileUrl = e.message.attachments[0].url; + const fileExt = e.message.attachments[0].url.split('.').pop(); - if (fileExt === 'mp3') { - bot.sendMessage({ - to: channelID, - message: 'Uploading file...' - }, function () { + if (fileExt === 'mp3') { + e.message.channel.sendMessage(`Uploading ${niceFileName}...`); downloadFileHttpget(fileUrl); - }); + } else { + e.message.channel.sendMessage('I only accept mp3 files'); + } } } -}; +} diff --git a/modules/sound/modules/join-voice-channel.js b/modules/sound/modules/join-voice-channel.js index d9a3a27..272ff8f 100644 --- a/modules/sound/modules/join-voice-channel.js +++ b/modules/sound/modules/join-voice-channel.js @@ -1,20 +1,8 @@ -export default function joinVoiceChannel(Config, soundDb, bot, channelID, message) { - bot.sendMessage({ - to: channelID, - message: 'Getting ready to play...', - }, function () { - var splitMessage = message.split('='); - var inviteCode = splitMessage[1]; - bot.queryInvite(inviteCode, function (err, response) { - if (err) return console.log(err); - var voiceChannelID = response.channel.id; - bot.joinVoiceChannel(voiceChannelID, function () { - var data = { - enabled: true, - voiceChannelID: voiceChannelID, - }; - soundDb.insert(data, function (err, newDoc) {}); - }); - }); +export default function joinVoiceChannel(e) { + const author = e.message.member; + const authorVoiceChannel = author.getVoiceChannel(); + + authorVoiceChannel.join().then(() => { + e.message.channel.sendMessage('Ready to play!'); }); -}; +} diff --git a/modules/sound/modules/list-sounds.js b/modules/sound/modules/list-sounds.js index db80544..87e4fc0 100644 --- a/modules/sound/modules/list-sounds.js +++ b/modules/sound/modules/list-sounds.js @@ -1,8 +1,7 @@ -export default function listSounds(Config, bot, channelID, message, voiceChannelID) { +import { Config } from './../../../config.js'; + +export default function listSounds(e, message) { if (message === 'listsounds') { - bot.sendMessage({ - to: channelID, - message: 'View our list of sounds here: ' + Config.domain + '/soundlist.html' - }); + e.message.channel.sendMessage(`View our list of sounds here: ${Config.domain}/soundlist.html`); } -}; +} diff --git a/modules/sound/modules/play-sound.js b/modules/sound/modules/play-sound.js index fc365e8..c5554ab 100644 --- a/modules/sound/modules/play-sound.js +++ b/modules/sound/modules/play-sound.js @@ -1,20 +1,77 @@ -export default function playSound(S, bot, channelID, message, voiceChannelID) { - if (S(message).contains('playsound=')) { - var splitMessage = message.split('='); - var song = splitMessage[1]; - bot.sendMessage({ - to: channelID, - message: 'Playing ' + song, - }, function () { - bot.getAudioContext({ channel: voiceChannelID, stereo: true }, function (stream) { - stream.playAudioFile('./modules/sound/sounds/' + song); - stream.once('fileEnd', function () { - bot.sendMessage({ - to: channelID, - message: 'Finished Playing ' + song, - }); - }); - }); +// const fs = require('fs'); +import S from 'string'; +const s = S; + +export default function playSound(client, e, message) { + const guild = e.message.channel.guild; + + function stop() { + const info = client.VoiceConnections.getForGuild(guild); + if (info) { + const encoderStream = info.voiceConnection.getEncoderStream(); + encoderStream.unpipeAll(); + } + } + + function play(info, song) { + let newInfo = info; + if (!client.VoiceConnections.length) { + return console.log('Voice not connected'); // eslint-disable-line + } + + if (!info) newInfo = client.VoiceConnections[0]; + + const encoder = newInfo.voiceConnection.createExternalEncoder({ + type: 'ffmpeg', + source: `./modules/sound/sounds/${song}.mp3`, + frameDuration: 60, + format: 'opus', + inputArgs: [], + outputArgs: ['-af', 'volume=0.04'], + debug: true, + }); + if (!encoder) return console.log('Voice connection is no longer valid'); // eslint-disable-line + + encoder.once('end', () => { + e.message.channel.sendMessage(`Finished playing ${song}`); }); + + const encoderStream = encoder.play(); + encoderStream.resetTimestamp(); + encoderStream.removeAllListeners('timestamp'); + // encoderStream.on('timestamp', time => console.log(`${time} time`)); // eslint-disable-line + return true; + } + + + if (s(message).contains('vplay=') || message === 'vstop' || message === 'vleave') { + const splitMessage = message.split('='); + const song = splitMessage[1]; + + if (s(message).contains('vplay=')) { + if (!client.VoiceConnections.length) { + return e.message.reply('Not connected to any channel'); + } + const info = client.VoiceConnections.getForGuild(guild); + e.message.channel.sendMessage(`Attempting to play ${song}`); + if (info) play(info, song); + } else if (message === 'vleave') { + stop(); + + client.Channels + .filter(channel => channel.type === 'voice') + .forEach(channel => { + if (channel.joined) { + channel.leave(); + } + }); + + e.message.channel.sendMessage('Disconnected!'); + } else { + stop(); + e.message.channel.sendMessage('Stopping...'); + } } -}; + + return true; +} diff --git a/modules/sound/modules/stopsound.js b/modules/sound/modules/stopsound.js deleted file mode 100644 index 0394c2a..0000000 --- a/modules/sound/modules/stopsound.js +++ /dev/null @@ -1,18 +0,0 @@ -export default function stopSound(bot, channelID, message, voiceChannelID) { - if (message === 'stopsound') { - bot.sendMessage({ - to: channelID, - message: 'Stopping Audio...', - }, function () { - bot.getAudioContext(voiceChannelID, function (stream) { - stream.stopAudioFile(); - stream.once('fileEnd', function () { - bot.sendMessage({ - to: channelID, - message: 'Stopped!', - }); - }); - }); - }); - } -}; diff --git a/modules/twitter/index.js b/modules/twitter/index.js index cd4fe73..df116d0 100644 --- a/modules/twitter/index.js +++ b/modules/twitter/index.js @@ -1,7 +1,7 @@ import { Config } from './../../config'; import Twit from 'twit'; -var T = new Twit({ +const T = new Twit({ consumer_key: Config.twitter.consumer_key, consumer_secret: Config.twitter.consumer_secret, access_token: Config.twitter.access_token, @@ -12,8 +12,8 @@ import { mirin } from './modules/mirin'; import { gazo } from './modules/gazo'; import { headline } from './modules/headline'; -export default function twitter(bot, channelID, message) { - mirin(T, bot, channelID, message); - headline(T, bot, channelID, message); - gazo(T, bot, channelID, message); -}; +export default function twitter(e, message) { + mirin(T, e, message); + headline(T, e, message); + gazo(T, e, message); +} diff --git a/modules/twitter/modules/gazo.js b/modules/twitter/modules/gazo.js index 9d0b165..0fc0fbb 100644 --- a/modules/twitter/modules/gazo.js +++ b/modules/twitter/modules/gazo.js @@ -1,19 +1,16 @@ -import S from 'string'; - -export function gazo(T, bot, channelID, message) { +export function gazo(T, e, message) { if (message === 'gazo') { T.get('statuses/user_timeline', { screen_name: 'idol_gazo', count: 50, - }, function (err, data) { - var tweet = data[Math.floor(Math.random() * data.length)]; - var person = tweet.text.split(' #')[0]; - var image = tweet.entities.media[0].media_url_https; + }, (err, data) => { + const tweet = data[Math.floor(Math.random() * data.length)]; + const person = tweet.text.split(' #')[0]; + const image = tweet.entities.media[0].media_url_https; + + const gazoMessage = `${person}"\r\n"${image}`; - bot.sendMessages(channelID, [ - person, - image, - ]); + e.message.channel.sendMessage(gazoMessage); }); } -}; +} diff --git a/modules/twitter/modules/headline.js b/modules/twitter/modules/headline.js index 2f7d422..4aedf6d 100644 --- a/modules/twitter/modules/headline.js +++ b/modules/twitter/modules/headline.js @@ -1,17 +1,15 @@ import moment from 'moment'; -export function headline(T, bot, channelID, message) { +export function headline(T, e, message) { if (message === 'headline') { T.get('statuses/user_timeline', { screen_name: 'guardian', count: 1, - }, function (err, data) { - var tweet = data[0]; - bot.sendMessages(channelID, [ - 'Via. The Guardian', - tweet.text, - 'Posted approx. ' + moment(tweet.created_at).fromNow(), - ]); + }, (err, data) => { + const tweet = data[0]; + const headlineMessage = `Via. The Guardian\r\n${tweet.text}\r\nPosted approx. ${moment(tweet.created_at).fromNow()}`; + + e.message.channel.sendMessage(headlineMessage); }); } -}; +} diff --git a/modules/twitter/modules/mirin.js b/modules/twitter/modules/mirin.js index ae7c30d..139f1aa 100644 --- a/modules/twitter/modules/mirin.js +++ b/modules/twitter/modules/mirin.js @@ -1,16 +1,16 @@ import moment from 'moment'; -export function mirin(T, bot, channelID, message) { +export function mirin(T, e, message) { if (message === 'mirin') { T.get('statuses/user_timeline', { screen_name: 'FurukawaMirin', count: 1, - }, function (err, data) { - var tweet = data[0]; - bot.sendMessages(channelID, [ - 'Mirin last said: ' + tweet.text + ' approx. ' + moment(tweet.created_at).fromNow(), - 'https://twitter.com/FurukawaMirin/status/' + tweet.id, - ]); + }, (err, data) => { + const tweet = data[0]; + + const mirinMessage = `Mirin last said:\r\n${tweet.text}\r\nApprox. ${moment(tweet.created_at).fromNow()} - https://twitter.com/FurukawaMirin/status/${tweet.id}`; + + e.message.channel.sendMessage(mirinMessage); }); } -}; +} diff --git a/modules/utils.js b/modules/utils.js index d6da9c8..8d0018e 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -1,52 +1,51 @@ +import { Config } from './../config'; + // About Command -export function about(Config, bot, channelID, message) { +export function about(e, message) { if (message === 'about') { - bot.sendMessage({ - to: channelID, - message: 'Hello, I\'m Disbott. A bot for Discord. Find out more about me here ' + Config.domain, - }); + e.message.channel.sendMessage(`Hello, I\'m Disbott. A bot for Discord. Find out more about me here ${Config.domain}`); } -}; +} // Help Command -export function help(Config, bot, channelID, message) { +export function help(e, message) { if (message === 'help') { - bot.sendMessage({ - to: channelID, - message: 'You can find my command list here: ' + Config.domain + '/#commands', - }); + e.message.channel.sendMessage(`You can find my command list here: ${Config.domain}/#commands`); } -}; +} // Info Command -export function info(Config, bot, channelID, message) { +export function info(e, message) { if (message === 'info') { - // version, uptime - bot.sendMessage({ - to: channelID, - message: 'Disbott Version ' + process.env.npm_package_version + ', ' + Config.domain, - }); + e.message.channel.sendMessage(`Disbott Version ${process.env.npm_package_version}, ${Config.domain}`); + } +} + +// Ping Command +export function ping(e, message) { + if (message === 'ping') { + e.message.channel.sendMessage(`${e.message.author.mention}, pong`); } -}; +} -// Kill Command -export function kill(bot, channelID, message) { - if (message === 'killdisbott') { - bot.sendMessage({ - to: channelID, - message: 'Killing self, brb', - }, function () { - bot.disconnect(); +// User has joined +export function userHasJoinedVoiceChannel(e) { + if (e.channel.position === 0) { + const channel = e.channel.guild.generalChannel; + channel.sendMessage(`${e.user.username} joined ${e.channel.name}`, true).then((result) => { + result.delete(); }); } -}; +} -// Ping Command -export function ping(bot, channelID, message) { - if (message === 'ping') { - bot.sendMessage({ - to: channelID, - message: 'pong', +export function deleteMessages(e, message) { + if (message === 'deleteall') { + const channel = e.message.channel; + channel.sendMessage('Attempting to delete messages'); + channel.fetchMessages(100).then(() => { + channel.messages.forEach((messageData) => { + messageData.delete(); + }); }); } -}; +} diff --git a/package.json b/package.json index 7c13881..3ae9fb1 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,24 @@ { "name": "disbott", - "version": "0.20.0", + "version": "1.0.0", "description": "A bot for Discord", "scripts": { "start:bot": "babel-node --presets es2015 ./bot.js", - "start:web": "babel-node --presets es2015 ./server.js" + "start": "babel-node --presets es2015 ./server.js", + "test": "ava --serial --tap | tap-summary" }, "author": "tomo@pagu", "dependencies": { "babel-cli": "^6.6.5", + "babel-eslint": "^6.0.3", "babel-preset-es2015": "^6.6.0", - "discord.io": "~1.8", + "discordie": "^0.6.0", "dotenv": "^1.2.0", + "eslint": "^2.8.0", + "eslint-config-airbnb": "^8.0.0", + "eslint-plugin-import": "^1.5.0", + "eslint-plugin-jsx-a11y": "^1.0.2", + "eslint-plugin-react": "^5.0.1", "express": "^4.13.3", "lolapi": "git://github.com/emmorts/lolapi.git#77a4c8c4899c7823ab73e43d4fb72641db02672c", "moment": "^2.10.6", @@ -20,5 +27,12 @@ "twit": "^2.1.1", "underscore": "^1.8.3" }, - "devDependencies": {} + "devDependencies": { + "async": "^1.5.2", + "ava": "^0.14.0", + "tap-summary": "^1.2.0" + }, + "ava": { + "require": "babel-register" + } } diff --git a/procfile b/procfile deleted file mode 100644 index 9d92d60..0000000 --- a/procfile +++ /dev/null @@ -1 +0,0 @@ -web: npm run start:web \ No newline at end of file diff --git a/server.js b/server.js index cb54b9d..110ec32 100644 --- a/server.js +++ b/server.js @@ -1,32 +1,32 @@ -var Config = require('./config'); +import { Config } from './config'; -var fs = require('fs'); +const fs = require('fs'); -var lolapi = require('lolapi')(Config.league.apikey, Config.league.location); -var _ = require('underscore'); -var EventEmitter = require('events'); -var moment = require('moment'); -var gameMode = require('./modules/lol/modules/util/gametype-constant'); +const lolapi = require('lolapi')(Config.league.apikey, Config.league.location); +import _ from 'underscore'; +const EventEmitter = require('events'); +import moment from 'moment'; +import gameMode from './modules/lol/modules/util/gametype-constant'; -var express = require('express'); -var app = express(); +const express = require('express'); +const app = express(); app.use(express.static('web')); -app.get('/api/lol/current-game', function (req, res) { - var summonerID = req.query.summonerID; - lolapi.CurrentGame.getBySummonerId(summonerID, function (error, game) { +app.get('/api/lol/current-game', (req, res) => { + const summonerID = req.query.summonerID; + lolapi.CurrentGame.getBySummonerId(summonerID, (error, currentGameInfo) => { if (error) { res.status(404).json({ error: 'No Game Found' }); - console.log(error); } else { + const game = currentGameInfo; game.gameType = gameMode(game); game.gameLength = moment(game.gameStartTime).toNow(true); - var getChampions = new EventEmitter(); - var count = (game.participants.length - 1); - _.each(game.participants, function (participant, i) { - lolapi.Static.getChampion(participant.championId, function (error, champion) { + const getChampions = new EventEmitter(); + const count = (game.participants.length - 1); + _.each(game.participants, (participant, i) => { + lolapi.Static.getChampion(participant.championId, (err, champion) => { game.participants[i].champion = champion.name; // Only send the json when we've set all the champions @@ -36,24 +36,24 @@ app.get('/api/lol/current-game', function (req, res) { }); }); - getChampions.on('completed', function (game) { - _.groupBy(game.participants, 'teamId'); - res.json(game); + getChampions.on('completed', (currentGame) => { + _.groupBy(currentGame.participants, 'teamId'); + res.json(currentGame); }); } }); }); -app.get('/api/sounds', function (req, res) { - fs.readdir('./modules/sound/sounds/', function (err, files) { - var sounds = _.without(files, '.DS_Store', '.gitignore'); +app.get('/api/sounds', (req, res) => { + fs.readdir('./modules/sound/sounds/', (err, files) => { + const sounds = _.without(files, '.DS_Store', '.gitignore', 'ENV'); res.json(sounds); }); }); -var server = app.listen(5000, function () { - var host = server.address().address; - var port = server.address().port; +const server = app.listen(5000, () => { + const host = server.address().address; + const port = server.address().port; - console.log('Example app listening at http://%s:%s', host, port); + console.log('Disbott Web listening at http://%s:%s', host, port); // eslint-disable-line }); diff --git a/test.js b/test.js new file mode 100644 index 0000000..8e1eb1f --- /dev/null +++ b/test.js @@ -0,0 +1,99 @@ +import test from 'ava'; + +import { Config } from './config'; + +import Discordie from 'discordie'; +const client = new Discordie(); + +function sendMessage(message, toBot) { + const guild = client.Guilds.find(g => g.name === 'Disbott Test'); + const channel = guild.textChannels.find(c => c.name === 'tests'); + const botUser = guild.members.find(m => m.username === 'disbott-dev'); + if (toBot) { + return channel.sendMessage(`${botUser.mention} ${message}`); + } + return channel.sendMessage(message); +} + +function returnMessage() { + client.Dispatcher.on('MESSAGE_CREATE', e => { + return e.message.content; + }); +} + +test.serial.cb.before('Can connect to Discord', t => { + client.connect({ + token: Config.discord.testerToken, + }); + + client.Dispatcher.on('GATEWAY_READY', () => { + sendMessage('Hello! I\'m the Disbott Tester. Beginning Tests').then((result, error) => { + if (error) { + console.log(error); + t.fail(); + } + + t.pass(); + t.end(); + }); + }); +}); + +test.serial.cb('Check ping command', t => { + sendMessage('ping', true).then((result, error) => { + if (error) { t.fail(); } + + setTimeout(() => { + const messages = client.Messages.toArray(); + const message = messages.slice(-1)[0]; + t.is(message.content, `<@${client.User.id}>, pong`); + t.end(); + }, 300); + }); +}); + +test.serial.cb('Check about command', t => { + sendMessage('about', true).then((result, error) => { + if (error) { t.fail(); } + + setTimeout(() => { + const messages = client.Messages.toArray(); + const message = messages.slice(-1)[0]; + t.is(message.content, 'Hello, I\'m Disbott. A bot for Discord. Find out more about me here https://disbott.pagu.co'); + t.end(); + }, 300); + }); +}); + +test.serial.cb('Check help command', t => { + sendMessage('help', true).then((result, error) => { + if (error) { t.fail(); } + + setTimeout(() => { + const messages = client.Messages.toArray(); + const message = messages.slice(-1)[0]; + t.is(message.content, 'You can find my command list here: https://disbott.pagu.co/#commands'); + t.end(); + }, 300); + }); +}); + +test.serial.cb('Check info command', t => { + sendMessage('info', true).then((result, error) => { + if (error) { t.fail(); } + + setTimeout(() => { + const messages = client.Messages.toArray(); + const message = messages.slice(-1)[0]; + t.is(message.content, 'Disbott Version 1.0.0, https://disbott.pagu.co'); + t.end(); + }, 300); + }); +}); + +test.after('Disconnect', (t) => { + return sendMessage('deleteall', true).then((result) => { + client.disconnect(); + t.pass(); + }); +}); diff --git a/web/Site/index.html b/web/Site/index.html new file mode 100644 index 0000000..1c95cc1 --- /dev/null +++ b/web/Site/index.html @@ -0,0 +1,119 @@ + + +
+ +All commands must start with @disbott (or if you have named it something else that!) to not conflict with anyother bots and conform to the
Discord Bot Best Practices.
An example command would be @disbott ping. +
Brings up this command list!
+Tells you who the bot is
+Some information about the bot
+The bot will reply to the ping with a pong.
+The bot will reply to the ping with a pong.
+The bot will remind you in a DM about the message given at the time given. You can chain multiple `(time).(unitoftime)` in one go e.g. @disbott remindme=2.hours.30.mins.15.s;Reminder Message will DM you in 2hours 30mins & 15secs about "Reminder Message".
+The bot will create a 6hour instant invite code & link for the given text channel of the server it is currently on.
+The bot will create a 6hour instant invite code & link for the given voice channel of the server it is currently on.
+The bot will start a 60second poll on the specified topic. After the 60seconds it will count the total number of votes made with the below commands and let the channel know.
+The bot will register a vote for the currently running poll with either a yes (y) or no (n).
+Will link your league username (summonername) with your discord user for ease of use. Only EUW at the moment!
+Provided you have linked your discord to a league account this command just tells chat what account you are linked to. If you add =@(discorduser) then it'll get their league user (provided they have linked too) and while a little silly it is possible to add =(summonername) which'll tell you the summoner name of the summoner you just searched...
+This command will post the specified users ranked status for this season. If you have linked your league account to disbott then you can just do `!lolrankedstats` and that will give you your ranked stats. Only EUW at the moment!
+This command will post the specified users current game with information on who they are playing, what game mode and for approximately how long. If you have linked your league account to disbott then you can omit the = part and it will give you your current game. Only EUW at the moment!
+Run this command to make disbott join your current voice channel. This must be run first before any of the other sound commands.
+This command stops any playing audio that the bot is playing, but keeps the bot in the voice channel.
+This command will instantly disconnect the bot from the voice channel and you'll need to rejoin with sound before playing audio again.
+Will take you to a website to see all the uploaded sounds to disbott. Also showcases commands for the below command.
+Plays whatever file specified to the voice channel, where file is the filename in the /modules/sound/sounds/.
+The bot gets the latest tweet from The Guardian's (@guardian) twitter feed.
+The bot gets the latest tweet from Furukawa Mirin's (@FurukawaMirin) twitter feed. She is my idol oshimen!
+WARNING MAYBE NSFW
+The bot gets a random tweet from @idol_gazo's twitter feed and tells name/group & image.
+