instauto 7.2.2 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +66 -36
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -165,27 +165,45 @@ const Instauto = async (db, browser, options) => {
165
165
  return new Date().getTime() - followedUserEntry.time < dontUnfollowUntilTimeElapsed;
166
166
  }
167
167
 
168
- async function safeGoto(url) {
169
- logger.log(`Goto ${url}`);
170
- const response = await page.goto(url);
171
- await sleep(1000);
172
- const status = response.status();
168
+ async function gotoWithRetry(url) {
169
+ for (let attempt = 0; ; attempt += 1) {
170
+ logger.log(`Goto ${url}`);
171
+ const response = await page.goto(url);
172
+ await sleep(1000);
173
+ const status = response.status();
174
+
175
+ // https://www.reddit.com/r/Instagram/comments/kwrt0s/error_560/
176
+ // https://github.com/mifi/instauto/issues/60
177
+ if (![560, 429].includes(status) || attempt > 3) return status;
178
+
179
+ logger.info(`Got ${status} - Retrying request later...`);
180
+ if (status === 429) logger.warn('429 Too Many Requests could mean that Instagram suspects you\'re using a bot. You could try to use the Instagram Mobile app from the same IP for a few days first');
181
+ await sleep((attempt + 1) * 30 * 60 * 1000);
182
+ }
183
+ }
184
+
185
+ async function safeGotoUser(url, checkPageForUsername) {
186
+ const status = await gotoWithRetry(url);
173
187
  if (status === 200) {
188
+ if (checkPageForUsername != null) {
189
+ // some pages return 200 but nothing there (I think deleted accounts)
190
+ // https://github.com/mifi/SimpleInstaBot/issues/48
191
+ // example: https://www.instagram.com/victorialarson__/
192
+ // so we check if the page has the user's name on it
193
+ return page.evaluate((username) => window.find(username), checkPageForUsername);
194
+ }
174
195
  return true;
175
- } else if (status === 404) {
196
+ }
197
+ if (status === 404) {
176
198
  logger.log('User not found');
177
199
  return false;
178
- } else if (status === 429) {
179
- logger.error('Got 429 Too Many Requests, waiting...');
180
- await sleep(60 * 60 * 1000);
181
- throw new Error('Aborted operation due to too many requests'); // TODO retry instead
182
200
  }
183
- throw new Error(`Navigate to user returned status ${response.status()}`);
201
+ throw new Error(`Navigate to user failed with status ${status}`);
184
202
  }
185
203
 
186
204
  async function navigateToUser(username) {
187
205
  logger.log(`Navigating to user ${username}`);
188
- return safeGoto(`${instagramBaseUrl}/${encodeURIComponent(username)}`);
206
+ return safeGotoUser(`${instagramBaseUrl}/${encodeURIComponent(username)}`, username);
189
207
  }
190
208
 
191
209
  async function getPageJson() {
@@ -197,7 +215,7 @@ const Instauto = async (db, browser, options) => {
197
215
  if (graphqlUserMissing) {
198
216
  // https://stackoverflow.com/questions/37593025/instagram-api-get-the-userid
199
217
  // https://stackoverflow.com/questions/17373886/how-can-i-get-a-users-media-from-instagram-without-authenticating-as-a-user
200
- const found = await safeGoto(`${instagramBaseUrl}/${encodeURIComponent(username)}?__a=1`);
218
+ const found = await safeGotoUser(`${instagramBaseUrl}/${encodeURIComponent(username)}?__a=1`);
201
219
  if (!found) throw new Error('User not found');
202
220
 
203
221
  const json = await getPageJson();
@@ -320,7 +338,7 @@ const Instauto = async (db, browser, options) => {
320
338
  await addPrevFollowedUser(entry);
321
339
 
322
340
  if (!elementHandle2) {
323
- logger.log('Button did not change state - Sleeping');
341
+ logger.log('Button did not change state - Sleeping 1 min');
324
342
  await sleep(60000);
325
343
  throw new Error('Button did not change state');
326
344
  }
@@ -791,6 +809,10 @@ const Instauto = async (db, browser, options) => {
791
809
  }
792
810
 
793
811
  page = await browser.newPage();
812
+
813
+ // https://github.com/mifi/SimpleInstaBot/issues/118#issuecomment-1067883091
814
+ await page.setExtraHTTPHeaders({ 'Accept-Language': 'en' });
815
+
794
816
  if (randomizeUserAgent) {
795
817
  const userAgentGenerated = new UserAgent({ deviceCategory: 'desktop' });
796
818
  await page.setUserAgent(userAgentGenerated.toString());
@@ -802,27 +824,19 @@ const Instauto = async (db, browser, options) => {
802
824
  const goHome = async () => page.goto(`${instagramBaseUrl}/?hl=en`);
803
825
 
804
826
  // https://github.com/mifi/SimpleInstaBot/issues/28
805
- async function setLang(short, long) {
827
+ async function setLang(short, long, assumeLoggedIn = false) {
806
828
  logger.log(`Setting language to ${long} (${short})`);
807
829
 
808
- // This doesn't seem to always work, hence why it's just a fallback now
809
- async function fallbackSetLang() {
810
- await goHome();
811
- await sleep(1000);
812
-
813
- await page.setCookie({
814
- name: 'ig_lang',
815
- value: short,
816
- path: '/',
817
- });
818
- await sleep(1000);
819
- await goHome();
820
- await sleep(3000);
821
- }
822
-
823
830
  try {
824
831
  await sleep(1000);
825
- await goHome();
832
+
833
+ // when logged in, we need to go to account in order to be able to check/set language
834
+ // (need to see the footer)
835
+ if (assumeLoggedIn) {
836
+ await page.goto(`${instagramBaseUrl}/accounts/edit/`);
837
+ } else {
838
+ await goHome();
839
+ }
826
840
  await sleep(3000);
827
841
  const elementHandles = await page.$x(`//select[//option[@value='${short}' and text()='${long}']]`);
828
842
  if (elementHandles.length < 1) throw new Error('Language selector not found');
@@ -841,6 +855,10 @@ const Instauto = async (db, browser, options) => {
841
855
 
842
856
  if (alreadyEnglish) {
843
857
  logger.log('Already English language');
858
+ if (!assumeLoggedIn) {
859
+ await goHome(); // because we were on the settings page
860
+ await sleep(1000);
861
+ }
844
862
  return;
845
863
  }
846
864
 
@@ -850,12 +868,23 @@ const Instauto = async (db, browser, options) => {
850
868
  await sleep(1000);
851
869
  } catch (err) {
852
870
  logger.error('Failed to set language, trying fallback (cookie)', err);
853
- await fallbackSetLang();
871
+ // This doesn't seem to always work, hence why it's just a fallback now
872
+ await goHome();
873
+ await sleep(1000);
874
+
875
+ await page.setCookie({
876
+ name: 'ig_lang',
877
+ value: short,
878
+ path: '/',
879
+ });
880
+ await sleep(1000);
881
+ await goHome();
882
+ await sleep(3000);
854
883
  }
855
884
  }
856
885
 
857
- const setEnglishLang = async () => setLang('en', 'English');
858
- // const setEnglishLang = async () => setLang('de', 'Deutsch');
886
+ const setEnglishLang = async (assumeLoggedIn) => setLang('en', 'English', assumeLoggedIn);
887
+ // const setEnglishLang = async (assumeLoggedIn) => setLang('de', 'Deutsch', assumeLoggedIn);
859
888
 
860
889
  async function tryPressButton(elementHandles, name, sleepMs = 3000) {
861
890
  try {
@@ -869,7 +898,7 @@ const Instauto = async (db, browser, options) => {
869
898
  }
870
899
  }
871
900
 
872
- await setEnglishLang();
901
+ await setEnglishLang(false);
873
902
 
874
903
  await tryPressButton(await page.$x('//button[contains(text(), "Accept")]'), 'Accept cookies dialog');
875
904
  await tryPressButton(await page.$x('//button[contains(text(), "Only allow essential cookies")]'), 'Accept cookies dialog 2 button 1', 10000);
@@ -924,7 +953,8 @@ const Instauto = async (db, browser, options) => {
924
953
  }
925
954
 
926
955
  // In case language gets reset after logging in
927
- await setEnglishLang();
956
+ // https://github.com/mifi/SimpleInstaBot/issues/118
957
+ await setEnglishLang(true);
928
958
 
929
959
  // Mobile version https://github.com/mifi/SimpleInstaBot/issues/7
930
960
  await tryPressButton(await page.$x('//button[contains(text(), "Save Info")]'), 'Login info dialog: Save Info');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instauto",
3
- "version": "7.2.2",
3
+ "version": "7.2.3",
4
4
  "description": "Instagram automation library written in Node.js",
5
5
  "main": "index.js",
6
6
  "scripts": {