Skip to content

Commit cc3f557

Browse files
committed
Instagram node fixes
1 parent e537111 commit cc3f557

File tree

3 files changed

+106
-101
lines changed

3 files changed

+106
-101
lines changed

instagram/instagram.html

+6-7
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@
6666
<div class="form-row">
6767
<label for="node-input-outputType"><i class="icon-search"></i> Output</label>
6868
<select type="text" id="node-input-outputType" style="display: inline-block; vertical-align: middle; width:60%;">
69-
<option value="file">The photo as a buffer</option>
70-
<option value="link">The photo url</option>
69+
<option value="buffer">the photo as a buffer</option>
70+
<option value="link">the photo url</option>
7171
</select>
7272
</div>
7373
<div class="form-row">
@@ -104,8 +104,8 @@
104104
<div class="form-row">
105105
<label for="node-input-outputType"><i class="icon-search"></i> Output</label>
106106
<select type="text" id="node-input-outputType" style="display: inline-block; vertical-align: middle; width:60%;">
107-
<option value="file">The photo as a buffer</option>
108-
<option value="link">The photo url</option>
107+
<option value="buffer">the photo as a buffer</option>
108+
<option value="link">the photo url</option>
109109
</select>
110110
</div>
111111
<div class="form-row">
@@ -244,7 +244,7 @@
244244
defaults: {
245245
instagram: { type:"instagram-credentials", required: true },
246246
inputType: { value: "photo"},
247-
outputType: { value:"file" },
247+
outputType: { value:"buffer" },
248248
name: {value:""}
249249
},
250250
color:"#889FB3",
@@ -266,14 +266,13 @@
266266
defaults: {
267267
instagram: { type:"instagram-credentials", required: true },
268268
inputType: { value: "photo"},
269-
outputType: { value:"file" },
269+
outputType: { value:"buffer" },
270270
name: {value:""}
271271
},
272272
color:"#889FB3",
273273
inputs:1,
274274
outputs:1,
275275
icon: "instagram.png",
276-
align: "right",
277276
label: function() {
278277
return this.name||"Instagram";
279278
},

instagram/instagram.js

