Avoiding multiple MessageCollectors - node.js

I'm making a discord bot with some messageCollector. This messageCollector is created when the bot detects the !Hello command, but if you write again !Hello, another messageCollector is created.
I checked in the discord.js documentation if it's possible to verify if a collector is already open, but I didn't find it.
I thought to make:
if (message === "!Hello") collector.stop("Stopped");
But I don't know if it's the right solution.
Thanks for your help.

You could make a variable that contains a boolean and just make it set to true when someone does !Hello.
let toggled = false;
if (message === "!Hello" && toggled = true) {
return;
} else if (message === "!Hello" && toggled = false) {
toggled = true;
//run the !Hello code here
}
Hope this works, not sure if it's the answer you wanted but this will stop it from creating more messageCollector's.

Related

Discord.js Problems With Default Command in Switch

So I'm trying to make a discord bot, and I am trying to set up a way to get the bot to ask to use the help command when an input isn't defined, but when I set the default in the switch statement, it just repeats itself over and over, #ing itself with the text inputted.
switch(args[0]){
case 'ping':
message.channel.send('pong!');
break;
case 'rockLink':
message.channel.send('') //text here, deleted to protect link
break;
case 'info':
if(args[1] === 'description'){
message.channel.send('I am eventually going to play rock music, for now I do random stuff.')
}else if(args[1] === 'author'){
message.channel.send('I was made by IAmAGreenFlamingo')
}else if(args[1] === 'version'){
message.channel.send('This bot is in version ' + version)
}else{
message.channel.send('Invalid Argument, please use !help info to see all valid arguments!')
}
break;
case 'help':
if(args[1] === 'info'){
message.reply('Arguments for !info: description, author.')
}else{
message.reply('The commands so far are: !ping, !rockLink, and !info (use !help info for arguments)!')
}
break;
default:
message.reply('Invalid Argument, please use !help to see all commands!')
break;
}
It is good practice to ignore bots and DMs for commands. Add something like this at the top of your .on('message') statement:
if(message.author.bot || !message.guild) return //ignores bot messages and pms
This should also stop it from answering to itself.
Another option is to replace the message.replys with message.sends so it doesn't tag itself or anyone else.

Detect end of a track's playback with Spotify Web API / Playback SDK

