Skip to content

Commit

Permalink
Merge branch 'release/v0.1.0'
Browse files Browse the repository at this point in the history
* release/v0.1.0:
  Add initial logic and modules
  • Loading branch information
dsibilly committed Jun 13, 2017
2 parents 7d98dc5 + 8094d5e commit fe3df1f
Show file tree
Hide file tree
Showing 10 changed files with 450 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ Configuration.js
.DS_Store
lib
coverage
node_modules
16 changes: 16 additions & 0 deletions Configuration.js.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = {
api: {
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) Jinx/0.1.0'
},
commandPrefix: '!',
discord: {
token: ''
},
rethinkdb: {
db: '',
host: '',
password: '',
port: '',
user: ''
}
};
1 change: 1 addition & 0 deletions js/clone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default (originalObject, newProperties) => Object.assign({}, originalObject, newProperties);
6 changes: 6 additions & 0 deletions js/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import config from '../Configuration';
import thinky from 'thinky';

thinky.init(config.rethinkdb);

export default thinky;
67 changes: 67 additions & 0 deletions js/get-launches.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import launchLib, {
args
} from './launch-library-api';

import clone from './clone';
import countdown from 'countdown';
import Discord from 'discord.js';
import padStart from 'pad-start';
import presage from 'presage';

const timeToLaunch = date => {
const timespan = countdown(date);

return `L-${timespan.days === 1 ?
'1 day' :
`${timespan.days} days`}, ${padStart(timespan.hours, 2, 0)}:${padStart(timespan.minutes, 2, 0)}:${padStart(timespan.seconds, 2, 0)}`;
},
promisify = (client, method, parameters) => {
const {
callbackFunction,
promise
} = presage.promiseWithCallback();

client.methods[method](clone(args, {
parameters
}), response => {
callbackFunction(null, response);
});

return promise;
},
nextLaunches = (client, next) => promisify(client, 'launch', {
next
}),
nextLaunch = (client, launchId) => promisify(client, 'launch', {
id: launchId,
mode: 'verbose'
}),
getLaunches = numberOfLaunches => nextLaunches(launchLib, numberOfLaunches).then(response => presage.filter(response.launches, launch => Promise.resolve(!launch.tbddate && !launch.tbdtime))).then(launches => presage.map(launches, launch => nextLaunch(launchLib, launch.id))).then(launches => presage.map(launches, launchData => new Promise(resolve => {
const launchObject = launchData.launches[0];

resolve(launchObject);
// resolve(`Mission: ${mission}\nLaunch vehicle: ${rocket}\nLaunch Site: ${launchSite}\nLaunch window opens at ${launchTime} (${timeToLaunch(launchTime)})\nWatch online: ${videoUrl}\n`);
})));

export default (bot, message) => new Promise((resolve, reject) => {
getLaunches(1).then(launches => {
const nextLaunch = launches[0],
windowOpens = new Date(nextLaunch.windowstart);

message.channel.send({
embed: new Discord.RichEmbed()
.setTitle('Next Rocket Launch')
// .setAuthor(bot.user.username, bot.user.avatarURL)
.setColor(0x00AE86).setThumbnail(nextLaunch.rocket.imageURL)
.setURL(nextLaunch.vidURLs[0])
.addField('Date', `${windowOpens} (${timeToLaunch(windowOpens)})`)
.addField('Mission', nextLaunch.missions[0].name)
.addField('Launch Vehicle', nextLaunch.rocket.name)
.addField('Launch Site', nextLaunch.location.pads[0].name)
}).then(() => {
resolve();
}).catch(error => {
reject(error);
});
});
});
161 changes: 161 additions & 0 deletions js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import Bunyan from 'bunyan';
import config from '../Configuration';
import Discord from 'discord.js';
import getLaunches from './get-launches';
import wikipedia from './wikipedia';

const _log = Bunyan.createLogger({
name: 'jinx'
}),
aliases = {
nl: 'nextLaunch'
},
bot = new Discord.Client(),
commands = {
avatar: {
description: 'displays the URL of your full-size Discord avatar',
process: (bot, message) => {
_log.info({
user: message.author.tag
}, 'Retrieving user avatar');
return message.channel.send(message.author.avatarURL);
}
},
nextLaunch: {
description: 'lists the next upcoming rocket launches',
process: (bot, message) => {
_log.info('Retriving next rocket launch information');
return getLaunches(bot, message);
}
},
ping: {
description: 'responds pong, useful for checking if bot is alive',
process: (bot, message, suffix) => {
_log.info({
user: message.author.tag
}, 'Sending ping response');
return message.channel.send(`${message.author.tag} pong!`).then(() => new Promise((resolve, reject) => {
if (suffix) {
message.channel.send(`${config.commandPrefix}ping takes no arguments...`).then(resolve).catch(reject);
return;
}

resolve();
}));
}
},
wiki: {
description: 'looks up the query string on Wikipedia',
process: (bot, message, suffix) => {
_log.info({
query: suffix
}, 'Starting Wikipedia search');
return wikipedia(bot, message, suffix);
}
}
},
token = config.discord.token;

bot.on('ready', () => {
_log.info('Jinx Discord bot online!');
});

bot.on('guildMemberAdd', member => {
member.guild.defaultChannel.send(`Welcome to the server, ${member}!`);
});