+99-93
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ module.exports = function(RED) {
2323
var Url = require('url');
2424
var request = require('request');
2525

26-
var DUMMY = null;
2726
var IMAGE = "image";// currently we're only considering images
2827

2928
var repeat = 900000; // 15 minutes => the repeat frequency of the input node
3029

3130
function InstagramCredentialsNode(n) {
3231
RED.nodes.createNode(this,n);
33-
this.clientID = n.clientID;
32+
// this.clientID = n.clientID;
3433
}
3534

3635
function downloadImageAndSendAsBuffer(node, url, msg) {
@@ -55,7 +54,7 @@ module.exports = function(RED) {
5554

5655
// Now grab initial state but only grab the ones we're concerned with
5756

58-
if (node.inputType === "photo") {
57+
if (node.inputType === "photo") {
5958
ig.user_media_recent('self', { count : 1, min_id : null, max_id : null}, function(err, medias, pagination, remaining, limit) {
6059
if (err) {
6160
node.warn('Instagram node has failed to fetch latest user photo : '+err);
@@ -64,17 +63,18 @@ module.exports = function(RED) {
6463
if(medias.length > 0) { // if the user has uploaded something to Instagram already
6564
node.latestSelfContentID = medias[0].id;
6665
}
67-
68-
node.initialized = true;
66+
67+
node.on("input", function(msg) {
68+
handleNodeInput(node, msg);
69+
});
70+
6971
if(isInputNode === true) {
7072
node.interval = setInterval(function() { // self trigger
7173
node.emit("input", {});
7274
}, repeat);
7375
}
7476
});
75-
}
76-
77-
if (node.inputType === "like") {
77+
} else if (node.inputType === "like") {
7878
ig.user_self_liked({ count : 1, max_like_id : null}, function(err, medias, pagination, remaining, limit) {
7979
if (err) {
8080
node.warn('Instagram node has failed to fetch latest liked photo : '+err);
@@ -83,7 +83,11 @@ module.exports = function(RED) {
8383
if(medias.length > 0) { // if the user has liked something to Instagram already
8484
node.latestLikedID = medias[0].id;
8585
}
86-
node.initialized = true;
86+
87+
node.on("input", function(msg) {
88+
handleNodeInput(node, msg);
89+
});
90+
8791
if(isInputNode === true) {
8892
node.interval = setInterval(function() { // self trigger
8993
node.emit("input", {});
@@ -104,38 +108,43 @@ module.exports = function(RED) {
104108
var carryOnPaginating = true;
105109

106110
if (err) {
107-
node.warn('Instagram node has failed to fetch latest liked media : '+err);
111+
node.warn('Instagram node has failed to fetch latest media : '+err);
108112
}
109113

110-
for(var i = 0; i < medias.length; i++) {
111-
if (node.inputType === "like") { // like is a special case as per Instagram API behaviour
112-
if(areWeInPaginationRecursion === false) { // need to set the pointer of latest served liked image before pagination occurs
113-
idOfLikedReturned = medias[0].id;
114+
if(medias) {
115+
for(var i = 0; i < medias.length; i++) {
116+
if (node.inputType === "like") { // like is a special case as per Instagram API behaviour
117+
if(areWeInPaginationRecursion === false) { // need to set the pointer of latest served liked image before pagination occurs
118+
idOfLikedReturned = medias[0].id;
119+
}
120+
if (medias[i].id === node.latestLikedID || node.latestLikedID === null) { // we finally found the image we already returned or has been there at init
121+
node.latestLikedID = idOfLikedReturned; // we need to assign the latest liked to the one we returned first => can only do node at the end, otherwise we'd never match break condition and always return everything
122+
carryOnPaginating = false;
123+
break;
124+
}
114125
}
115-
if (medias[i].id === node.latestLikedID || node.latestLikedID === DUMMY) { // we finally found the image we already returned or has been there at init
116-
node.latestLikedID = idOfLikedReturned; // we need to assign the latest liked to the one we returned first => can only do node at the end, otherwise we'd never match break condition and always return everything
117-
carryOnPaginating = false;
118-
break;
126+
127+
if (node.inputType === "photo" && i === 0 && (areWeInPaginationRecursion === false) ) { // only set the served self content ID to equal the first media of the first pagination page and ignore on subsequent pages
128+
idOfSelfReturned = medias[i].id;
119129
}
120-
}
121-
122-
if (node.inputType === "photo" && i === 0 && (areWeInPaginationRecursion === false) ) { // only set the served self content ID to equal the first media of the first pagination page and ignore on subsequent pages
123-
idOfSelfReturned = medias[0].id;
124-
}
125-
126-
if (node.inputType === "photo" && (medias[i].id === node.latestSelfContentID) ) { // if we say to the Insta API that we want images more recent than image id "blah", it returns image with that id too
127-
//deliberate no-op
128-
} else if(medias[i].type === IMAGE) {
129-
var url = medias[i].images.standard_resolution.url;
130-
if (node.outputType === "link") {
131-
msg.payload = url;
132-
node.send(msg);
133-
} else if (node.outputType === "file") {
134-
downloadImageAndSendAsBuffer(node, url, msg);
130+
131+
if (node.inputType === "photo" && (medias[i].id === node.latestSelfContentID) ) { // if we say to the Insta API that we want images more recent than image id "blah", it returns image with that id too
132+
//deliberate no-op
133+
} else if(medias[i].type === IMAGE) {
134+
var url = medias[i].images.standard_resolution.url;
135+
if (node.outputType === "link") {
136+
msg.payload = url;
137+
node.send(msg);
138+
} else if (node.outputType === "buffer") {
139+
downloadImageAndSendAsBuffer(node, url, msg);
140+
}
135141
}
136-
}
142+
}
143+
} else if(areWeInPaginationRecursion === false) {
144+
node.warn('Instagram node has failed to fetch any media');
145+
return;
137146
}
138-
if(pagination.next && carryOnPaginating) {
147+
if(pagination && pagination.next && carryOnPaginating) {
139148
areWeInPaginationRecursion = true;
140149
pagination.next(returnPagefulsOfStuff);
141150
} else {
@@ -146,69 +155,67 @@ module.exports = function(RED) {
146155
// If we're processing user content
147156
if (node.inputType === "photo") {
148157
ig.user_media_recent('self', { count : null, min_id : node.latestSelfContentID, max_id : null}, returnPagefulsOfStuff);
149-
}
150-
151-
// If we're processing likes
152-
if (node.inputType === "like") {
158+
} else if (node.inputType === "like") { // If we're processing likes
153159
ig.user_self_liked({ count : null, max_like_id : null}, returnPagefulsOfStuff);
154160
}
155161
}
156162

157-
function InstagramInNode(n) {
158-
this.latestSelfContentID = DUMMY; // use a dummy -1 value if the user has not liked/uploaded any content yet
159-
this.latestLikedID = DUMMY;
163+
function InstagramInNode(n) {
164+
RED.nodes.createNode(this,n);
165+
166+
var node = this;
167+
168+
node.latestSelfContentID = null; // if the user has not liked/uploaded any content yet
169+
node.latestLikedID = null;
160170

161-
this.inputType = n.inputType;
162-
this.outputType = n.outputType;
171+
node.inputType = n.inputType;
172+
node.outputType = n.outputType;
163173

164-
this.interval = null; // used to track individual refresh intervals
174+
node.interval = null; // used to track individual refresh intervals
165175

166-
RED.nodes.createNode(this,n);
167-
this.instagramConfig = RED.nodes.getNode(n.instagram);
168-
if (!this.instagramConfig) {
169-
this.warn("Missing Instagram credentials");
176+
node.instagramConfig = RED.nodes.getNode(n.instagram);
177+
if (!node.instagramConfig) {
178+
node.warn("Missing Instagram credentials");
170179
return;
171180
}
172181

173-
initializeNode(this, true); // the build in poll interval is getting set up at the end of init
182+
initializeNode(node, true); // the build in poll interval is getting set up at the end of init
174183

175-
this.on("input", function(msg) {
176-
handleNodeInput(this, msg);
177-
});
178-
179-
this.on("close", function() {
180-
if (this.interval !== null) {
181-
clearInterval(this.interval);
184+
node.on("close", function() {
185+
if (node.interval !== null) {
186+
clearInterval(node.interval);
182187
}
188+
node.latestSelfContentID = null;
189+
node.latestLikedID = null;
190+
node.inputType = null;
191+
node.outputType = null;
183192
});
184193
}
185194

186195
function InstagramNode(n) {
196+
RED.nodes.createNode(this,n);
187197

188-
this.initialized = false;
189-
this.latestSelfContentID = DUMMY; // use a dummy -1 value if the user has not liked/uploaded any content yet
190-
this.latestLikedID = DUMMY;
198+
var node = this;
199+
200+
node.latestSelfContentID = null; // if the user has not liked/uploaded any content yet
201+
node.latestLikedID = null;
191202

192-
this.inputType = n.inputType;
193-
this.outputType = n.outputType;
203+
node.inputType = n.inputType;
204+
node.outputType = n.outputType;
194205

195-
RED.nodes.createNode(this,n);
196-
this.instagramConfig = RED.nodes.getNode(n.instagram);
197-
if (!this.instagramConfig) {
198-
this.warn("Missing Instagram credentials");
206+
node.instagramConfig = RED.nodes.getNode(n.instagram);
207+
if (!node.instagramConfig) {
208+
node.warn("Missing Instagram credentials");
199209
return;
200210
}
201211

202-
if(this.initialized !== true) {
203-
initializeNode(this, false);
204-
}
212+
initializeNode(node, false);
205213

206-
this.on("input", function(msg) {
207-
if(this.initialized === true) {
208-
handleNodeInput(this, msg);
209-
} else {
210-
this.warn("Instagram node has received an input before it had initialized. Input dropped.");
211-
}
214+
node.on("close", function() {
215+
node.latestSelfContentID = null;
216+
node.latestLikedID = null;
217+
node.inputType = null;
218+
node.outputType = null;
212219
});
213220
}
214221

@@ -299,25 +306,24 @@ module.exports = function(RED) {
299306
return res.send("oauth error: " + data.error);
300307
}
301308

302-
credentials.access_token = data.access_token;
309+
if(result.statusCode !== 200) {
310+
return res.send("Instagram replied with the unexpected HTTP status code of " + result.statusCode + "\nDetails:\n" + data);
311+
}
303312

304-
// figuring out the user's username for the UI:
305-
ig.use({ access_token: credentials.access_token });
306-
ig.user('self', function(err, result, remaining, limit) { // warning, this is not the same as the other result or res!
307-
if (err) {
308-
return res.send('Error! Instagram node has failed to fetch the username : '+err);
309-
}
310-
if(!result) {
311-
return res.send('Error! Fetching the authenticated user\'s details has failed');
312-
}
313-
if(result.username) { // SUCCESS
314-
credentials.username = result.username;
315-
RED.nodes.addCredentials(node_id,credentials);
316-
res.send("<html><head></head><body>Successfully authorized with Instagram. You can close this window now.</body></html>");
317-
} else {
318-
return res.send('Error! No username found for authenticated user.');
319-
}
320-
});
313+
if(data.user.username) {
314+
credentials.username = data.user.username;
315+
} else {
316+
return res.send('Error! Instagram node has failed to fetch the username.');
317+
}
318+
319+
if(data.access_token) {
320+
credentials.access_token = data.access_token;
321+
} else {
322+
return res.send('Error! Instagram node has failed to fetch a valid access token.');
323+
}
324+
325+
RED.nodes.addCredentials(node_id,credentials);
326+
res.send("<html><head></head><body>Successfully authorized with Instagram. You can close this window now.</body></html>");
321327
});
322328
});
323329
};

test/instagram/instagram_spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ describe('instagram nodes', function() {
397397
.reply(200, replyText);
398398

399399
helper.load(instagramNode, [{id:"instagramCredentials1", type:"instagram-credentials"},
400-
{id:"instagramNode1", type:"instagram", instagram: "instagramCredentials1","inputType":"photo","outputType":"file", wires:[["helperNode1"]]},
400+
{id:"instagramNode1", type:"instagram", instagram: "instagramCredentials1","inputType":"photo","outputType":"buffer", wires:[["helperNode1"]]},
401401
{id:"helperNode1", type:"helper"}],
402402
{
403403
"instagramCredentials1" : { // pre-loaded credentials, no need to call OAuth

0 commit comments

Comments
 (0)