So I want to create a bot command that when i type
-say Something Here it returns someone says: Something here But all it does is returns someone says: undefined Btw i'm using tmi.js
bot.on("chat", function (channel, user, message, self) {
if(message === "-say")
var code = message.split(' ')[1];
bot.action("stankotomic", "someone says: " + code);
});
I am not really sure, but i think you meant something else. Tell me if i got you wrong. but as I've understood your question, that is the correct way to do it.
considering that message = "-say Something Here";
and your result should be: "Someone says: Something Here"
Lets look at your code line by line:
if(message === "-say") // I am 100% sure "-say" and
//"-say something here" are different. correct me if i am wrong.
//so we need to check for the first word, or first element in our array of words.
//lets first create array than check: if(message.split(" ")[0] == "-say")
var code = message.split(' ')[1]; //now, we don't have 2 spaces together
//anywhere in our message, so array == nothing.
//I guess it should be more like: message.split(" ").shift().join(" ");
// this will return you: "Something Here".
bot.action("stankotomic", "someone says: " + code);
Your final code:
bot.on("chat", function (channel, user, message, self) {
if(message.split(" ")[0] == "-say")
var code = message.split(" ").shift().join(" ");
bot.action("stankotomic", "someone says: " + code);
});
PS:
Split documentation.
Join documentation.
Shift documentation.
If you take the following line:
var code = message.split(' ')[1];
...and change it to the following, it should help:
var code = message.split(' ')[1];
You had two spaces as the separator argument to split() where you should have only had one.
See here for documentation for String.prototype.split()
Related
First things first, my help command does work but not in the way I would like it to work.
My first issue is that the commands are being sent in separate messages which is kind of annoying when you have a lot of commands.
My second issue is that when the message is sent in an embed, it shows up like this:
Command
Description
Usage
Undefined
I tried multiple ways to get rid of 'Undefined'.
My code:
const fs = require("fs");
const Discord = require("discord.js");
module.exports.run = async(bot, message, args, con) => {
fs.readdir("./commands/", (err, files) => {
if(err) console.error(err);
let jsfiles = files.filter(f => f.split(".").pop() === "js");
if(jsfiles.length <= 0) {
console.log("No commands to load!");
return;
}
var namelist = "";
var desclist = "";
var usage = "";
let result = jsfiles((f, i) => {
let props = require(`./${f}`);
namelist = props.help.name;
desclist = props.help.description;
usage = props.help.usage;
// send help text
let helpembed = new Discord.RichEmbed()
.setTitle("Commands")
.setFooter("Please report any bugs to Vati#1662")
.setColor("RANDOM")
.addField(`**${namelist}** \n${desclist} \n${usage}`)
message.author.sendEmbed(helpembed);
});
})
}
module.exports.help = {
name: "help",
description: "shows all commands",
usage: "help"
}
When you use RichEmbed.addField() it expects at least two arguments: the title of the field and its value.
.addField(`**${namelist}** \n${desclist} \n${usage}`) // this has only the title argument
Try putting the three "sections" in three different fields.
.addField("Name:", namelist, true) // the 'true' means that they're inline fileds
.addField("Usage:", usage, true) // they will try to fit on the same line
.addField("Description:", desclist) // if there's no third argument, the default is 'false'
The commands are sent in different messages because you're running the whole code for every command, and not only adding the fields for every command. If you don't want to spend time on all this stuff, you can use the discord.js-commando library: it's a framework that deals with the commands and also handles errors, incomplete commands, and a lot of other stuff. If you want to check it out, you can find the docs here.
Im am working on a twitch-bot using the tmi.js-npm and got a question about that.
I want to make a command like - "!giveaway" with an input, which could be anything. eg. "!giveaway pg". Then it should return "!pg". So the keyword "!giveaway" should be fixed, but the part after the blank, could be anything that is typed in.
My script looks like this:
client.on("chat", function (channel, user, message, self) {
if (message === "!Giveaway" + " " + "input"){
if(user["display-name"] === "username"){
client.say("channel", "!" + "input");
} else {
client.say("channel", "No permissions");
}
};
});
Thanks :)
Something like this is most commonly used, adding more checks is advised, but depends on your needs.
Checking the incoming message to see if it starts with a specific command, like so:
message.startsWith("!giveaway")
and with other logic
if (message.startsWith("!giveaway")) {
var input = message.split(' ')[1];
if (input.count < 2) return;
if (user["display-name"] === "username") {
client.say("channel", "!" + input);
} else {
client.say("channel", "No permissions");
}
}
I am pretty new to NodeJS , so sorry :( But you gotta start somewhere. Anyway, I was editing a code that I was trying to finish, and I came across a challenge when trying to make have one of my commands (this is a bot) work. Here's the bit of the code that isn't working :/
steamFriends.on('friendMsg', (id, msg) => {
if (msg == '') {}
else {
LOG(id + ' sent me ' + '"' + msg + '"')
}
if (config.get('admins').indexOf(id) == -1) return;
if (msg.indexOf('!price') == 0) {
var match = msg.match(/!price (director|audition) ([\.0-9]+)/);
if (!match) steamFriends.sendMessage(id, 'Usage: !price <director or audtion> <price> (e.g. !price director 3.77)');
else {
steamFriends.sendMessage(id, 'Successfully set price of '+match[1] + ' reels to '+match[2] + '!');
PRICES[match[1] == 'audition' ? 0 : 1] = parseFloat(match[2]);
changePrices();
}
}
else if(msg.indexOf('!changestate') == 0) {
var match = msg.match(/!changestate (Online|Offline|Away|Busy|LookingToTrade|LookingToPlay|Snooze)/);
LOG(match);
LOG(match[1]);
if (!match)
steamFriends.sendMessage(id, '!changestate <state> (Online, Offline, Away, LookingToTrade, Busy, LookingToPlay, Snooze)');
var state = match[1]
if (match)
steamFriends.setPersonaState(Steam.EPersonaState.state)
}
});
So the top part works, but the bottom part does not. Bottom part is the else if statement which should be triggered by the keyword !changestate The top part (the part that works) is the part that is triggered by !price.
EXAMPLE: When I try to do !changestate Away, which should be executed as steamFriends.setPersonaState(Steam.EpersonaState.Away) the code does not return an error, it logs "!changestate Away, Away" and on the next line, just "Away". I'm not sure if this is a logic error or something else in my code that is going wrong :/
I've had it log the match and match[1] for debugging, but nothing seems to help.
Thanks for the help guys, I really appreciate it.
At the end of your code you have
steamFriends.setPersonaState(Steam.EPersonaState.state)
Your 'state' variable isn't being used here. I suspect you would have more luck with something like
switch(state.toLowerCase()) {
case 'away':
steamFriends.setPersonaState(Steam.EPersonaState.Away);
break;
case 'online':
steamFriends.setPersonaState(Steam.EPersonaState.Online);
break;
// etc...
}
I have some node code and I'm trying to set this up but it seems like it's processing one item before another is complete and I'm wondering if I'm right and if so if there is some kind of work around
var input = function(text){
process.stdout.write(text);
process.stdin.setEncoding('utf-8')
process.stdin.once("data", function(input_data){
return input_data;
}).resume();
}
var test = function(var1, var2){
var var1 = (var1 == null) ? input("Var One: ") : var1;
var var2 = (var2 == null) ? input("Var Two: ").split(" ") : var1;
console.log(var1, var2);
}
Though, when I execute test(null,null) I expected it to ask me for Var one then define var1 as the data then after that I thought it would prompt me with Var Two and then split that by spaces into a list however that did not work and it just errored saying "Cannot call method of undefined "
I came from python where this was possible and it wouldn't do any other executions till the previously defined one was completed so I'm wondering if node has something similar to this and note I am not using a server or website for this I'm just testing code on my computer.
I'm fairly new to node myself, but here's my understanding of how it will execute:
test(null, null);
// enter test() function
// see that var1 == null, run input("Var One: ")
// write "Var One: " to stdout
// set stdin encoding to utf-8
// set an event listener for 'data' on stdin, and provide a callback for that event
... let's pause there for a moment, because this is the important bit.
When you set a listener and a callback, you've entered the land of asynchronicity. Your code will continue to march on without waiting and do the next things that you've told it to do. Which, in this case, is just sending back an undefined return from input(), and then moving on to handle var2 similarly, where you try to call undefined.split(), and the whole process pukes.
If, on the other hand, you just remove .split(), you'll probably get an output like this:
Var One: Var Two : [waiting for input]
At this point, when you enter the first value, it'll take it and return it from your callback to... nowhere... then it'll wait for your next value and do the same.
This is where you have to start to break your mind away form your python background and procedural, synchronous habits.
I'll risk beating a dead horse, and comment up your code directly:
var input = function(text){
process.stdout.write(text);
process.stdin.setEncoding('utf-8')
// .once() is an asynchronous call
process.stdin.once("data", function(input_data){
// the return value of this anonymous function isn't used anywhere
return input_data;
}).resume();
// there is no return value of the "input" function
}
Functionally, what you're looking for is something like the following (though this is ugly, something like async.waterfall makes this sort of structure much more palatable, and there may be even better ways to do it that I haven't learned yet):
function test(var1, var2) {
if (!var1 || !var2) {
process.stdin.resume();
process.stdin.setEncoding('utf-8');
if (!var1) {
process.stdout.write('Var One: ');
process.stdin.once('data', function(input_data) {
// var1 & var2 get pulled in from the parent context
var1 = input_data;
if (!var2) {
process.stdout.write('Var Two: ');
process.stdin.once('data', function(input_data) {
var2 = input_data;
console.log(var1, var2);
});
}
else {
console.log(var1, var2);
}
});
}
else if (!var2) {
process.stdout.write('Var Two: ');
process.stdin.once('data', function(input_data) {
var2 = input_data;
console.log(var1, var2);
});
}
else {
// there is no else, either var1 or var2 is missing
// per the first conditional
}
}
else {
console.log(var1, var2);
}
}
Here is how you can do it :
function input (text, val, cb) {
if (val) return cb(null, val)
process.stdout.write(text)
process.stdin.setEncoding('utf-8')
process.stdin.once('data', function(data){
process.stdin.pause()
cb(null, data)
}).resume()
}
function test (var1, var2) {
input('Var One: ', var1, function (err, var1) {
input('Var Two: ', var2, function (err, var2) {
console.log(var1)
console.log(var2)
})
})
}
test(null, null)
Basically, since stdin is async, so is input function. You need to use callback-based function style. This works, though you strongly recommend not using stdin this way. Try readline core module or some special userland modules from npm.
You can see that writing callback based code can be a little messy (aka callback hell). Here is a fancy way to address this issue using co module (you need node 0.11.x for this and use --harmony-generators flag):
var co = require('co')
function input (text) {
return function (cb) {
process.stdout.write(text)
process.stdin.setEncoding('utf-8')
process.stdin.once('data', function(data){
process.stdin.pause()
cb(null, data)
}).resume()
}
}
function * test (var1, var2) {
var1 = var1 || (yield input('Var One: '))
var2 = var2 || (yield input('Var Two: '))
console.log(var1)
console.log(var2)
}
co(test)(null, null)
I would use this built-in Node.js module: http://nodejs.org/api/readline.html
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("What do you think of node.js? ", function(answer) {
// TODO: Log the answer in a database
console.log("Thank you for your valuable feedback:", answer);
rl.question("What do you think of JavaScript?", function(answer2) {
console.log("Answer2 is ", answer2);
});
rl.close();
});
There is a relatively new language derived from CoffeeScript that makes async code more readable. It basically looks like sync code, and you don't have to nest indents for callbacks all the time. Its called ToffeeScript https://github.com/jiangmiao/toffee-script Coming from Python you may appreciate it.
readline = require 'readline'
rl = readline.createInterface { input: process.stdin, output: process.stdout }
answer = rl.question! "What do you think of node.js?"
console.log "Thank you for your valuable feedback:", answer
answer2 = rl.question! "What do you think of ToffeeScript?"
console.log "Thanks again."
rl.close()
Is there a way to remove the listeners on a passed in named callback function that are wrapped in an anonymous function?
UPDATE. More complete code examples below.
Here are the details.
I've a function that gets passed in a named callback.
Before
function read (message, named_callback ) {
var named_callback = named_callback || default_callback
, message = message || "Choose: ";
stdout.write(message);
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', named_callback);
});
};
All the named_callbacks take and prepare a passed in user input (answer).
answer = answer.trim().toLowerCase();
I end up repeating the trimming and lowercasing line everywhere! I wanted to move this step into one place, so tried to prepare the answer before it got passed into the callback.
I wrote this:
After
function read (message, named_callback ) {
var named_callback = named_callback || default_callback
, message = message || "Choose: ";
stdout.write(message);
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', function (answer) {
answer = answer.trim().toLowerCase();
named_callback(answer);
});
};
However, this results in event listeners not being removed, and they just pile up until the program crashes with too many listeners.
Thank you.
the problem is probably not where you think it is. with the info you give i would expect you just call the read method everytime, and thats where the tomanylisteners comes into place, because you just everytime append a new 'data' listener. if you change that 'on' to 'once' your application shouldnt crash anymore:
stdin.once('data'...
this of course isnt the solution to your problem, it is just to illustrate where your problem is (its not the trim/tolowercase.
if you show as a little bit more of your code maybe we are able to help you better, but probably your read-method is just unecessary overhead...