Working with Spotify Web API and Web Playback SDK, does anybody know a good way to detect when a track's playback has finished, i.e. the song is over?
I know about some event named player_state_changed in Web Playback SDK, but the data provided in the event doesn't seem to be very helpful to me.
In my web app, the next song to be played is determined pretty spontaneously. It would be nice, if I could determine it only, when the current track has reached its end. Hence, there is no playlist. Instead, the app plays single tracks in series and should determine the next song, when the current one has ended.
Meanwhile I try it with this code here:
var bCallingNextSong = false;
player.addListener('player_state_changed', state => {
if (state != null &&
state.position == 0 &&
state.duration == 0 &&
state.paused == true) {
if (!bCallingNextSong) {
playNextSong();
}
}
});
function playNextSong() {
$.ajax({
url:"playback.php", //the page containing php script
type: "post", //request type,
dataType: 'json',
data: {action: "next", device: deviceId},
success: function(result) {
bCallingNextSong = false;
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
bCallingNextSong = false;
}
});
}
and in playback.php:
switch ($action) {
case "next":
//some blackbox magic here to determine next song, do logging etc.
//but for now just play the same song over and over
$api->play($deviceId, ['uris' => "spotify:track:0eGsygTp906u18L0Oimnem"],]);
echo json_encode(array("answer"=>"played next"));
break;
// more code
}
However, this will often (but not always) throw an InvalidStateError (I haven't found out where exactly yet nor why). Stack says dequeueUpdates / tryUpdate / _processUpdate / _appendUpdate. Yet, I'm a beginner and I've gotta learn how to cope with Firefox Debugger first.. :)
My last answer got broken so I will now add new solution which work for now.
this.player.addListener('player_state_changed', (state) => {
console.log(state);
if (
this.state
&& state.track_window.previous_tracks.find(x => x.id === state.track_window.current_track.id)
&& !this.state.paused
&& state.paused
) {
console.log('Track ended');
this.setTrackEnd(true);
}
this.state = state;
});
So what is different from last solution? I check that current_track is in previous track list. But there was problem now with position check because it seems that current track appears to previous track list before track is completely end. But that wasn't problem in my app because there is always small delays with commands.
EDIT: This is not working anymore for some reason. Check my other answer which will work now. https://stackoverflow.com/a/51114848/8081009
Here is my solution. It works most of the time. Actually I didn't get it broken in any scenarios I can imagine. So hold last state and check that is it gone to paused state. Hopefully Spotify will ease our work with track ended event. It would be great if they does. This is still better than polling their /me/player/currently-playing endpoint for every 1 second or so.
this.player.addListener(
'player_state_changed',
state =>
{
console.log(state);
if(this.state && !this.state.paused && state.paused && state.position === 0) {
console.log('Track ended');
this.setTrackEnd(true);
}
this.state = state;
}
);
I had this same problem, this is how I solved it.
When a song finish playing it gets added to the state.track_window.previous_tracks list
state.track_window.previous_tracks gets populated only if there is a next track and it starts playing
But every time you call the api to play a new track, it clears the state.track_window.previous_tracks & state.track_window.next_tracks list.
If there is a next track, I want to stop and choose my own next track and then call the api
var alreadyPlayed = state.track_window.previous_tracks
if(alreadyPlayed.length > 0) {
player.pause()
}
if there is no next track the player will be paused when the song finish
if(state.paused && state.position === 0) {
//song ended
ChooseNextSong()
}
the state callback gets fired many times but I want to call ChooseNextSong()
only once, so I increment startCheck every time it fires
if(state.paused && state.position === 0) {
//song ended
startCheck++
if(startCheck === 1) {
ChooseNextSong()
}
}
check if song started
if(state.position === 0 && alreadyPlayed.length === 0 && !state.paused)
{
//song started
startCheck = 0
}
You should use the player_state_changed event and look at which track is playing to see if the track has changed. You can find the current track in playerStateObject.track_window.current_track.
A possible implementation could look like this:
let currentTrack = '';
player.on('player_state_changed', state => {
if( state.track_window.current_track.id != currentTrack ) {
// The track changed!
currentTrack = state.track_window.current_track.id;
}
});

Node.js - How to parse arguments passed via an IRC chat message

EDIT: I am using the twitch-irc library from Github for Node.js, installed via npm.
This is such a basic question and I feel like a bit of an idiot for asking, but...
if (message.toLowerCase().indexOf('!os') === 0) {
}
Let's say I used this code, how would I add if statements for the arguments that the user provides? By this, I mean after typing !os, they would create a space and type something else, this would either be the 0th or 1st argument.
Would it be possible to just use this?:
if (message.toLowerCase().indexOf('kernel') === 4) {
}
In pseudo code, I want to do:
if (firstargument === 'kernel') {
//Do stuff.
}
Thank you for your time.
You could simply use var args = message.match(/\S+/g) to get all the arguements (including '!os') in an array and use them as you wish.
e.g.
var args = message.match(/\S+g/);
var cmd = args[1]; //do a length check before accessing args[1] though
switch (cmd) {
case 'kernel':
// do stuff
break;
case 'process':
// do stuff
break;
default:
// invalid command
}
What you said would make sense to do, but you should remove white space (spaces) so that a command like !os kernel will still work (note the two spaces).
Do that like this:
if (message.replace(/\s\g, '').toLowerCase().indexOf('kernel') === 3) {
//Do stuff
}

Spotify - libspotify error codes

I'm trying to create a command based spotify client running on ubuntu/debian. But, I keep on getting in to a problem when trying to login.
The code:
int main() {
sp_session *sp;
sp_error err;
sp_session_callbacks callbacks;
sp_session_config config;
config.api_version = 10;
config.cache_location = "tmp";
config.settings_location = "tmp";
config.application_key = g_appkey;
config.application_key_size = g_appkey_size;
config.user_agent = "name";
config.callbacks = NULL;
err = sp_session_create(&config, &sp);
if (SP_ERROR_OK != err) {
fprintf(stderr, "Unable to create session: %s\n",
sp_error_message(err));
exit(1);
}
return 0;
}
And i get this:
"Unable to create session: Unable to open trace file"
Its error code 26.
Do anyone know what this error message means? Having a hard time finding a good answer for this.
Thx
Credentials are not put in before the call to sp_session_login() and the callback returned when that completes will tell you if the user entered bad credentials through an error code.
Also, in general libspotify will like it better if you provide zero for all unused fields in structs, like so:
memset(&config, 0, sizeof(sp_session_config));
// here goes setup of config struct
That said, sp_session_create() should never block and is not asynchronous.
The file paths (cache and settings) need to be absolute paths to a writable place on disk. Try replacing "tmp" with something like "/tmp/libSpotify" - make sure /tmp/libSpotify or whatever actually exists first.
try adding config.tracefile = NULL;

chrome.tabs.executeScript only working with an alert before it

I believe this is related to the asynchronous nature of chrome extensions.
This section of my code:
alert(tab.title);
chrome.tabs.executeScript(tab.id, {code:"document.title = 'test'"});
Works fine, but as soon as I remove the alert, it stops working. Is there anything I can do to remove the alert but still have the js injected?
EDIT: More Code
tabs is a global array of tab objects.
chrome.tabs.onSelectionChanged.addListener(function (tabId) {
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == tabId) {
var tab = tabs[i];
while (i < tabs.length) {//length-1
tabs[i] = tabs[i+1];
i++;
}
tabs.pop();
alert(tab.title);//WHY IS THIS NEEDED
chrome.tabs.executeScript(tab.id, {code:"document.title = document.title.substring(1)"});
return;
}
}
});
I am very confused. Changing it the following solves the problem:
chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});
However, as soon as I change the delay to 50, the script doesn't get executed again. I would prefer not to have to have to make this delay. Does anyone know whats going on?
I know this is an old question, but if anyone is looking - wrap the chrome.tabs.executeScript method in a timeout.
setTimeout(function(){chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});},500);
It's certainly not ideal but it gets the job done.
Sounds like you have a race condition. My best guess would be to change the injected code to execute on onLoad.

Resources