From 3bb5bcf9b56c0863d83be128b148271a93612542 Mon Sep 17 00:00:00 2001 From: hgill Date: Wed, 5 May 2021 22:20:02 +0530 Subject: [PATCH] Updates on Twitter-In node: 1. Node now takes topic string input rather than hard-coded 2. "Sticky" followers: If new input string suggests updates in handles to follow, creates "sticky" new intervals - meaning previously followed handles are maintained, new ones added 3. Node now takes refresh time as an input value, previously hardcoded at 60s --- social/twitter/27-twitter.html | 10 ++- social/twitter/27-twitter.js | 81 ++++++++++++++++---- social/twitter/locales/en-US/27-twitter.json | 6 +- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/social/twitter/27-twitter.html b/social/twitter/27-twitter.html index 57ea833b3..eee02c4f1 100644 --- a/social/twitter/27-twitter.html +++ b/social/twitter/27-twitter.html @@ -96,6 +96,10 @@ +
+ + +
@@ -108,7 +112,8 @@ tags: {value:""}, user: {value:"false",required:true}, name: {value:""}, - inputs: {value:0} + inputs: {value:0}, + pollInterval: {value:60000} }, inputs: 0, outputs: 1, @@ -139,6 +144,7 @@ var userph = this._("twitter.placeholder.user"); var forlabel = this._("twitter.label.for"); var forph = this._("twitter.placeholder.for"); + var pollInterval = this._("twitter.placeholder.pollInterval") $("#node-input-user").change(function() { var type = $("#node-input-user option:selected").val(); if (type == "user") { @@ -156,7 +162,7 @@ $("#node-input-user").change(); }, oneditsave: function() { - if ($('#node-input-tags').val() === '' && $("#node-input-user option:selected").val() === 'false') { + if ($('#node-input-tags').val() === ''/* && $("#node-input-user option:selected").val() === 'false'*/) { this.inputs = 1; } else { diff --git a/social/twitter/27-twitter.js b/social/twitter/27-twitter.js index ac037bee8..caa9953af 100644 --- a/social/twitter/27-twitter.js +++ b/social/twitter/27-twitter.js @@ -169,6 +169,7 @@ module.exports = function(RED) { this.twitterConfig = RED.nodes.getNode(this.twitter); this.poll_ids = []; this.timeout_ids = []; + this.pollInterval=n.pollInterval || 60000; var credentials = RED.nodes.getCredentials(this.twitter); this.status({}); @@ -177,17 +178,60 @@ module.exports = function(RED) { var node = this; if (this.user === "true") { // Poll User Home Timeline 1/min - this.poll(60000,"https://api.twitter.com/1.1/statuses/home_timeline.json"); + this.poll(node.pollInterval,"https://api.twitter.com/1.1/statuses/home_timeline.json"); } else if (this.user === "user") { - var users = node.tags.split(/\s*,\s*/).filter(v=>!!v); + var tags= node.tags || ""; + var users = tags.split(/\s*,\s*/).filter(v=>!!v); + /* // Block no longer reqd as accepts msg.payload if (users.length === 0) { node.error(RED._("twitter.warn.nousers")); return; } + */ + + // Poll User timeline + node.lastMessageTS = new Date(); + node.status({fill:"green",shape:"ring",text:"Initializing"}); users.forEach(function(user) { - node.poll(60000,"https://api.twitter.com/1.1/statuses/user_timeline.json",{screen_name: user}); + node.poll(node.pollInterval,"https://api.twitter.com/1.1/statuses/user_timeline.json",{screen_name: user}); }) + + node.on("input", function(msg) { // sticky polling - identifies already tracked handles vs add/remove handles + var payloadtags=msg.payload.split(/\s*,\s*/).filter(v=>!!v); + var screennames=node.poll_ids.map(p=>p.asset.opts.screen_name); + var newusers=payloadtags.filter(x=>!screennames.includes(x)); + var removeusers=screennames.filter(x=>!payloadtags.includes(x)); + newusers.forEach(function(user) { //start tracking new users in msg.payload + node.warn("Twitter-In: New Handle: "+user) + node.status({fill:"green",shape:"ring",text:"Adding handles"}); + node.lastMessageTS = new Date(); + node.poll(node.pollInterval,"https://api.twitter.com/1.1/statuses/user_timeline.json",{screen_name: user}); + }); + removeusers.forEach(function(user) { // remove any tracked users missing from msg.payload + node.poll_ids.forEach((p,i)=>{ + if(user===p.asset.opts.screen_name){ + node.status({fill:"green",shape:"ring",text:"Removing handles"}); + node.lastMessageTS = new Date(); + node.warn("Twitter-In: Delete Handle: "+p.asset.opts.screen_name); + clearInterval(p.interval); + node.poll_ids.splice(i,1); + } + }) + }); + }); + + function checklastMessageTS() { + if(node.lastMessageTS != null){ + var timeDiff = new Date() - node.lastMessageTS; + if(timeDiff > 5000){ + node.status({fill:"yellow",shape:"ring",text:"Idle @ "+node.lastMessageTS.toLocaleTimeString()}); + node.lastMessageTS=null; + } + } + } + + node.interval = setInterval(checklastMessageTS, 1000); } else if (this.user === "dm") { node.pollDirectMessages(); } else if (this.user === "event") { @@ -266,7 +310,7 @@ module.exports = function(RED) { node.log(RED._("twitter.status.using-geo",{location:node.tags.toString()})); } } - + // all public tweets if (this.user === "false") { node.on("input", function(msg) { @@ -312,8 +356,11 @@ module.exports = function(RED) { catch (err) { node.error(err); } + + } this.on('close', function() { + clearInterval(node.interval); if (this.tout) { clearTimeout(this.tout); } if (this.tout2) { clearTimeout(this.tout2); } if (this.stream) { @@ -328,7 +375,7 @@ module.exports = function(RED) { } if (this.poll_ids) { for (var i=0; i 0) { since = res[0].id_str; } - pollId = setInterval(function() { + pollId.asset={url:url,opts:opts}; + pollId.interval = setInterval(function() { + node.lastMessageTS = new Date(); + node.status({fill:"blue",shape:"ring",text:"Polling"}); opts.since_id = since; node.twitterConfig.get(url,opts).then(function(result) { if (result.status === 429) { node.warn("Rate limit hit. Waiting "+Math.floor(result.rateLimitTimeout/1000)+" seconds to try again"); - clearInterval(pollId); + clearInterval(pollId.interval); node.timeout_ids.push(setTimeout(function() { node.poll(interval,url,opts); },result.rateLimitTimeout)) @@ -378,7 +428,7 @@ module.exports = function(RED) { // 'since_id parameter is invalid' - reset it for next time delete opts.since_id; } - clearInterval(pollId); + clearInterval(pollId.interval); node.timeout_ids.push(setTimeout(function() { node.poll(interval,url,opts); },interval)) @@ -409,7 +459,7 @@ module.exports = function(RED) { } }).catch(function(err) { node.error(err); - clearInterval(pollId); + clearInterval(pollId.interval); node.timeout_ids.push(setTimeout(function() { delete opts.since_id; delete opts.count; @@ -433,7 +483,7 @@ module.exports = function(RED) { var node = this; var opts = {}; var url = "https://api.twitter.com/1.1/direct_messages/events/list.json"; - var pollId; + var pollId={}; opts.count = 50; this.twitterConfig.get(url,opts).then(function(result) { if (result.status === 429) { @@ -457,11 +507,12 @@ module.exports = function(RED) { if (messages.length > 0) { since = messages[0].id; } - pollId = setInterval(function() { + pollId.asset={url:url,opts:opts}; + pollId.interval = setInterval(function() { node.twitterConfig.get(url,opts).then(function(result) { if (result.status === 429) { node.warn("Rate limit hit. Waiting "+Math.floor(result.rateLimitTimeout/1000)+" seconds to try again"); - clearInterval(pollId); + clearInterval(pollId.interval); node.timeout_ids.push(setTimeout(function() { node.pollDirectMessages(); },result.rateLimitTimeout)) @@ -471,7 +522,7 @@ module.exports = function(RED) { var res = result.body; if (res.errors) { node.error(res.errors[0].message); - clearInterval(pollId); + clearInterval(pollId.interval); node.timeout_ids.push(setTimeout(function() { node.pollDirectMessages(); },interval)) @@ -532,7 +583,7 @@ module.exports = function(RED) { } }).catch(function(err) { node.error(err); - clearInterval(pollId); + clearInterval(pollId.interval); node.timeout_ids.push(setTimeout(function() { node.pollDirectMessages(); },interval)) diff --git a/social/twitter/locales/en-US/27-twitter.json b/social/twitter/locales/en-US/27-twitter.json index 4282327da..739262a3e 100644 --- a/social/twitter/locales/en-US/27-twitter.json +++ b/social/twitter/locales/en-US/27-twitter.json @@ -16,11 +16,13 @@ "copy-accessToken": "Create a new 'Access token & access token secret' and copy them", "access_key": "Access token", "access_secret": "Access token secret", - "enter-id": "Set your Twitter ID" + "enter-id": "Set your Twitter ID", + "pollInterval": "Poll Interval" }, "placeholder": { "for": "comma-separated words, @ids, #tags", - "user": "comma-separated @twitter handles" + "user": "comma-separated @twitter handles", + "pollInterval": "Time in milliseconds, default 60000 (1 minute)" }, "search": { "public": "all public tweets",