bot.on('message', message => {
if (message.author.id !== bot.user.id && message.content.startsWith(config.commandPrefix)) {
_log.info({
author: message.author.tag,
content: message.content
}, 'Processing command');

let command,
commandText = message.content.split(' ')[0].substring(config.commandPrefix.length),
suffix = message.content.substring(commandText.length + config.commandPrefix.length + 1);

if (message.isMentioned(bot.user)) {
try {
commandText = message.content.split(' ')[1];
suffix = message.content.substring(bot.user.mention().length + commandText.length + config.commandPrefix.length + 1);
} catch (exception) {
message.channel.send(`How can I help you, ${message.author.tag}?`);
return;
}
}

const alias = aliases[commandText];

if (alias) {
_log.info({
alias: commandText,
command: alias,
query: suffix
}, 'Dealiasing command');
commandText = alias;
suffix = `${suffix}`;
}

command = commands[commandText];

if (commandText === 'help') {
if (suffix) {
message.channel.send(suffix.split(' ').filter(cmd => commands[cmd]).reduce((info, helpCommand) => {
let description = commands[helpCommand].description;
const usage = commands[helpCommand].usage;

info += `**${config.commandPrefix}${helpCommand}**`;

if (usage) {
info += ` ${usage}`;
}

if (description instanceof Function) {
description = description();
}

if (description) {
info += `\n\t ${description}`;
}

info += '\n';
return info;
}, ''));
} else {
message.author.send(Object.keys(commands).sort().reduce((info, helpCommand) => {
let description = commands[helpCommand].description;
const usage = commands[helpCommand].usage;

info += `**${config.commandPrefix}${helpCommand}**`;

if (usage) {
info += ` ${usage}`;
}

if (description instanceof Function) {
description = description();
}

if (description) {
info += `\n\t ${description}`;
}

info += '\n';
return info;
}, '**Available Commands:**\n\n'));
}
} else if (command) {
command.process(bot, message, suffix).then(() => {
_log.info({
author: message.author.tag,
command: commandText
}, 'Command processed');
}).catch(error => {
message.channel.send(`**Jinx Command Error**: ${commandText} failed!\nStack:\n${error.stack}`);
});
}
}
});

bot.login(token);
35 changes: 35 additions & 0 deletions js/launch-library-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
Client
} from 'node-rest-client';

import config from '../Configuration';

const args = {
headers: {
Accept: 'application/json',
'User-Agent': config.api.userAgent
}
},
client = new Client();

client.registerMethod('agency', 'https://launchlibrary.net/1.2/agency', 'GET');
client.registerMethod('agencyType', 'https://launchlibrary.net/1.2/agencytype', 'GET');
client.registerMethod('eventType', 'https://launchlibrary.net/1.2/eventtype', 'GET');
client.registerMethod('launch', 'https://launchlibrary.net/1.2/launch', 'GET');
client.registerMethod('launchEvent', 'https://launchlibrary.net/1.2/launchevent', 'GET');
client.registerMethod('launchStatus', 'https://launchlibrary.net/1.2/launchstatus', 'GET');
client.registerMethod('location', 'https://launchlibrary.net/1.2/location', 'GET');
client.registerMethod('mission', 'https://launchlibrary.net/1.2/mission', 'GET');
client.registerMethod('missionEvent', 'https://launchlibrary.net/1.2/missionevent', 'GET');
client.registerMethod('missionType', 'https://launchlibrary.net/1.2/missiontype', 'GET');
client.registerMethod('nextLaunch', 'http://launchlibrary.net/1.2/launch/next/1', 'GET');
client.registerMethod('pad', 'https://launchlibrary.net/1.2/pad', 'GET');
client.registerMethod('rocket', 'https://launchlibrary.net/1.2/rocket', 'GET');
client.registerMethod('rocketEvent', 'https://launchlibrary.net/1.2/rocketevent', 'GET');
client.registerMethod('rocketFamily', 'https://launchlibrary.net/1.2/rocketfamily', 'GET');

export default client;

export {
args
};
37 changes: 37 additions & 0 deletions js/wikipedia.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Discord from 'discord.js';
import wiki from 'wikijs';

const wikipedia = (bot, message, query) => {
if (!query) {
message.channel.send('usage: !wiki query');
return Promise.resolve();
}

return wiki().search(query, 1).then(data => wiki().page(data.results[0]).then(page => {
page.summary().then(summary => Promise.resolve(summary.toString().split('\n').reduce((text, paragraph) => {
if (text !== '' || !paragraph) {
return text;
}

if (paragraph) {
return paragraph;
}

return text;
}, ''))).then(summaryText => {
const pageTitle = page.raw.title,
canonicalUrl = page.raw.canonicalurl;

return message.channel.send({
embed: new Discord.RichEmbed()
.setTitle(pageTitle)
.setURL(canonicalUrl)
.setDescription(summaryText)
.setThumbnail('https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Wikipedia-logo-v2-wordmark.svg/200px-Wikipedia-logo-v2-wordmark.svg.png')
.setFooter('Data provided by Wikipedia: The Free Encyclopedia')
});
});
}));
};

export default wikipedia;
Loading

0 comments on commit fe3df1f

Please # to comment.