Manageable timers in node - javascript

I'm looking for a way to create named timers in node that can be started, stopped/paused and have their intervals or functionality changed.
I am making an IRC bot that I want to have say certain general messages on a timer.
I have this messages.js setup with a handful of objects like so
module.exports = [
{
title: "donate",
message: "If you would like to help the stream out, donate at https://www.twitchalerts.com/donate/matax91 . All donations go toward the stream!",
interval: 1,
active: true
},
...
]
And in my app.js I have this setup
var Messages = require('./messages');
var activeMessages = [];
client.addListener('join', function(){
for(var id in Messages){
if(Messages[id].active){
console.log('set interval');
activeMessages[Messages[id].title] = setInterval(function(){
console.log('sent message');
client.say(config.channels[0], Messages[id].message);
},(Messages[id].interval * 60000));
}
}
});
The problem I see is that it's going to be really hard to pause these messages, or make changes to their intervals if I want to. I feel like there is a module that may be able to help me do this, but my searches aren't turning up much. Any advice would be great!

Related

How to play the sounds one by one the other within a specified BPM?

I am trying to build a small sequencer with my kids and struggle to find a solution on this.
I am using this library: https://github.com/alemangui/pizzicato
Our goal is to create little samples of their voice and have them playing one after the other(but not at the same time).
I wrote this code hoping to solve the problem but upon playing on "Play", all the samples play at the same time rather than 1 after the other...
var sound = [];
this.samples.forEach((item, i) => {
sound[i] = new Pizzicato.Sound(
{
source: "file",
options: { path: item.sampleUrl },
},
() => {
sound[i].play();
}
);
});
this.samples is just an array with the files(wav) URLs.
Our ultimate goal is to be able to play the files with a set BPM, ie: 120BPM(Beat per minute).
I really thought it would have been a lot easier :-)
If you have a clever idea to solve this, you are welcome to demonstrate it.
Thank you!
The callback you pass while initializing the Pizzicato.Sound class is run immediately when the sound is ready to play.
So it's best to get all the sounds, pick one sound, play it and listen for it's end event and call the next sound.
const sounds = this.samples.map(item => new Pizzicato.Sound({
source: 'file',
options: { path: item.sampleUrl }
}));
playSound(0);
function playSound(i) {
sounds[i].play();
if (i < sounds.length) sound.on('end', _ => playSound(++i));
}

How to program a decision tree with Alexa?

