From a11b10df3b5775ac4fffff75a7d932e24b1874c3 Mon Sep 17 00:00:00 2001 From: Timo Lins Date: Fri, 16 Mar 2018 21:16:06 +0100 Subject: [PATCH 1/3] Added `getFollowers()` & `getFollowings()` --- README.md | 22 ++++++++++++++++++++++ lib/index.js | 39 +++++++++++++++++++++++++++++++++++++++ test/index.js | 18 ++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/README.md b/README.md index cde43fc..82b2098 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ const credentialsFile = joinPath(__dirname, 'credentials.json') * [.logout()](#logout) * [.getHome()](#gethome) * [.getUserByUsername({ username })](#getuserbyusernameparams) + * [.getFollowers({ userId, first, after })](#getfollowers) + * [.getFollowings({ userId, first, after })](#getfollowings) * [.getActivity()](#getactivity) * [.getProfile()](#getprofile) * [.updateProfile({ name, email, username, phoneNumber, gender, biography, website, similarAccountSuggestions })](#updateprofileparams) @@ -170,6 +172,26 @@ const me = await client.getUserByUsername({ username: client.credentials.usernam - `params` - `username`: The username of the profile +### getFollowers(params) +```js +const followers = await client.getFollowers({ userId: '1284161654' }) +``` +> Get followers for given userId. Be aware that the response gets slightly altered for easier usage. +- `params` + - `userId`: The user id + - `first`: Amount of followers to request. Default is `20` + - `after`: Optional `end_cursor` (`String`) for pagination. + +### getFollowings(params) +```js +const followings = await client.getFollowings({ userId: '1284161654' }) +``` +> Get followings for given userId. Be aware that the response gets slightly altered for easier usage. +- `params` + - `userId`: The user id + - `first`: Amount of followings to request. Default is `20` + - `after`: Optional `end_cursor` (`String`) for pagination. + ### getActivity() ```js const activity = await client.getActivity() diff --git a/lib/index.js b/lib/index.js index b1c7958..f3ad901 100644 --- a/lib/index.js +++ b/lib/index.js @@ -96,6 +96,45 @@ class Instagram { return this.request(`/${username}/?__a=1`).then(data => data.graphql.user) } + _getFollowData({ fieldName, queryHash, variables }) { + return this.request('/graphql/query/', { + qs: { + query_hash: queryHash, + variables: JSON.stringify(variables) + } + }) + .then(data => data.data.user[fieldName]) + .then(({ count, page_info, edges }) => ({ + count, + page_info, + data: edges.map(edge => edge.node) + })) + } + + getFollowers({ userId, first = 20, after }) { + return this._getFollowData({ + fieldName: 'edge_followed_by', + queryHash: '37479f2b8209594dde7facb0d904896a', + variables: { + id: userId, + first, + after + } + }) + } + + getFollowings({ userId, first = 20, after }) { + return this._getFollowData({ + fieldName: 'edge_follow', + queryHash: '58712303d941c6855d4e888c5f0cd22f', + variables: { + id: userId, + first, + after + } + }) + } + getActivity() { return this.request('/accounts/activity/?__a=1').then( data => data.graphql.user diff --git a/test/index.js b/test/index.js index b72d52e..c27a8fe 100644 --- a/test/index.js +++ b/test/index.js @@ -107,6 +107,24 @@ test('getUserByUsername', async t => { t.is(user.username, users.Instagram.username) }) +test('getFollowers', async t => { + const followers = await client.getFollowers({ + userId: users.Instagram.id + }) + + t.true('count' in followers) + t.true(Array.isArray(followers.data)) +}) + +test('getFollowings', async t => { + const followings = await client.getFollowings({ + userId: users.Instagram.id + }) + + t.true('count' in followings) + t.true(Array.isArray(followings.data)) +}) + test('addComment', async t => { const { status, id, text } = await client.addComment({ mediaId: media.GraphImage.id, From 944a42a14380589b4de98da29df22b4cb33277e4 Mon Sep 17 00:00:00 2001 From: Timo Lins Date: Fri, 16 Mar 2018 21:22:01 +0100 Subject: [PATCH 2/3] Fixed README links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 82b2098..6592f13 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,8 @@ const credentialsFile = joinPath(__dirname, 'credentials.json') * [.logout()](#logout) * [.getHome()](#gethome) * [.getUserByUsername({ username })](#getuserbyusernameparams) - * [.getFollowers({ userId, first, after })](#getfollowers) - * [.getFollowings({ userId, first, after })](#getfollowings) + * [.getFollowers({ userId, first, after })](#getfollowersparams) + * [.getFollowings({ userId, first, after })](#getfollowingsparams) * [.getActivity()](#getactivity) * [.getProfile()](#getprofile) * [.updateProfile({ name, email, username, phoneNumber, gender, biography, website, similarAccountSuggestions })](#updateprofileparams) From 091bacd47ba8c33c65c369063f2588d68b9e1601 Mon Sep 17 00:00:00 2001 From: Timo Lins Date: Sat, 17 Mar 2018 18:46:00 +0100 Subject: [PATCH 3/3] Added challenge endpoints --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ lib/index.js | 46 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6592f13..bc56e86 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,10 @@ const credentialsFile = joinPath(__dirname, 'credentials.json') * [.getMediaByShortcode({ shortcode })](#getmediabyshortcodeparams) * [.addComment({ mediaId, text })](#addcommentparams) * [.deleteComment({ mediaId, commentId })](#deletecommentparams) + * [.getChallenge({ challengeUrl })](#getchallengeparams) + * [.updateChallenge({ challengeUrl, choice, securityCode })](#updatechallengeparams) + * [.resetChallenge({ challengeUrl })](#resetchallengeparams) + * [.replayChallenge({ challengeUrl })](#replaychallengeparams) * [.approve({ userId })](#approveparams) * [.ignore({ userId })](#ignoreparams) * [.follow({ userId })](#followparams) @@ -310,6 +314,43 @@ await client.deleteComment({ mediaId: '1442533050805297981', commentId: '1784890 - `mediaId`: The media id - `commentId`: The comment id +### getChallenge(params) +```js +await client.getChallenge({ challengeUrl: '/challenge/1284161654/a1B2c3d4E6/' }) +``` +> Get information about a challenge. +- `params` + - `challengeUrl`: A `String` with a challenge path + +### updateChallenge(params) +```js +const challengeUrl = '/challenge/1284161654/a1B2c3d4E6/' + +await client.updateChallenge({ challengeUrl, choice: 0 }) +await client.updateChallenge({ challengeUrl, securityCode: 123456 }) +``` +> Request or submit a verifcation code for the given challenge. +- `params` + - `challengeUrl`: A `String` with a challenge path + - `choice`: `Number` `0` for phone and `1` for email. Default is `` + - `securityCode`: `Number` the received verifcation code for the challenge. Default is `` + +### resetChallenge(params) +```js +await client.resetChallenge({ challengeUrl: '/challenge/1284161654/a1B2c3d4E6/' }) +``` +> Reset a challenge to start over again. +- `params` + - `challengeUrl`: A `String` with a challenge path + +### replayChallenge(params) +```js +await client.replayChallenge({ challengeUrl: '/challenge/1284161654/a1B2c3d4E6/' }) +``` +> Request a new verifcation message. +- `params` + - `challengeUrl`: A `String` with a challenge path + ### approve(params) ```js await client.approve({ userId: '1284161654' }) diff --git a/lib/index.js b/lib/index.js index f3ad901..f48a470 100644 --- a/lib/index.js +++ b/lib/index.js @@ -56,10 +56,14 @@ class Instagram { .then(res => res.find(cookie => cookie.key === 'csrftoken')) .then(res => res.toJSON()) + // Provide CSRFToken for login or challenge request + this.request = this.request.defaults({ + headers: { 'X-CSRFToken': value } + }) + // Login const cookies = await this.request .post('/accounts/login/ajax/', { - headers: { 'X-CSRFToken': value }, resolveWithFullResponse: true, form: { username, password } }) @@ -241,6 +245,46 @@ class Instagram { return this.request.post(`/web/comments/${mediaId}/delete/${commentId}/`) } + getChallenge({ challengeUrl }) { + return this.request(`${challengeUrl}?__a=1`) + } + + _navigateChallenge({ challengeUrl, endpoint, form }) { + const url = endpoint + ? challengeUrl.replace('/challenge/', `/challenge/${endpoint}/`) + : challengeUrl + return this.request.post(url, { + headers: { + Referer: `${baseUrl}${challengeUrl}` + }, + form + }) + } + + updateChallenge({ challengeUrl, choice, securityCode }) { + return this._navigateChallenge({ + challengeUrl, + form: { + choice, + security_code: securityCode + } + }) + } + + resetChallenge({ challengeUrl }) { + return this._navigateChallenge({ + challengeUrl, + endpoint: 'reset' + }) + } + + replayChallenge({ challengeUrl }) { + return this._navigateChallenge({ + challengeUrl, + endpoint: 'replay' + }) + } + approve({ userId }) { return this.request.post(`/web/friendships/${userId}/approve/`) }