var yModule = require('youtube-node'),
nodeYoutube = new yModule();
nodeYoutube.setKey("key");
module.exports.getVideoLength = function (vData){
youTube.getById(vData, function (result) {
return convertTime(result['items'][0]['contentDetails']['duration']);
})
};
var convertTime = function (time){
var reptms = /(?:(\d+)DT)?(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/;
var days = "00", hours = "00", minutes = "00", seconds = "00", formattedTime;
//if (reptms.test(time)) {
var matches = reptms.exec(time);
console.log(matches);
if (matches[1]) days = String(matches[1]);
if (matches[2]) hours = String(matches[2]);
if (matches[3]) minutes = String(matches[3]);
if (matches[4]) seconds = String(matches[4]);
formattedTime = "[" + days + ":" + hours + ":" + minutes + ":" + seconds + "]";
return formattedTime;
//}
};
I'm struggling to understand callbacks even after reading a few things about it.
nodeJs callbacks simple example this helped a little, but I'm still unclear about how it works. I've spent the past hour trying to figure out how to write this using callbacks.
This module is being called by this:
ytRetrieve.getVideoLength(youtube_parser(text))
youtube_parser's function:
function youtube_parser(url){
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
var match = url.match(regExp);
//console.log(match);
if (match&&match[7]){
return match[7].split(" ")[0];
}
}
You need to use callbacks. The issue with your code youtube_parser( is that you are calling the function. A callback is a function that is passed as an argument to be called later. If you call the function, a string is returned. getVideoLength is expecting a function as an argument, not a string.
Instead use getVideoLength(youtube_parser). This actually passes in the youtube_parser function itself to be called later (i.e. when getVideoLength completes). The arguments to youtube_parser may need to be (error, url) instead, though.
Here is a solution I came up with. Is there anything I can do to enhance this code?
Thank you for your help.
Main.js
var ytempRetrieve = require('./youtube'), ytRetrieve = new ytempRetrieve();
var ytRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?/;
bot.addListener('message', function (from, to, text, message) {
if (text.match(ytRegex)) {
console.log(text);
youtube_parser(text, to, ytRetrieve.getVideoLength)
}
});
function youtube_parser(url, to, callback) {
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
var match = url.match(regExp);
//console.log(match);
if (match && match[7]) {
callback(match[7].split(" ")[0], function (res) {
setTimeout(function () {
bot.say(to, match[7].split(" ")[0] + " is " + res + " long.")
}, 1500)
});
}
}
youtube.js
var yModule = require('youtube-node'),
nodeYoutube = new yModule(),
apiKey = require('./config');
var youtube = function () {
var self = this;
self.time = null;
self.setAPIKey = function (key) {
nodeYoutube.setKey(key);
};
apiKey.getAPIKey(self.setAPIKey);
self.getVideoLength = function (vData, callback) {
nodeYoutube.getById(vData, function (result) {
callback(self.convertTime(result['items'][0]['contentDetails']['duration']));
})
};
self.convertTime = function (time) {
var reptms = /(?:(\d+)DT)?(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/;
var days = 0, hours = 0, minutes = 0, seconds = 0, formattedTime;
//if (reptms.test(time)) {
var matches = reptms.exec(time);
console.log(matches);
if (matches[1]) days = Number(matches[1]);
if (matches[2]) hours = Number(matches[2]);
hours += days * 24;
if (hours.toString().length === 1) {
hours = "0" + hours
}
if (matches[3]) minutes = String(matches[3]);
if (minutes.toString().length === 1) {
minutes = "0" + minutes
}
if (matches[4]) seconds = String(matches[4]);
if (seconds.toString().length === 1) {
seconds = "0" + seconds
}
formattedTime = "[" + hours + ":" + minutes + ":" + seconds - 1 + "]";
return (formattedTime);
//}
};
};
module.exports = youtube;
Related
does anyone have time to help me with a little problem? I did this function to check the license time but it doesn't really work, does anyone have any idea?
https://cdn.discordapp.com/attachments/953617052202074132/954398145868083291/unknown.png
https://cdn.discordapp.com/attachments/953617052202074132/954398654217723914/unknown.png
exilied_client.on('message', async message => {
if (message.content.startsWith(`${prefix}time`)) {
automex = message.author;
if(message.guild == undefined) {
message.reply("Comenzile le poti da doar pe server-ul de discord");
return;
};
if(message.member.roles.cache.has(zedu_roldiscord)) {
const argomento = message.content.slice(prefix.length).split(/ +/g)
const comando = argomento.shift().toLowerCase();
var i = 1;
if(argomento[0])
{
if(message.member.roles.cache.has(zedu_roldiscord))
{
var verificaretimp = message.guild.member(message.mentions.users.first() || message.guild.members.fetch(argomento[1]))
} else {
message.delete()
message.reply(automex.username + " Ce gatu ma-tii vrei sa faci?")
return;
}
} else {
var verificaretimp = automex
}
const Verificare = `SELECT license, used, total_time FROM licenses WHERE userid = '${verificaretimp.id}';`
const autoreasd = querytxt => {
return new Promise((resolve, reject) => {
exilied_database.query(querytxt, (err, results, fields) => {
if (err) reject(err);
resolve([results, fields]);
});
});
};
const [results, fields] = await autoreasd(Verificare);
const Mappa1 = results.map(results => `${(results.used)}`);
const Mappa2 = results.map(results => `${(results.total_time)}`);
var TempoAttesa = parseInt (Mappa1, 10);
var TempoAttesa2 = parseInt (Mappa2, 10);
function ConvertireTimp(UNIX_timestamp){
var exilied_time = new Date(UNIX_timestamp * 1000);
var mesi = ['January','February','March','April','May','June','July','August','September','October','November','December'];
exilied_time.setDate(exilied_time.getDate() + TempoAttesa2);
var year = exilied_time.getFullYear();
var month = mesi[exilied_time.getMonth()];
var date = exilied_time.getDate();
var hour = exilied_time.getHours();
var min = exilied_time.getMinutes();
var sec = exilied_time.getSeconds();
var time = date + ' ' + month + ' ' + year + ' ' + hour + ":"+ min;
return time;
}
message.delete()
var convertireatimp = ConvertireTimp(TempoAttesa2)
var expirelicense = automex.send("**__Your License Expired On__**: \n" + "" + convertireatimp + " \n If Not See Date Your Key Is Expired")
} else {
automex.send("**You Dont Have A License Key**")
}
}
});```
I'm running a pubsub scheduled function on firebase functions which run every two mintues.
I try to log the events collected by the snapshot loop but something doesn't go properly.
exports.check_event_ended_notification = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
let default_lineup = "default";
let events = [];
return admin.database().ref("Events").once('value')
.then(snapshot => {
console.log(("EVENTS number : " + snapshot.numChildren()));
snapshot.forEach(event_snapshot => {
let event_key = event_snapshot.key;
let event = event_snapshot.val();
events.push(event_key);
console.log("EVENT_UID : " + event_key);
console.log(("EVENTS : " + events));
// iterate through all events and check if they're marked as ended
// if not, check if ended
let event_status = event[['ended_status']];
if (event_status === '0') {
// get event date
let event_day = event[['date']]['0'];
let event_month = event[['date']]['1'];
let event_year = event[['date']]['2'];
let event_full_date = event_year + "-" + event_month + "-" + event_day;
// get today date
let today = new Date();
let today_day = today.getDate();
let today_month = (today.getMonth() + 1);
let today_year = today.getFullYear();
let today_full_date = today_year + "-" + today_month + "-" + today_day;
//create date objects to compare
let event_date = new Date(event_full_date);
let today_date = new Date(today_full_date);
// if event date is in the past
// check to see if its marked as ended.
if (event_date.getTime() < today_date.getTime()) {
console.log("EVENT : past event : " + event_key);
if (event[['ended_status']] === "0") {
console.log("EVENT : ended 0 : " + event_key);
//mark as ended
// admin.database().ref("Events/"+event_key+"/ended_status").set("1");
//create notifications for participation artists
for (let artist_key in event[['lineup']]) {
console.log("ARTIST before: " + artist_key);
if (artist_key !== default_lineup) {
console.log("ARTIST after: " + artist_key);
let approved_invitation = event[['lineup']][artist_key]['approved_invitation'];
let handshake_status = event[['lineup']][artist_key]['handshake_status'];
let quit = event[['lineup']][artist_key]['quit'];
let removed = event[['lineup']][artist_key]['removed'];
let event_publish_status = event[['publish_status']];
let owner_uid = event[['owner_uid']];
if (approved_invitation === '1' && handshake_status === '1' && quit === '0' && removed === '0' && event_publish_status === '1') {
return admin.database().ref("Notifications/" + artist_key + "/" + owner_uid + "/" + event['uid']).push({
notification_type: "ended",
seen_status: "0",
timestamp: new Date().getTime()
})
}
}
}
}
}
}
return null;
})
})
}
while the numChildren() log at the beginning show there are 4 children under the snapshot (which is correct), the foreach() method seems to run only twice, collecting the first two children and adding them to the "events" list.
and the logs stop after this:
2020-07-29T14:22:00.593Z ? check_event_ended_notification: EVENTS number : 4
2020-07-29T14:22:00.593Z ? check_event_ended_notification: EVENT_UID : 3853c2db-f31a-4f46-8c1b-740ca4e3407b
2020-07-29T14:22:00.593Z ? check_event_ended_notification: EVENTS : 3853c2db-f31a-4f46-8c1b-740ca4e3407b
2020-07-29T14:22:00.594Z ? check_event_ended_notification: EVENT_UID : 4253c2db-f31a-4f46-8c1b-740ca4e3407s
2020-07-29T14:22:00.594Z ? check_event_ended_notification: EVENTS : 3853c2db-f31a-4f46-8c1b-740ca4e3407b,4253c2db-f31a-4f46-8c1b-740ca4e3407s
You are not correctly managing the life cycle of your Cloud Function. As explained in the doc, you need to "resolve functions that perform asynchronous processing (also known as "background functions") by returning a JavaScript promise".
Also, in a Cloud Function, it is not recommended to use the on() method, which sets a listener, but the once() one, which "listens for exactly one event of the specified event type, and then stops listening.".
So the following should do the trick:
exports.check_event_ended_notification = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
let default_lineup = "default";
let events = [];
return admin.database().ref("Events").once('value') // Note the return here
.then(snapshot => {
snapshot.forEach(event_snapshot => {
let event_key = event_snapshot.key;
let event = event_snapshot.val();
events.push(event_key)
console.log("EVENT_UID : " + event_key);
console.log(("EVENTS : " + events));
});
// Do something with events... We don't have enough details
return null; // Or return a promise
});
});
Update following your comment
If you want, in the forEach(), to write to the database (which is an asynchronous process), you should use Promise.all(), in order to return a promise when all the parallel calls to the asynchronous push() method are done.
Here is a skeleton of the code, that you should adapt with all the details:
exports.check_event_ended_notification = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
let default_lineup = "default";
let events = [];
return admin.database().ref("Events/").once('value')
.then(snapshot => {
const promises = [];
snapShot.forEach(event_snapshot => {
let event_key = event_snapshot.key;
let event = event_snapshot.val();
events.push(event_key)
console.log("EVENT_UID : " + event_key);
console.log(("EVENTS : " + events));
promises.push(
admin.database().ref("Notifications/" + artist_key + "/" + owner_uid + "/" + event['uid']).push({
notification_type: "ended",
seen_status: "0",
timestamp: new Date().getTime()
})
);
});
return Promise.all(promises); // This returns a promise!!
});
});
I have this code:
var CookieHelper = function () {
return {
GetCookie : function (cookieName) {
var cookieNameRequest = cookieName + "=";
var cookiesCollection = document.cookie.split(";");
for (var i = 0; i < cookiesCollection.length; i++) {
var cookieValuePair = cookiesCollection[i];
while (cookieValuePair.charAt(0) == " ") cookieValuePair = cookieValuePair.substring(1, cookieValuePair.length);
if (cookieValuePair.indexOf(cookieNameRequest) == 0)
return cookieValuePair.substring(cookieNameRequest.length, cookieValuePair.length);
}
return null;
},
DeleteCookie : function (cookieName) {
CookieHelper.SetCookie(cookieName, "", -1);
},
SetCookie : function (cookieName, cookieValue, cookieExpirationDays) {
var tmpDate = new Date;
if (cookieExpirationDays) {
tmpDate.setTime(tmpDate.getTime() + cookieExpirationDays * 24 * 60 * 60 * 1000);
var expires = "; expires=" + tmpDate.toGMTString();
} else {
// if cookieExpirationDays isn't set cookie will expire at the end of the day
var expirationTime = new Date(tmpDate.getFullYear(), tmpDate.getMonth(), tmpDate.getDate(), 23, 59, 59);
var expires = "; expires=" + expirationTime.toGMTString();
}
document.cookie = cookieName + "=" + cookieValue + expires + "; path=/;" + (location.protocol === "https:" ? "secure=true" : "");
}
};
}();
and I need to write unit tests for GetCookie.
I tried with:
QUnit.module('Cookie Helper Tests');
QUnit.test('GetCookie - returns no cookie', function(assert) {
var stub = sinon.spy(CookieHelper, 'GetCookie');
var cookieName = 'testCookieName';
var cookieValue = CookieHelper.GetCookie(cookieName);
assert.ok(cookieValue == null, 'returns no cookie');
});
I need to mock/stub document.cookie but I am completely new with Sinon and QUnit.
Can someone give me explanation what I did wrong?
Thanks in advance!
Srdjan
Well actually you can't mock properties with Sinon and more over you cannot mock the document.cookies property as it's immutable. What you can do though, is to use a fake double object that mimics the behavior of the original object, as described here.
For example, if you were running the same test outside of the browser (e.g. in NodeJS) you would do something like that
const chai = require('chai');
const sinon = require('sinon');
const SinonChai = require('sinon-chai');
chai.use(SinonChai);
chai.should();
context('test', function() {
it('should pass',
(done) => {
var cookieName = 'testCookieName';
document = {
cookie: cookieName + '=123'
};
var cookieValue = CookieHelper.GetCookie(cookieName);
console.log(cookieValue);
done();
});
});
in order to introduce a document object to the context and mimic it's cookies attribute by returning a fixed result.
Now, there is a workaround for the browser which involves redefining the getter and setter of 'document.cookie' as described here:
(function (document) {
var cookies = {};
document.__defineGetter__('cookie', function () {
var output = [];
for (var cookieName in cookies) {
output.push(cookieName + '=' + cookies[cookieName]);
}
return output.join(';');
});
document.__defineSetter__('cookie', function (s) {
var indexOfSeparator = s.indexOf('=');
var key = s.substr(0, indexOfSeparator);
var value = s.substring(indexOfSeparator + 1);
cookies[key] = value;
return key + '=' + value;
});
document.clearCookies = function () {
cookies = {};
};
})(document);
I have written this code to get the value of the Timer in a div :
var timerGenerator = (function() {
var time = {
centiSec: 0,
secondes: 0,
minutes: 0,
hours: 0
};
var container = document.createElement("div");
var timeDisplay = function() {
function smoothDisplay(value) {
return (value < 10 ? '0' : '') + value;
}
return "" + smoothDisplay(this.hours) + ":" + smoothDisplay(this.minutes) + ":" + smoothDisplay(this.secondes) + "." + smoothDisplay(this.centiSec);
};
var boundTimeDisplay = timeDisplay.bind(time);
var timeUpdate = function() {
container.innerHTML = boundTimeDisplay();
//console.log(container);
this.centiSec++;
if(this.centiSec === 100) {
this.centiSec = 0;
this.secondes++;
}
if(this.secondes === 60) {
this.secondes = 0;
this.minutes++;
}
if(this.minutes === 60) {
this.minutes = 0;
this.hours++;
}
};
var boundTimeUpdate = timeUpdate.bind(time);
window.setInterval(boundTimeUpdate,10);
console.log(container);
return container;
})();
This code works when I link the var timerGenartor with a div. But, now I would like to return the var container into a string. So I changed my code to this : (I just changed the initialization of container and this value)
var timerGenerator = (function() {
var time = {
centiSec: 0,
secondes: 0,
minutes: 0,
hours: 0
};
var container = "";
var timeDisplay = function() {
function smoothDisplay(value) {
return (value < 10 ? '0' : '') + value;
}
return "" + smoothDisplay(this.hours) + ":" + smoothDisplay(this.minutes) + ":" + smoothDisplay(this.secondes) + "." + smoothDisplay(this.centiSec);
};
var boundTimeDisplay = timeDisplay.bind(time);
var timeUpdate = function() {
container = boundTimeDisplay();
//console.log(container);
this.centiSec++;
if(this.centiSec === 100) {
this.centiSec = 0;
this.secondes++;
}
if(this.secondes === 60) {
this.secondes = 0;
this.minutes++;
}
if(this.minutes === 60) {
this.minutes = 0;
this.hours++;
}
};
var boundTimeUpdate = timeUpdate.bind(time);
window.setInterval(boundTimeUpdate,10);
console.log(container);
return container;
})();
With this modification nothing is returned or display in the console and I don't understand why. However, the comment "console.log" gives me good the timer. So, why the first console.log displays the good result and not the second one ?
The working code as you expected with two JS functions
// JS 1
var timerGenerator = (function() {
var time = {
centiSec: 0,
secondes: 0,
minutes: 0,
hours: 0
};
var container = "";
var timeDisplay = function() {
function smoothDisplay(value) {
return (value < 10 ? '0' : '') + value;
}
return "" + smoothDisplay(this.hours) + ":" + smoothDisplay(this.minutes) + ":" + smoothDisplay(this.secondes) + "." + smoothDisplay(this.centiSec);
};
var boundTimeDisplay = timeDisplay.bind(time);
var timeUpdate = function() {
container = boundTimeDisplay();
//console.log(container);
this.centiSec++;
if(this.centiSec === 100) {
this.centiSec = 0;
this.secondes++;
}
if(this.secondes === 60) {
this.secondes = 0;
this.minutes++;
}
if(this.minutes === 60) {
this.minutes = 0;
this.hours++;
}
return container;
};
var boundTimeUpdate = timeUpdate.bind(time);
return boundTimeUpdate;
})();
// JS 2
var spanGenerator = (function() {
var container = document.createElement('span');
window.setInterval(function(){
container.innerHTML = timerGenerator();
}, 10);
return container;
})();
document.getElementById('timer').appendChild(spanGenerator);
<div id="timer"></div>
It can be because your container is empty as it is initialized in timeUpdate function which is eventually called 10ms later(for the first time) because of the setInterval. U will have to call the timeUpdate function before putting it in setInterval.
My domain is quite simple. I have a Message class, and a MessagesManager class.
Message has 3 attributes:
author
message (body)
timestamp
MessagesManager is basically just an interface that keeps the history of messages, adds new messages etc.
I want to store the messages in localStorage so that they can be retrieved at later points, yet I'm not sure how to do it.
class MessagesManager {
constructor() {
this.msgs = []; //retrieve from localStorage
}
add(author, message) {
var msg = new Message(author, message)
this.msgs.push(msg);
}
save() {
// save to localStorage
}
delete() {
this.msgs = [];
}
}
And my Message:
class Message {
constructor(author, message) {
this.timestamp = Date.now();
this.author = author;
this.message = message;
}
toString() {
var date = new Date(this.timestamp);
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
if (hours < 10) hours = "0" + hours;
if (minutes < 10) minutes = "0" + minutes;
if (seconds < 10) seconds = "0" + seconds;
var time = "[" + [hours, minutes, seconds].join(":") + "]";
return time + " " + this.author + ": " + this.message;
}
}
What is the nicest/best way to store the messages (as objects, kind of) in the localStorage, while also being able to retrieve them easily (ie. in MessagesManager contructor)?
Try this:
class MessagesManager {
constructor() {
this.msgs = (localStorage.getItem("messages"))?JSON.parse(localStorage.getItem("messages")):[];
}
add(author, message) {
var msg = new Message(author, message)
this.msgs.push(msg);
}
save() {
localStorage.setItem("messages", JSON.stringify(this.msgs));
}
delete() {
this.msgs = [];
localStorage.removeItem("messages");
}
}
Docs: http://www.w3schools.com/html/html5_webstorage.asp