I am currently trying to program an alexa skill. I am very stuck... trying to see if I can get Alexa to ask the user 'How they are feeling' and then use this to ask further questions. Not sure if I should make a variable or attribute... any help please.
For example, once the user says "SAD" for the emotion - I want to be able to ask further questions, like "Is it from your past or present?"
(AWS code)
const GREETING = [
'What emotion are you feeling today?',
'Hello, what emotion are you feeling right now?'
];
const SKILL_NAME = 'March Test';
const GET_FEEL = "That is unfortunate to hear?";
const HELP_MESSAGE = 'I can give you more information if you tell me
how you are feeling';
const HELP_REPROMPT = 'How are you feeling currently?';
const STOP_MESSAGE = 'Goodbye!';
const FeelingsList = [
{
Emotion: "SAD",
suggestion: "My suggestion for sad is dry your tears and find a
distraction"
},
{
Emotion: "HAPPY",
suggestion: "My suggestion for happy is keep smiling and keep shining"
},
{
Emotion: "ANGRY",
suggestion: "My suggestion for angry is count to ten and cool down"
}
];
const handlers = {
'LaunchRequest': function () {
const greetingArr = GREETING;
const greetingIndex = Math.floor(Math.random() *
greetingArr.length);
this.emit(':ask',greetingArr[greetingIndex]); //first action that
will be fired
},
'EmotionalState': function () {
var stateSlot = this.event.request.intent.slots.Emotion.value;
this.emit(':ask', EmotionalResponse(FeelingsList, 'Emotion',
stateSlot.toUpperCase()).suggestion);
},
'AMAZON.HelpIntent': function () {
const speechOutput = HELP_MESSAGE;
const reprompt = HELP_REPROMPT;
this.response.speak(speechOutput).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.CancelIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
Okay, thanks for answering my questions in comments, the EmotionalResponse function looks good. The way you have it set up currently should work well for a single response. If that is all you want Alexa to do here then just change ':ask' to ':tell' (which will respond and not expect the user to reply) so the line would become:
this.emit(':tell', EmotionalResponse(FeelingsList, 'Emotion', stateSlot.toUpperCase()).suggestion );
However, you want to be able to continue the conversation with multiple questions and response handlings. You might already have this but it's not in your code above, and you need it to use the Alexa SDK, so make sure you have this line at the very beginning:
const Alexa = require('alexa-sdk');
You also need this, preferably at the end:
exports.handler = function(event, context, callback) {
const alexa = Alexa.handler(event, context, callback);
alexa.registerHandlers(handlers);
alexa.execute();
};
Next, some things to know about continuing a conversation using Alexa SDK:
':ask'
will respond with the speechOutput sentence and expect a reply from the user, but if the user does not reply, then Alexa will "reprompt" the user with the repromptSpeech sentence.
':delegate'
will tell Alexa to determine which required slot to ask the user for, and use the prompt (set up in the Alexa developer console) to elicit the slot information from the user.
':elicitSlot'
will give Alexa the specific instructions of which slot to elicit and the exact prompt to use.
There are many ways to continue an Alexa conversation and build your logic of handling the user's input and build an appropriate response. But to use your example of requesting more information from the user such as "Is it from your past or present?", here is one way I would suggest:
First, create another slot for this intent (anytime you want to hold user input information you'll need another slot). Let's call it Timeframe.
The simplest way is to "delegate" to Alexa to elicit this slot, so in the console make the slot required and add a prompt message such as, "Are you feeling this way because of something in your past or present?" You can even get fancy and use the emotion slot in that message like this: "Are you feeling {Emotion} because of something in your past or present?" Alexa will auto fill that and it will sound more intelligent and conversational.
Next you'll want to improve the logic of this intent inside const handlers:
const handlers = {
...
'EmotionalState': function () {
var emotion = this.event.request.intent.slots.Emotion.value;
var timeframe = this.event.request.intent.slots.Timeframe.value;
if (!timeframe){
this.emit(':delegate');
} else {
var response = responseBuilder(emotion, timeframe);
this.emit(':tell', response);
}
},
...
} //<<--------------your code seems to be missing this to close handlers
function responseBuilder(emotion, timeframe) {
// compare emotion with timeframe to build the appropriate response
// just for example
if (emotion=="sad" && timeframe=="past") {
return "My suggestion for feeling sadness about the past is, dry your tears and find a distraction.";
}
}
That's just a rough idea, but should certainly get you progressing again. Good luck!
Create a global object emotions and have all the emotions as properties and the corresponding suggestions as the value for them. Something like this,
const emotions = {"Happy" : "Keep smiling and shining", "Angry" : "count to 10 and cool down"}
Then, access the global object with the varibale to which you got the slot value from the user utterance and add it along with your response.
For instance,
var stateSlot = this.event.request.intent.slots.Emotion.value;
var suggestion = emotions[stateSlot];
Use the square bracket to get the property in the emotions object that matches for the value in the variable stateSlot.

Accessing published Meteor data

Not sure if I'm going about this the right way. I'll map out what I'm trying to achieve and please give me any feedback you can. Also very new to meteor so sorry if I'm a bit uneducated in some aspects. This is going to be a two player game where users login in with accounts-twitter or accounts-facebook. Here's the tricky part it will only initialize the game if there are two users logged in. To figure out who is logged in I have put this line of code in my server portion:
if (Meteor.isServer) {
Meteor.publish("userStatus", function() {
return Meteor.users.find({
"status.online": true
})
});
}
My idea of what needs to be done is write an if statement if(userStatus === true){get a users "_id"} then push that user into an array and have a for loop run through every 2 users signed on in the array and initialize a game for them. Also the main question is how do I grab the users ID if status.online is true? Also any input on how to make this more efficient is much appreciated.
Answering your "main question," you would do this with a mongoDB for-each like so.
Meteor.methods({
getOnline : function(){
var retArr = new Array();
Meteor.users.find({"status.online": true}).forEach(function(u){
retArr.push(u._id); //populated retArr with the id of users online
});
return retArr;
}
});
If I left out something or you need clarification on something, please comment.

How to create discincts JS methodes in Spotify App

I've been working on a small Spotify app for some time now. I started using the old API (0.x) but now that I want to access the user's playlists, I need to use the library module which is only available throught the API version 1.0
The spotify team even gives a migration guide to do so ! (if you read me: Thanks guys for all this ;) ).
I already have created a few objects (It's a small app so I don't need much more than that), with a function for each one of my needs, like so:
var sp = getSpotifyApi();
var models = require('sp://import/scripts/api/models');
var player = models.player;
var views = require('sp://import/scripts/api/views');
// in file 'mySpotify.js'
var mySpotify =
{
playerNextTrack: function()
{
player.next();
},
}
Whenever I need to Skip the current track, I can call mySpotify.playerNextTrack();
But now, with the new API, I need to do things like this (from Spotify doc):
require(['$api/models'], function(models) {
var player = models.player;
player.next();
});
My question is simple: how can I include this kind of code into my objects ? How can I give a name to this last "function" ?
As I'm fresh new to JS, I'm probably doing something wrong or understood something the wrong way so feel free to elaborate if you can ;)
I'll start with what I think is the easy answer, just put the require([], function {[all your code]}); around your whole myspotify.js file. That's basically what I have for mine, though I haven't built any of my own objects. Don't think that would matter.
Update
Here's a bit more info showing that objects can be used. Is this what you were looking for?
require(['$api/models'], function(models) {
var mySpotify =
{
playerNextTrack: function()
{
models.player.skipToNextTrack();
},
}
var playtest = document.querySelector('#playtest');
playtest.addEventListener('click', function() { mySpotify.playerNextTrack(); });
});

Subscribe to a count of an existing collection

I need to keep track of a counter of a collection with a huge number of documents that's constantly being updated. (Think a giant list of logs). What I don't want to do is to have the server send me a list of 250k documents. I just want to see a counter rising.
I found a very similar question here, and I've also looked into the .observeChanges() in the docs but once again, it seems that .observe() as well as .observeChanges() actually return the whole set before tracking what's been added, changed or deleted.
In the above example, the "added" function will fire once per every document returned to increment a counter.
This is unacceptable with a large set - I only want to keep track of a change in the count as I understand .count() bypasses the fetching of the entire set of documents. The former example involves counting only documents related to a room, which isn't something I want (or was able to reproduce and get working, for that matter)
I've gotta be missing something simple, I've been stumped for hours.
Would really appreciate any feedback.
You could accomplish this with the meteor-streams smart package by Arunoda. It lets you do pub/sub without needing the database, so one thing you could send over is a reactive number, for instance.
Alternatively, and this is slightly more hacky but useful if you've got a number of things you need to count or something similar, you could have a separate "Statistics" collection (name it whatever) with a document containing that count.
There is an example in the documentation about this use case. I've modified it to your particular question:
// server: publish the current size of a collection
Meteor.publish("nbLogs", function () {
var self = this;
var count = 0;
var initializing = true;
var handle = Messages.find({}).observeChanges({
added: function (id) {
count++;
if (!initializing)
self.changed("counts", roomId, {nbLogs: count});
},
removed: function (id) {
count--;
self.changed("counts", roomId, {nbLogs: count});
}
// don't care about moved or changed
});
// Observe only returns after the initial added callbacks have
// run. Now return an initial value and mark the subscription
// as ready.
initializing = false;
self.added("counts", roomId, {nbLogs: count});
self.ready();
// Stop observing the cursor when client unsubs.
// Stopping a subscription automatically takes
// care of sending the client any removed messages.
self.onStop(function () {
handle.stop();
});
});
// client: declare collection to hold count object
Counts = new Meteor.Collection("counts");
// client: subscribe to the count for the current room
Meteor.subscribe("nbLogs");
// client: use the new collection
Deps.autorun(function() {
console.log("nbLogs: " + Counts.findOne().nbLogs);
});
There might be some higher level ways to do this in the future.

Categories