Tipbot is here!

Please review!
This commit is contained in:
Fillerino 2017-10-25 21:12:38 +02:00
parent 6d68fc6657
commit f018335f7b
9 changed files with 2276 additions and 1 deletions

3
.babelrc Normal file
View file

@ -0,0 +1,3 @@
{
"presets": ["node8"]
}

63
.gitignore vendored Normal file
View file

@ -0,0 +1,63 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# dist
dist/*
#configuration
config/default.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env

View file

@ -1 +1,25 @@
Will be updated with the new wunderbot when changes have been reviewed.
# Bot for [LBRY's Discord](https://discord.gg/tgnNHf5)
(This README will be updated along with bot updates)
Features:
- Tipbot for LBC. Responds to `!tip`.
- Dynamic plugin loading with permission support.
## Requirements
- node > 8.0.0
- npm > 0.12.x
## Installation
Create a bot and get the bot's API Token: https://discordapp.com/developers/applications/me
Edit and rename default.json.example in /config, then run:
```
npm install
node bot.js
```

121
bot/bot.js Normal file
View file

@ -0,0 +1,121 @@
'use strict';
// Load up libraries
const Discord = require("discord.js");
// Load config!
let config = require('config');
config = config.get('bot');
var aliases;
try {
aliases = require("./alias.json");
} catch (e) {
//No aliases defined
aliases = {
"test": {
process: function(bot,msg){
msg.channel.send('test');
}
}
}
}
var commands = {
};
var bot = new Discord.Client();
bot.on("ready", function() {
console.log(
"Logged in! Serving in " + bot.guilds.array().length + " servers"
);
require("./plugins.js").init();
console.log("type " + config.prefix + "help in Discord for a commands list.");
bot.user.setGame(
config.prefix + "help | Tipping not available"
);
});
bot.on("disconnected", function() {
console.log("Disconnected!");
process.exit(1); //exit node.js with an error
});
function checkMessageForCommand(msg, isEdit) {
//check if message is a command
if (msg.author.id != bot.user.id && msg.content.startsWith(config.prefix)) {
console.log(
"treating " + msg.content + " from " + msg.author + " as command"
);
var cmdTxt = msg.content.split(" ")[0].substring(config.prefix.length);
var suffix = msg.content.substring(
cmdTxt.length + config.prefix.length + 1
); //add one for the ! and one for the space
if (msg.isMentioned(bot.user)) {
try {
cmdTxt = msg.content.split(" ")[1];
suffix = msg.content.substring(
bot.user.mention().length + cmdTxt.length + config.prefix.length + 1
);
} catch (e) {
//no command
msg.channel.send("Yes?");
return;
}
}
let alias = aliases[cmdTxt];
if (alias) {
var cmd = alias;
} else {
var cmd = commands[cmdTxt];
}
if (cmd) {
// Add permission check here later on ;)
try {
cmd.process(bot, msg, suffix, isEdit);
} catch (e) {
var msgTxt = "command " + cmdTxt + " failed :(";
if (config.debug) {
msgTxt += "\n" + e.stack;
}
msg.channel.send(msgTxt);
}
}
} else {
//message isn't a command or is from us
//drop our own messages to prevent feedback loops
if (msg.author == bot.user) {
return;
}
if (msg.author != bot.user && msg.isMentioned(bot.user)) {
msg.channel.send("yes?"); //using a mention here can lead to looping
} else {
}
}
}
bot.on("message", msg => checkMessageForCommand(msg, false));
bot.on("messageUpdate", (oldMessage, newMessage) => {
checkMessageForCommand(newMessage, true);
});
exports.addCommand = function(commandName, commandObject) {
try {
commands[commandName] = commandObject;
} catch (err) {
console.log(err);
}
};
exports.addCustomFunc = function(customFunc) {
try {
customFunc(bot);
} catch (err) {
console.log(err);
}
}
exports.commandCount = function() {
return Object.keys(commands).length;
};
bot.login(config.token);

189
bot/modules/tipbot.js Normal file
View file

@ -0,0 +1,189 @@
'use strict';
const bitcoin = require('bitcoin');
let config = require('config');
config = config.get('lbrycrd');
const lbry = new bitcoin.Client(config);
exports.commands = [
"tip"
]
exports.tip = {
usage: "<subcommand>",
description: 'balance: get your balance\n deposit: get adress for your deposits\n withdraw ADDRESS AMOUNT: withdraw AMOUNT credits to ADDRESS\n <user> <amount>: mention a user with @ and then the amount to tip them',
process: async function(bot,msg,suffix){
let tipper = msg.author.id,
words = msg.content.trim().split(' ').filter( function(n){return n !== "";} ),
subcommand = words.length >= 2 ? words[1] : 'help';
if (subcommand === 'help') {
doHelp(msg);
}
else if (subcommand === 'balance') {
doBalance(msg, tipper);
}
else if (subcommand === 'deposit') {
doDeposit(msg, tipper);
}
else if (subcommand === 'withdraw') {
doWithdraw(msg, tipper, words);
}
else {
doTip(msg, tipper, words);
}
}
}
function doBalance(message, tipper) {
lbry.getBalance(tipper, 1, function(err, balance) {
if (err) {
message.reply('Error getting balance');
}
else {
message.reply('You have *' + balance + '* LBC');
}
});
}
function doDeposit(message, tipper) {
if(!inPrivateOrBotSandbox(message)){
message.reply('Please use <#369896313082478594> or DMs to talk to bots.');
return;
}
getAddress(tipper, function(err, address) {
if (err) {
message.reply('Error getting deposit address');
}
else {
message.reply('Your address is ' + address);
}
});
}
function doWithdraw(message, tipper, words) {
if(!inPrivateOrBotSandbox(message)){
message.reply('Please use <#369896313082478594> or DMs to talk to bots.');
return;
}
if (words.length < 4) {
doHelp(message);
return;
}
var address = words[2],
amount = getValidatedAmount(words[3]);
if (amount === null) {
message.reply('I dont know how to withdraw that many credits');
return;
}
lbry.sendFrom(tipper, address, amount, function(err, txId) {
if (err) {
message.reply(err.message);
}
else {
message.reply('You withdrew ' + amount + ' to ' + address + ' (' + txLink(txId) + ')');
}
});
}
function doTip(message, tipper, words) {
if (words.length < 3 || !words) {
doHelp(message);
return;
}
let amount = getValidatedAmount(words[2]);
if (amount === null) {
message.reply('I dont know how to tip that many credits');
return;
}
if (words[1].match(/^<@[^>]+>$/)) {
let id = words[1].substr(2,words[1].length-3);
sendLbc(message, tipper, id, amount);
}
else
{
message.reply('Sorry, I could not find a user in your tip...');
}
}
async function doHelp(message) {
if(!inPrivateOrBotSandbox(message)){
message.reply('Please use <#369896313082478594> or DMs to talk to bots.');
return;
}
message.author.send('**!tip**\n balance: get your balance\n deposit: get adress for your deposits\n withdraw ADDRESS AMOUNT: withdraw AMOUNT credits to ADDRESS\n <user> <amount>: send <amount> credits to <user>');
}
function sendLbc(message, tipper, id, amount) {
getAddress(id, function(err, address){
if (err) {
message.reply(err.message);
}
else {
lbry.sendFrom(tipper, address, amount, 1, null, null, function(err, txId){
if (err) {
message.reply(err.message);
}
else {
var imessage =
'Wubba lubba dub dub! <@' + tipper + '> tipped <@' + id + '> ' + amount + ' LBC (' + txLink(txId) + '). ' +
'DM me `!help` for tipbot instructions.'
message.reply(imessage);
}
});
}
});
};
function getAddress(userId, cb) {
lbry.getAddressesByAccount(userId, function(err, addresses) {
if (err) {
cb(err);
}
else if(addresses.length > 0) {
cb(null, addresses[0]);
}
else {
lbry.getNewAddress(userId, function(err, address) {
if (err) {
cb(err);
}
else {
cb(null, address);
}
});
}
});
}
function inPrivateOrBotSandbox(msg){
if((msg.channel.type == 'dm') || (msg.channel.id === '369896313082478594')){
return true;
}else{
return false;
}
}
function getValidatedAmount(amount) {
amount = amount.trim();
if (amount.toLowerCase().endsWith('lbc')) {
amount = amount.substring(0, amount.length-3);
}
return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null;
}
function txLink(txId) {
return "<https://explorer.lbry.io/tx/" + txId + ">";
}

47
bot/plugins.js Normal file
View file

@ -0,0 +1,47 @@
'use strict';
const fs = require("fs"),
path = require("path");
function getPlugins(srcpath) {
return fs.readdirSync(srcpath);
}
let plugin_directory = path.join(__dirname, "modules");
let plugins = getPlugins(plugin_directory);
exports.init = function init() {
load_plugins();
};
function load_plugins() {
const dbot = require("./bot.js");
let commandCount = 0;
let otherFunc = 0;
for (let i = 0; i < plugins.length; i++) {
let plugin;
try {
plugin = require(`${plugin_directory}/${plugins[i]}`);
} catch (err) {
console.log(`Improper setup of the '${plugins[i]}' plugin. : ${err}`);
}
if (plugin) {
if ("commands" in plugin) {
for (let j = 0; j < plugin.commands.length; j++) {
if (plugin.commands[j] in plugin) {
dbot.addCommand(plugin.commands[j], plugin[plugin.commands[j]]);
commandCount++;
}
}
}
if("custom" in plugin){
for (let j = 0; j < plugin.custom.length; j++) {
if (plugin.custom[j] in plugin) {
dbot.addCustomFunc(plugin[plugin.custom[j]]);
otherFunc++;
}
}
}
}
}
console.log(`Loaded ${dbot.commandCount()} chat commands and ${otherFunc} custom functions.`);
}

View file

@ -0,0 +1,20 @@
{
// Bot configuration
"bot": {
"token":"discordbottoken",
"prefix": "!",
"debug": false
},
"lbrycrd": {
"port": 9245,
"user": "lbry",
"pass": "lbry"
},
"mongodb": {
"url":"mongodb://localhost:27017/wunderbot"
},
"moderation":{
"perms": ["LBRY MODS","LBRY TEAM"], // Roles that have access to all commands.
"logchannel": "371620338263523328" // Channel to log the bots moderation..
}
}

32
package.json Normal file
View file

@ -0,0 +1,32 @@
{
"dependencies": {
"babel-cli": "^6.26.0",
"babel-preset-node8": "^1.2.0",
"bitcoin": "^3.0.1",
"chrono-node": "^1.3.5",
"config": "^1.27.0",
"discord.js": "^11.2.1",
"embed-creator": "^1.1.4",
"jsonpath": "^0.2.12",
"moment": "^2.19.1",
"mongoose": "^4.12.3",
"node-config": "^0.0.2",
"numeral": "^2.0.6",
"request": "^2.83.0"
},
"scripts": {
"prettier": "prettier * --write",
"build": "babel bot -d dist",
"prod": "babel bot -d dist & node dist/bot.js"
},
"devDependencies": {
"prettier": "1.7.4"
},
"name": "wunderbot-discord",
"version": "0.0.1",
"description": "LBRYs bot for Discord",
"main": "app.js",
"repository": "https://github.com/filipnyquist/wunderbot-disc",
"author": "filipnyquist <filip@lbry.io>",
"license": "MIT"
}

1776
yarn.lock Normal file

File diff suppressed because it is too large Load diff