UNPKG

9.29 kBJavaScriptView Raw
1
2import https from 'https';
3import querystring from 'querystring';
4import Promise from 'bluebird';
5import logger from '../lib/logger';
6
7class InstagramSDK {
8 instagramHost = 'api.instagram.com';
9 apiPath = '/v1';
10
11 constructor({clientID = null, clientSecret = null, accessToken = null} = {}) {
12
13 if(!clientID && !clientSecret && !accessToken) {
14 throw new Error('You must specify on of: `accessToken` or both `clientID` and `clientSecret`.');
15 }
16
17 this.clientID = clientID;
18 this.clientSecret = clientSecret;
19 this.accessToken = accessToken;
20
21 if(!accessToken && (clientID && clientSecret)) {
22 this.printLoginUrl();
23 } else if(accessToken) {
24
25 }
26 }
27
28 printLoginUrl() {
29 console.log(`https://${this.instagramHost}/oauth/authorize/?client_id=${this.clientID}&redirect_uri=http://poster.loc&response_type=code`);
30 }
31
32
33 //////////////////////////
34 //// Users
35 //////////////////////////
36 getSelf() {
37 return this._request().then(this._parseJSON);
38 }
39
40 getSelfRecentMedia({count = 10, min_id = undefined, max_id = undefined} = {}) {
41 return this._request({path: '/users/self/media/recent', query: {count, min_id, max_id}}).then(this._parseJSON);
42 }
43
44 getSelfRecentLikes({count = 10, max_like_id = undefined} = {}) {
45 return this._request({path: '/users/self/media/liked', query: {count, max_like_id}}).then(this._parseJSON);
46 }
47
48 getUser(userID) {
49 if(!userID) {
50 throw new Error('Argument `userID` is required.');
51 }
52
53 return this._request({path: '/users/' + userID}).then(this._parseJSON);
54 }
55
56 getUserRecentMedia(userID, {count = 10, min_id = undefined, max_id = undefined} = {}) {
57 if(!userID) {
58 throw new Error('Argument `userID` is required.');
59 }
60
61 return this._request({path: `/users/${userID}/media/recent`, query: {count, min_id, max_id}}).then(this._parseJSON);
62 }
63
64 usersSearch({q = '', count = 10} = {}) {
65 return this._request({path: '/users/search', query: {q, count}}).then(this._parseJSON);
66 }
67
68 //////////////////////////
69 //// Relationships
70 //////////////////////////
71
72 getSelfFollows() {
73 return this._request({path: '/users/self/follows'}).then(this._parseJSON);
74 }
75
76 getSelfFollowedBy() {
77 return this._request({path: '/users/self/followed-by'}).then(this._parseJSON);
78 }
79
80 getSelfRequestedBy() {
81 return this._request({path: '/users/self/requested-by'}).then(this._parseJSON);
82 }
83
84 getUserRelationship(userID) {
85 if(!userID) {
86 throw new Error('Argument `userID` is required.');
87 }
88
89 return this._request({path: `/users/${userID}/relationship`}).then(this._parseJSON);
90 }
91
92 updateUserRelationship(userID, action) {
93 if(!userID) {
94 throw new Error('Argument `userID` is required.');
95 }
96
97 if(!action) {
98 throw new Error('Argument `action` is required.');
99 }
100
101 return this._request({method: 'POST', path: `/users/${userID}/relationship`, postData: {action}}).then(this._parseJSON);
102 }
103
104 //////////////////////////
105 //// Media
106 //////////////////////////
107
108 getMediaInfoById(mediaID) {
109 if(!mediaID) {
110 throw new Error('Argument `mediaID` is required.');
111 }
112
113 return this._request({path: `/media/${mediaID}`}).then(this._parseJSON);
114 }
115
116 getMediaInfoByShortCode(shortCode) {
117 if(!shortCode) {
118 throw new Error('Argument `shortCode` is required.');
119 }
120
121 return this._request({path: `/media/shortcode/${shortCode}`}).then(this._parseJSON);
122 }
123
124 mediaSearch({lat = 0, lng = 0, distance = 10} = {}) {
125 return this._request({path: '/media/search', query: {lat, lng, distance}}).then(this._parseJSON);
126 }
127
128 //////////////////////////
129 //// Comments
130 //////////////////////////
131
132 getCommentsForMedia(mediaID) {
133 if(!mediaID) {
134 throw new Error('Argument `mediaID` is required.');
135 }
136
137 return this._request({path: `/media/${mediaID}/comments`}).then(this._parseJSON);
138 }
139
140 addCommentForMedia(mediaID, text) {
141 if(!mediaID) {
142 throw new Error('Argument `mediaID` is required.');
143 }
144
145 if(!text) {
146 throw new Error('Argument `text` is required.');
147 }
148
149 return this._request({method: 'POST', path: `/media/${mediaID}/comments`, postData: {text}}).then(this._parseJSON);
150 }
151
152 removeCommentForMedia(mediaID, commentId) {
153 if(!mediaID) {
154 throw new Error('Argument `mediaID` is required.');
155 }
156
157 if(!commentId) {
158 throw new Error('Argument `commentId` is required.');
159 }
160
161 return this._request({method: 'DELETE', path: `/media/${mediaID}/comments/${commentId}`}).then(this._parseJSON);
162 }
163
164 //////////////////////////
165 //// Likes
166 //////////////////////////
167
168 getLikesForMedia(mediaID) {
169 if(!mediaID) {
170 throw new Error('Argument `mediaID` is required.');
171 }
172
173 return this._request({path: `/media/${mediaID}/likes`}).then(this._parseJSON);
174 }
175
176 addLikeForMedia(mediaID) {
177 if(!mediaID) {
178 throw new Error('Argument `mediaID` is required.');
179 }
180
181 return this._request({method: 'POST', path: `/media/${mediaID}/likes`}).then(this._parseJSON);
182 }
183
184 removeLikeForMedia(mediaID) {
185 if(!mediaID) {
186 throw new Error('Argument `mediaID` is required.');
187 }
188
189 return this._request({method: 'DELETE', path: `/media/${mediaID}/likes`}).then(this._parseJSON);
190 }
191
192 //////////////////////////
193 //// Tags
194 //////////////////////////
195
196 getTagInfoByTagName(tagName) {
197 if(!tagName) {
198 throw new Error('Argument `tagName` is required.');
199 }
200
201 return this._request({path: `/tags/${tagName}`}).then(this._parseJSON);
202 }
203
204 getRecentMediaForTagName(tagName, {count = 10, min_tag_id = undefined, max_tag_id = undefined} = {}) {
205 if(!tagName) {
206 throw new Error('Argument `tagName` is required.');
207 }
208
209 return this._request({path: `/tags/${tagName}/media/recent`, query: {count, min_tag_id, max_tag_id}}).then(this._parseJSON);
210 }
211
212 tagsSearch(q = '') {
213 return this._request({path: '/tags/search', query: {q}}).then(this._parseJSON);
214 }
215
216 //////////////////////////
217 //// Locations
218 //////////////////////////
219
220 getLocationInfoByLocationId(locationId) {
221 if(!locationId) {
222 throw new Error('Argument `locationId` is required.');
223 }
224
225 return this._request({path: `/locations/${locationId}`}).then(this._parseJSON);
226 }
227
228 getRecentMediaForLocationId(locationId, {min_tag_id = undefined, max_tag_id = undefined} = {}) {
229 if(!locationId) {
230 throw new Error('Argument `locationId` is required.');
231 }
232
233 return this._request({path: `/locations/${locationId}/media/recent`, query: {min_tag_id, max_tag_id}}).then(this._parseJSON);
234 }
235
236 locationsSearch({
237 distance = 1000,
238 facebook_places_id = undefined,
239 foursquare_id = undefined,
240 lat = undefined,
241 lng = undefined,
242 foursquare_v2_id = undefined
243 } = {}) {
244
245 return this._request({
246 path: '/locations/search',
247 query: {
248 distance,
249 facebook_places_id,
250 foursquare_id,
251 lat,
252 lng,
253 foursquare_v2_id
254 }
255 }).then(this._parseJSON);
256 }
257
258 //////////////////////////
259 //// Embedding
260 //////////////////////////
261
262 getMediaJPGByShortCode(shortCode) {
263 if(!shortCode) {
264 throw new Error('Argument `shortCode` is required.');
265 }
266
267 return this._request({path: `/p/${shortCode}/media`}).then(this._getHeaderValue('Location'));
268 }
269
270 _getHeaderValue(headerName) {
271 return ({res} = {}) => {
272 return Promise.resolve(res.headers[headerName]);
273 };
274 }
275
276 _parseJSON({res, resData} = {}) {
277 console.log('_parseJSON called');
278 var resJSON = {};
279
280 if(res.statusCode == 204) {
281 return Promise.resolve({});
282 }
283
284 try {
285 resJSON = JSON.parse(resData);
286 } catch(err) {
287 logger.debug('_parseJSON: invalid response:', resData);
288 return Promise.reject(new Error('Invalid JSON response:' + resData));
289 }
290
291 logger.debug('_parseJSON: response: %:2j', resJSON);
292 return Promise.resolve(resJSON);
293 }
294
295 _request({method = 'GET', path = '/users/self', postData, query = {}} = {}) {
296 return new Promise((resolve, reject) => {
297 query.access_token = this.accessToken;
298 let contentType = 'application/json',
299 headers = {
300 Accept: contentType
301 },
302 requestOptions = {
303 hostname: this.instagramHost,
304 path: this.apiPath + path + '?' + querystring.stringify(query),
305 method
306 },
307 _postData;
308
309 if(postData) {
310 _postData = JSON.stringify(postData);
311 headers['Content-Type'] = 'application/json';
312 headers['Content-length'] = _postData.length;
313 logger.debug('_request: request with postData: %:2j', _postData);
314 }
315
316 requestOptions.headers = headers;
317 logger.debug('_request: request with params: %:2j', requestOptions);
318
319 var request = https.request(requestOptions, (res) => {
320 var resData = '';
321
322 res.on('data', (data) => {
323 resData += data;
324 });
325 res.on('end', () => {
326 logger.debug('_request: response statusCode:', res.statusCode);
327 resolve({res, resData});
328 });
329 }).on('error', reject);
330
331 if(postData) {
332 request.write(_postData);
333 }
334
335 request.end();
336 });
337 }
338}
339
340export default InstagramSDK;