Tipbot is here!
Please review!
This commit is contained in:
parent
6d68fc6657
commit
f018335f7b
9 changed files with 2276 additions and 1 deletions
3
.babelrc
Normal file
3
.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"presets": ["node8"]
|
||||||
|
}
|
63
.gitignore
vendored
Normal file
63
.gitignore
vendored
Normal 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
|
26
README.md
26
README.md
|
@ -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
121
bot/bot.js
Normal 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
189
bot/modules/tipbot.js
Normal 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
47
bot/plugins.js
Normal 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.`);
|
||||||
|
}
|
20
config/default.json.example
Normal file
20
config/default.json.example
Normal 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
32
package.json
Normal 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"
|
||||||
|
}
|
Loading…
Reference in a new issue