@irfanshadikrishad/anilist 1.7.0 → 2.0.0-forbidden

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.
@@ -7,24 +7,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { Cipher } from "@irfanshadikrishad/cipher";
11
- import fs from "fs";
12
- import inquirer from "inquirer";
13
- import fetch from "node-fetch";
14
- import open from "open";
15
- import os from "os";
16
- import path from "path";
17
- import Spinner from "tiny-spinner";
18
- import { fetcher } from "./fetcher.js";
19
- import { AniDB, AniList, MyAnimeList } from "./lists.js";
20
- import { deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, saveTextActivityMutation, toggleFollowMutation, } from "./mutations.js";
21
- import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, } from "./queries.js";
22
- import { responsiveOutput } from "./truncate.js";
23
- import { aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from "./workers.js";
10
+ import { Cipher } from '@irfanshadikrishad/cipher';
11
+ import fs from 'fs';
12
+ import inquirer from 'inquirer';
13
+ import fetch from 'node-fetch';
14
+ import open from 'open';
15
+ import os from 'os';
16
+ import path from 'path';
17
+ import { exit } from 'process';
18
+ import Spinner from 'tiny-spinner';
19
+ import { fetcher } from './fetcher.js';
20
+ import { colorize } from './lib/colorize.js';
21
+ import { AniDB, AniList, MyAnimeList } from './lists.js';
22
+ import { deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, likeActivityMutation, saveTextActivityMutation, toggleFollowMutation, } from './mutations.js';
23
+ import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, followingActivitiesQuery, globalActivitiesQuery, specificUserActivitiesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from './queries.js';
24
+ import { responsiveOutput } from './truncate.js';
25
+ import { activityBy, aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from './workers.js';
24
26
  const home_dir = os.homedir();
25
- const save_path = path.join(home_dir, ".anilist_tok3n");
27
+ const save_path = path.join(home_dir, '.anilist_token');
26
28
  const spinner = new Spinner();
27
- const vigenere = new Cipher.Vigenere("anilist");
29
+ const vigenere = new Cipher.Vigenere('anilist');
28
30
  class Auth {
29
31
  /**
30
32
  * Get access-token from user
@@ -34,13 +36,13 @@ class Auth {
34
36
  try {
35
37
  const { token } = yield inquirer.prompt([
36
38
  {
37
- type: "password",
38
- name: "token",
39
- message: "Please enter your AniList access token:",
39
+ type: 'password',
40
+ name: 'token',
41
+ message: 'Please enter your AniList access token:',
40
42
  },
41
43
  ]);
42
44
  if (!token) {
43
- console.warn("\nNo token entered. Please try again.");
45
+ console.warn('\nNo token entered. Please try again.');
44
46
  return null;
45
47
  }
46
48
  return token;
@@ -55,10 +57,10 @@ class Auth {
55
57
  return __awaiter(this, void 0, void 0, function* () {
56
58
  try {
57
59
  if (!token) {
58
- console.warn("\nNo token provided. Nothing to store.");
60
+ console.warn('\nNo token provided. Nothing to store.');
59
61
  return;
60
62
  }
61
- fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding: "utf8" });
63
+ fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding: 'utf8' });
62
64
  }
63
65
  catch (error) {
64
66
  console.error(`\nError storing access token: ${error.message}`);
@@ -69,7 +71,7 @@ class Auth {
69
71
  return __awaiter(this, void 0, void 0, function* () {
70
72
  try {
71
73
  if (fs.existsSync(save_path)) {
72
- return vigenere.decrypt(fs.readFileSync(save_path, { encoding: "utf8" }));
74
+ return vigenere.decrypt(fs.readFileSync(save_path, { encoding: 'utf8' }));
73
75
  }
74
76
  else {
75
77
  return null;
@@ -84,18 +86,18 @@ class Auth {
84
86
  static Login(clientId, clientSecret) {
85
87
  return __awaiter(this, void 0, void 0, function* () {
86
88
  try {
87
- console.log("Starting AniList login...");
89
+ console.log('Starting AniList login...');
88
90
  const authUrl = `https://anilist.co/api/v2/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`;
89
- console.log("Opening browser for AniList login...");
91
+ console.log('Opening browser for AniList login...');
90
92
  open(authUrl);
91
93
  const authCode = yield Auth.GetAccessToken();
92
- const tokenResponse = yield fetch("https://anilist.co/api/v2/oauth/token", {
93
- method: "POST",
94
+ const tokenResponse = yield fetch('https://anilist.co/api/v2/oauth/token', {
95
+ method: 'POST',
94
96
  headers: {
95
- "Content-Type": "application/json",
97
+ 'Content-Type': 'application/json',
96
98
  },
97
99
  body: JSON.stringify({
98
- grant_type: "authorization_code",
100
+ grant_type: 'authorization_code',
99
101
  client_id: String(clientId),
100
102
  client_secret: clientSecret,
101
103
  redirect_uri: redirectUri,
@@ -114,7 +116,7 @@ class Auth {
114
116
  }
115
117
  }
116
118
  else {
117
- console.error("\nFailed to get access token:", token_Data);
119
+ console.error('\nFailed to get access token:', token_Data);
118
120
  }
119
121
  }
120
122
  catch (error) {
@@ -128,11 +130,11 @@ class Auth {
128
130
  try {
129
131
  if (yield Auth.isLoggedIn()) {
130
132
  const headers = {
131
- "Content-Type": "application/json",
132
- "Authorization": `Bearer ${yield Auth.RetriveAccessToken()}`,
133
+ 'Content-Type': 'application/json',
134
+ 'Authorization': `Bearer ${yield Auth.RetriveAccessToken()}`,
133
135
  };
134
136
  const request = yield fetch(aniListEndpoint, {
135
- method: "POST",
137
+ method: 'POST',
136
138
  headers: headers,
137
139
  body: JSON.stringify({ query: currentUserQuery }),
138
140
  });
@@ -185,7 +187,7 @@ Statistics (Manga):
185
187
  console.log(`\nRecent Activities:`);
186
188
  if (activities.length > 0) {
187
189
  activities.map(({ status, progress, media, createdAt }) => {
188
- responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
190
+ responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ''}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
189
191
  });
190
192
  }
191
193
  return user;
@@ -227,11 +229,11 @@ Statistics (Manga):
227
229
  console.log(`\nLogout successful. See you soon, ${username}.`);
228
230
  }
229
231
  catch (error) {
230
- console.error("\nFailed to remove the save file during logout:", error.message);
232
+ console.error('\nFailed to remove the save file during logout:', error.message);
231
233
  }
232
234
  }
233
235
  else {
234
- console.warn("\nNo active session found. You may already be logged out.");
236
+ console.warn('\nNo active session found. You may already be logged out.');
235
237
  }
236
238
  }
237
239
  catch (error) {
@@ -271,16 +273,16 @@ Statistics (Manga):
271
273
  }
272
274
  const { activityType } = yield inquirer.prompt([
273
275
  {
274
- type: "list",
275
- name: "activityType",
276
- message: "What type of activity you want to delete?",
276
+ type: 'list',
277
+ name: 'activityType',
278
+ message: 'What type of activity you want to delete?',
277
279
  choices: [
278
- { name: "All Activity", value: 0 },
279
- { name: "Text Activity", value: 1 },
280
- { name: "Media List Activity", value: 2 },
281
- { name: "Anime List Activity", value: 3 },
282
- { name: "Manga List Activity", value: 4 },
283
- { name: "Message Activity", value: 5 },
280
+ { name: 'All Activity', value: 0 },
281
+ { name: 'Text Activity', value: 1 },
282
+ { name: 'Media List Activity', value: 2 },
283
+ { name: 'Anime List Activity', value: 3 },
284
+ { name: 'Manga List Activity', value: 4 },
285
+ { name: 'Message Activity', value: 5 },
284
286
  ],
285
287
  },
286
288
  ]);
@@ -317,7 +319,7 @@ Statistics (Manga):
317
319
  const isDeleted = (_f = (_e = deleteResponse === null || deleteResponse === void 0 ? void 0 : deleteResponse.data) === null || _e === void 0 ? void 0 : _e.DeleteActivity) === null || _f === void 0 ? void 0 : _f.deleted;
318
320
  count++;
319
321
  totalCount++;
320
- console.log(`[${count}/${activities.length}/${totalCount}]\t${act === null || act === void 0 ? void 0 : act.id} ${isDeleted ? "✅" : "❌"}`);
322
+ console.log(`[${count}/${activities.length}/${totalCount}]\t${act === null || act === void 0 ? void 0 : act.id} ${isDeleted ? colorize.Green('✔') : colorize.Red('✘')}`);
321
323
  // Avoiding rate-limit
322
324
  yield new Promise((resolve) => setTimeout(resolve, 1100));
323
325
  }
@@ -353,9 +355,9 @@ Statistics (Manga):
353
355
  if (lists.length > 0) {
354
356
  const { selectedList } = yield inquirer.prompt([
355
357
  {
356
- type: "list",
357
- name: "selectedList",
358
- message: "Select an anime list:",
358
+ type: 'list',
359
+ name: 'selectedList',
360
+ message: 'Select an anime list:',
359
361
  choices: lists.map((list) => list.name),
360
362
  pageSize: 10,
361
363
  },
@@ -375,7 +377,7 @@ Statistics (Manga):
375
377
  }
376
378
  }
377
379
  else {
378
- console.log("No entries found.");
380
+ console.log('No entries found.');
379
381
  }
380
382
  }
381
383
  else {
@@ -394,7 +396,7 @@ Statistics (Manga):
394
396
  const response = yield fetcher(deleteMediaEntryMutation, { id: id });
395
397
  if (response === null || response === void 0 ? void 0 : response.data) {
396
398
  const deleted = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.DeleteMediaListEntry) === null || _b === void 0 ? void 0 : _b.deleted;
397
- console.log(`del ${title ? getTitle(title) : ""} ${deleted ? "✅" : "❌"}`);
399
+ console.log(`del ${title ? getTitle(title) : ''} ${deleted ? colorize.Green('✔') : colorize.Red('✘')}`);
398
400
  }
399
401
  else {
400
402
  console.log(`\nError deleting anime. ${(_c = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _c === void 0 ? void 0 : _c.message}`);
@@ -427,9 +429,9 @@ Statistics (Manga):
427
429
  if (lists.length > 0) {
428
430
  const { selectedList } = yield inquirer.prompt([
429
431
  {
430
- type: "list",
431
- name: "selectedList",
432
- message: "Select a manga list:",
432
+ type: 'list',
433
+ name: 'selectedList',
434
+ message: 'Select a manga list:',
433
435
  choices: lists.map((list) => list.name),
434
436
  pageSize: 10,
435
437
  },
@@ -449,7 +451,7 @@ Statistics (Manga):
449
451
  }
450
452
  }
451
453
  else {
452
- console.error("\nNo entries found.");
454
+ console.error('\nNo entries found.');
453
455
  }
454
456
  }
455
457
  else {
@@ -466,10 +468,10 @@ Statistics (Manga):
466
468
  var _a, _b, _c, _d;
467
469
  try {
468
470
  const response = yield fetcher(deleteMangaEntryMutation, { id });
469
- const statusMessage = title ? getTitle(title) : "";
471
+ const statusMessage = title ? getTitle(title) : '';
470
472
  if (response === null || response === void 0 ? void 0 : response.data) {
471
473
  const deleted = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.DeleteMediaListEntry) === null || _b === void 0 ? void 0 : _b.deleted;
472
- console.log(`del ${statusMessage} ${deleted ? "✅" : "❌"}`);
474
+ console.log(`del ${statusMessage} ${deleted ? colorize.Green('✔') : colorize.Red('✘')}`);
473
475
  }
474
476
  else {
475
477
  console.error(`Error deleting manga. ${(_d = (_c = response === null || response === void 0 ? void 0 : response.errors) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.message}`);
@@ -508,13 +510,13 @@ Statistics (Manga):
508
510
  try {
509
511
  const { source } = yield inquirer.prompt([
510
512
  {
511
- type: "list",
512
- name: "source",
513
- message: "Select a source:",
513
+ type: 'list',
514
+ name: 'source',
515
+ message: 'Select a source:',
514
516
  choices: [
515
- { name: "Exported JSON file.", value: 1 },
516
- { name: "MyAnimeList (XML)", value: 2 },
517
- { name: "AniDB (json-large)", value: 3 },
517
+ { name: 'Exported JSON file.', value: 1 },
518
+ { name: 'MyAnimeList (XML)', value: 2 },
519
+ { name: 'AniDB (json-large)', value: 3 },
518
520
  ],
519
521
  pageSize: 10,
520
522
  },
@@ -544,12 +546,12 @@ Statistics (Manga):
544
546
  try {
545
547
  const { source } = yield inquirer.prompt([
546
548
  {
547
- type: "list",
548
- name: "source",
549
- message: "Select a source:",
549
+ type: 'list',
550
+ name: 'source',
551
+ message: 'Select a source:',
550
552
  choices: [
551
- { name: "Exported JSON file.", value: 1 },
552
- { name: "MyAnimeList (XML)", value: 2 },
553
+ { name: 'Exported JSON file.', value: 1 },
554
+ { name: 'MyAnimeList (XML)', value: 2 },
553
555
  ],
554
556
  pageSize: 10,
555
557
  },
@@ -571,6 +573,342 @@ Statistics (Manga):
571
573
  }
572
574
  });
573
575
  }
576
+ static LikeFollowing() {
577
+ return __awaiter(this, void 0, void 0, function* () {
578
+ var _a, _b, _c, _d, _e, _f;
579
+ try {
580
+ let page = 1;
581
+ let hasMoreActivities = true;
582
+ let retryCount = 0;
583
+ const maxRetries = 5;
584
+ let likedCount = 0;
585
+ while (hasMoreActivities) {
586
+ const activities = yield fetcher(followingActivitiesQuery, {
587
+ page,
588
+ perPage: 50,
589
+ });
590
+ if (activities && ((_b = (_a = activities === null || activities === void 0 ? void 0 : activities.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.activities.length) > 0) {
591
+ spinner.success(`Got ${(_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities.length} activities..`);
592
+ retryCount = 0; // Reset retry count on successful fetch
593
+ const activiti = (_f = (_e = activities === null || activities === void 0 ? void 0 : activities.data) === null || _e === void 0 ? void 0 : _e.Page) === null || _f === void 0 ? void 0 : _f.activities;
594
+ for (let activ of activiti) {
595
+ if (!activ.isLiked && activ.id) {
596
+ try {
597
+ const like = yield fetcher(likeActivityMutation, {
598
+ activityId: activ.id,
599
+ });
600
+ if (like === null || like === void 0 ? void 0 : like.data) {
601
+ likedCount++;
602
+ }
603
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, likedCount)}`);
604
+ }
605
+ catch (error) {
606
+ console.error(`Activity possibly deleted. ${error.message}`);
607
+ }
608
+ }
609
+ else {
610
+ responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, likedCount)}`);
611
+ }
612
+ // avoiding rate-limit
613
+ yield new Promise((resolve) => {
614
+ setTimeout(resolve, 2000);
615
+ });
616
+ }
617
+ page++;
618
+ }
619
+ else {
620
+ if (retryCount < maxRetries) {
621
+ spinner.start('Getting activities...');
622
+ retryCount++;
623
+ spinner.update(`Empty activities returned. Retrying... (${retryCount}/${maxRetries})`);
624
+ yield new Promise((resolve) => setTimeout(resolve, 2000));
625
+ }
626
+ else {
627
+ spinner.error(`Probably the end of activities after ${maxRetries} retries.`);
628
+ hasMoreActivities = false;
629
+ }
630
+ }
631
+ }
632
+ }
633
+ catch (error) {
634
+ console.error(`\nError from likeFollowing. ${error.message}`);
635
+ }
636
+ });
637
+ }
638
+ static LikeGlobal() {
639
+ return __awaiter(this, void 0, void 0, function* () {
640
+ var _a, _b, _c, _d, _e, _f;
641
+ try {
642
+ let page = 1;
643
+ let hasMoreActivities = true;
644
+ let likedCount = 0;
645
+ spinner.start(`Getting global activities...`);
646
+ while (hasMoreActivities) {
647
+ const activities = yield fetcher(globalActivitiesQuery, {
648
+ page,
649
+ perPage: 50,
650
+ });
651
+ if (activities && ((_b = (_a = activities === null || activities === void 0 ? void 0 : activities.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.activities.length) > 0) {
652
+ const activiti = (_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities;
653
+ spinner.success(`Got ${activiti.length} activities...`);
654
+ for (let activ of activiti) {
655
+ if (!activ.isLiked && activ.id) {
656
+ try {
657
+ const like = yield fetcher(likeActivityMutation, {
658
+ activityId: activ.id,
659
+ });
660
+ // const ToggleLike = like?.data?.ToggleLike
661
+ likedCount++;
662
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, likedCount)}`);
663
+ }
664
+ catch (error) {
665
+ console.error(`Activity possibly deleted. ${error.message}`);
666
+ }
667
+ }
668
+ else {
669
+ responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, likedCount)}`);
670
+ }
671
+ // avoiding rate-limit
672
+ yield new Promise((resolve) => {
673
+ setTimeout(resolve, 1500);
674
+ });
675
+ }
676
+ page++;
677
+ }
678
+ else {
679
+ // No more activities to like
680
+ spinner.error(`Probably the end of activities. ${(_f = (_e = activities === null || activities === void 0 ? void 0 : activities.data) === null || _e === void 0 ? void 0 : _e.Page) === null || _f === void 0 ? void 0 : _f.activities}`);
681
+ hasMoreActivities = false;
682
+ }
683
+ }
684
+ }
685
+ catch (error) {
686
+ console.error(`\nError from likeFollowing. ${error.message}`);
687
+ }
688
+ });
689
+ }
690
+ static LikeSpecificUser() {
691
+ return __awaiter(this, void 0, void 0, function* () {
692
+ var _a, _b, _c, _d;
693
+ try {
694
+ const { username } = yield inquirer.prompt([
695
+ {
696
+ type: 'input',
697
+ name: 'username',
698
+ message: 'Username of the user:',
699
+ },
700
+ ]);
701
+ const { toLikeAmount } = yield inquirer.prompt([
702
+ {
703
+ type: 'number',
704
+ name: 'toLikeAmount',
705
+ message: 'Likes to give:',
706
+ },
707
+ ]);
708
+ const userDetails = yield fetcher(userQuery, { username: username });
709
+ spinner.start(`Getting activities by ${username}`);
710
+ if ((_b = (_a = userDetails === null || userDetails === void 0 ? void 0 : userDetails.data) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.id) {
711
+ let page = 1;
712
+ const perPage = 50;
713
+ const userId = userDetails.data.User.id;
714
+ let likedCount = 0;
715
+ while (likedCount < toLikeAmount) {
716
+ const activities = yield fetcher(specificUserActivitiesQuery, {
717
+ page,
718
+ perPage,
719
+ userId,
720
+ });
721
+ const activiti = (_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities;
722
+ if (!activiti || activiti.length === 0) {
723
+ spinner.error('No more activities found.');
724
+ break;
725
+ }
726
+ spinner.success(`Got ${activiti.length} activities...`);
727
+ for (let activ of activiti) {
728
+ if (!activ.isLiked && activ.id) {
729
+ try {
730
+ const like = yield fetcher(likeActivityMutation, {
731
+ activityId: activ.id,
732
+ });
733
+ likedCount++;
734
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, likedCount)}`);
735
+ if (likedCount >= toLikeAmount) {
736
+ spinner.success(`Finished liking ${likedCount} activities of ${username}.`);
737
+ return;
738
+ }
739
+ }
740
+ catch (error) {
741
+ console.error(`Activity possibly deleted. ${error.message}`);
742
+ }
743
+ }
744
+ else {
745
+ responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, likedCount)}`);
746
+ }
747
+ }
748
+ page += 1;
749
+ }
750
+ }
751
+ else {
752
+ spinner.error(`User ${username} does not exist.`);
753
+ exit(1);
754
+ }
755
+ }
756
+ catch (error) {
757
+ console.error(`\nError from LikeSpecificUser. ${error.message}`);
758
+ }
759
+ });
760
+ }
761
+ static LikeFollowingActivityV2(perPage) {
762
+ return __awaiter(this, void 0, void 0, function* () {
763
+ var _a, _b, _c, _d, _e;
764
+ try {
765
+ if (!(yield Auth.isLoggedIn())) {
766
+ console.error(`\nPlease log in to use this feature.`);
767
+ return;
768
+ }
769
+ const allFollowingUsers = [];
770
+ let hasNextPage = true;
771
+ let page = 1;
772
+ let liked = 0;
773
+ // ------------------------
774
+ // Fetch all following users
775
+ // ------------------------
776
+ spinner.start(`Gathering following information...`);
777
+ while (hasNextPage) {
778
+ spinner.update(`Fetched page ${page}...`);
779
+ const followingUsers = yield fetcher(userFollowingQuery, {
780
+ userId: yield Auth.MyUserId(),
781
+ page,
782
+ });
783
+ if (!((_b = (_a = followingUsers === null || followingUsers === void 0 ? void 0 : followingUsers.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.following)) {
784
+ console.error(`\nFailed to fetch following users.`);
785
+ return;
786
+ }
787
+ allFollowingUsers.push(...followingUsers.data.Page.following);
788
+ hasNextPage = followingUsers.data.Page.pageInfo.hasNextPage;
789
+ page++;
790
+ }
791
+ spinner.stop(`Got ${allFollowingUsers.length} following user.`);
792
+ // Extract the IDs of all following users
793
+ const followingUserIds = allFollowingUsers.map((user) => user.id);
794
+ // --------------------
795
+ // APPROXIMATE TIME
796
+ // --------------------
797
+ const totalActivities = followingUserIds.length * perPage;
798
+ const perActivityTimeInSec = 1;
799
+ const rateLimitTimeInSec = 60;
800
+ const batchSize = 29;
801
+ const batches = Math.floor(totalActivities / batchSize);
802
+ const remaining = totalActivities % batchSize;
803
+ const processingTime = batches * batchSize * perActivityTimeInSec +
804
+ remaining * perActivityTimeInSec;
805
+ const waitTime = (batches - 1) * rateLimitTimeInSec;
806
+ const totalWaitTimeInSec = processingTime + (batches > 0 ? waitTime : 0);
807
+ const hours = Math.floor(totalWaitTimeInSec / 3600);
808
+ const minutes = Math.floor((totalWaitTimeInSec % 3600) / 60);
809
+ const seconds = totalWaitTimeInSec % 60;
810
+ const time = `${String(hours).padStart(2, '0')}h ${String(minutes).padStart(2, '0')}m ${String(seconds).padStart(2, '0')}s`;
811
+ console.log(`\nTotal following: ${followingUserIds.length}\nApproximately ${totalActivities} to like.\nWill take around ${time}`);
812
+ // -------------------
813
+ // Traverse the array and
814
+ // fetch users' activities one by one
815
+ // -------------------
816
+ let userNumber = 0;
817
+ for (const userId of followingUserIds) {
818
+ userNumber++;
819
+ console.log(`\n[${userNumber}]\tID: ${userId}`);
820
+ // Fetch `perPage` activities for the current user
821
+ const activities = yield fetcher(specificUserActivitiesQuery, {
822
+ userId,
823
+ page: 1, // Always fetch from the first page
824
+ perPage,
825
+ });
826
+ if (!((_e = (_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities) === null || _e === void 0 ? void 0 : _e.length)) {
827
+ console.log(`[${userNumber}] No activities found for User ID: ${userId}`);
828
+ continue;
829
+ }
830
+ const activiti = activities.data.Page.activities;
831
+ for (let i = 0; i < activiti.length; i++) {
832
+ const activ = activiti[i];
833
+ if (!activ.isLiked && activ.id) {
834
+ try {
835
+ const like = yield fetcher(likeActivityMutation, {
836
+ activityId: activ.id,
837
+ });
838
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, i + 1)}`);
839
+ if (like === null || like === void 0 ? void 0 : like.data) {
840
+ liked++;
841
+ }
842
+ }
843
+ catch (error) {
844
+ console.error(`Activity possibly deleted. ${error.message}`);
845
+ }
846
+ }
847
+ else {
848
+ responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, i + 1)}`);
849
+ }
850
+ // Avoid rate-limiting
851
+ yield new Promise((resolve) => setTimeout(resolve, 1200));
852
+ }
853
+ }
854
+ console.log(`\n${colorize.Green('✔')} All ${liked} activities liked successfully.`);
855
+ }
856
+ catch (error) {
857
+ console.error(`\nError in LikeFollowingActivityV2: ${error.message}`);
858
+ }
859
+ });
860
+ }
861
+ static AutoLike() {
862
+ return __awaiter(this, void 0, void 0, function* () {
863
+ try {
864
+ if (!(yield Auth.isLoggedIn())) {
865
+ console.error(`\nPlease login to use this feature.`);
866
+ return;
867
+ }
868
+ const { activityType } = yield inquirer.prompt([
869
+ {
870
+ type: 'list',
871
+ name: 'activityType',
872
+ message: 'Select activity type:',
873
+ choices: [
874
+ { name: 'Following • v1', value: 1 },
875
+ { name: 'Following • v2', value: 2 },
876
+ { name: 'Global', value: 3 },
877
+ { name: 'Specific User', value: 4 },
878
+ ],
879
+ pageSize: 10,
880
+ },
881
+ ]);
882
+ switch (activityType) {
883
+ case 1:
884
+ yield this.LikeFollowing();
885
+ break;
886
+ case 2: {
887
+ const { count } = yield inquirer.prompt([
888
+ {
889
+ type: 'number',
890
+ name: 'count',
891
+ message: 'Likes to give:',
892
+ },
893
+ ]);
894
+ yield this.LikeFollowingActivityV2(count);
895
+ break;
896
+ }
897
+ case 3:
898
+ yield this.LikeGlobal();
899
+ break;
900
+ case 4:
901
+ yield this.LikeSpecificUser();
902
+ break;
903
+ default:
904
+ console.error(`\nInvalid choice. (${activityType})`);
905
+ }
906
+ }
907
+ catch (error) {
908
+ console.error(`\nError from autolike. ${error.message}`);
909
+ }
910
+ });
911
+ }
574
912
  }
575
913
  class Social {
576
914
  /**
@@ -584,7 +922,7 @@ class Social {
584
922
  let hasNextPage = true;
585
923
  let allFollowerUsers = [];
586
924
  let followedBack = 0;
587
- spinner.start("Fetching all the followers...");
925
+ spinner.start('Fetching all the followers...');
588
926
  while (hasNextPage) {
589
927
  const followerUsers = yield fetcher(userFollowersQuery, {
590
928
  userId: yield Auth.MyUserId(),
@@ -597,7 +935,7 @@ class Social {
597
935
  allFollowerUsers.push(...(((_h = (_g = followerUsers === null || followerUsers === void 0 ? void 0 : followerUsers.data) === null || _g === void 0 ? void 0 : _g.Page) === null || _h === void 0 ? void 0 : _h.followers) || []));
598
936
  pager++;
599
937
  }
600
- spinner.stop("Fetched all the followers. Starting follow back.");
938
+ spinner.stop('Fetched all the followers. Starting follow back.');
601
939
  // Filter users that do no follow me
602
940
  const notFollowing = allFollowerUsers
603
941
  .filter(({ isFollowing }) => !isFollowing)
@@ -613,10 +951,7 @@ class Social {
613
951
  for (let nf of notFollowing) {
614
952
  try {
615
953
  const follow = yield fetcher(toggleFollowMutation, { userId: nf.id });
616
- console.log(`${String(`[${nf.id}]`).padEnd(maxIdLength)}` +
617
- `\t${String(`[${(_k = (_j = follow === null || follow === void 0 ? void 0 : follow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]`).padEnd(maxNameLength)}` +
618
- `\t${((_m = (_l = follow === null || follow === void 0 ? void 0 : follow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? "✅" : "🈵"}`);
619
- // Count the followed back users
954
+ console.log(`${String(`[${nf.id}]`).padEnd(maxIdLength)}\t${String(`[${(_k = (_j = follow === null || follow === void 0 ? void 0 : follow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]`).padEnd(maxNameLength)}\t${((_m = (_l = follow === null || follow === void 0 ? void 0 : follow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? colorize.Green('✔') : colorize.Red('✘')}`); // Count the followed back users
620
955
  if ((_p = (_o = follow === null || follow === void 0 ? void 0 : follow.data) === null || _o === void 0 ? void 0 : _o.ToggleFollow) === null || _p === void 0 ? void 0 : _p.id) {
621
956
  followedBack++;
622
957
  }
@@ -625,7 +960,7 @@ class Social {
625
960
  console.log(`automate_follow_toggle_follow: ${error.message}`);
626
961
  }
627
962
  }
628
- console.log(`\n Followed back ${followedBack} users.`);
963
+ console.log(`\n${colorize.Green('✔')} Followed back ${followedBack} users.`);
629
964
  }
630
965
  catch (error) {
631
966
  console.log(`\nautomate_follow ${error.message}`);
@@ -643,7 +978,7 @@ class Social {
643
978
  let hasNextPage = true;
644
979
  let allFollowingUsers = [];
645
980
  let unfollowedUsers = 0;
646
- spinner.start("Fetching all following users...");
981
+ spinner.start('Fetching all following users...');
647
982
  while (hasNextPage) {
648
983
  const followingUsers = yield fetcher(userFollowingQuery, {
649
984
  userId: yield Auth.MyUserId(),
@@ -674,7 +1009,7 @@ class Social {
674
1009
  const unfollow = yield fetcher(toggleFollowMutation, {
675
1010
  userId: nfm.id,
676
1011
  });
677
- console.log(`[${nfm.id}]\t[${(_k = (_j = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]\t${((_m = (_l = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? "✅" : "🈵"}`);
1012
+ console.log(`[${nfm.id}]\t[${(_k = (_j = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]\t${((_m = (_l = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? colorize.Green('✔') : colorize.Red('✘')}`);
678
1013
  // Count the unfollowed users
679
1014
  if ((_p = (_o = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _o === void 0 ? void 0 : _o.ToggleFollow) === null || _p === void 0 ? void 0 : _p.id) {
680
1015
  unfollowedUsers++;
@@ -684,7 +1019,7 @@ class Social {
684
1019
  console.log(`unfollow_toggle_follow. ${error.message}`);
685
1020
  }
686
1021
  }
687
- console.log(`\nTotal Unfollowed: ${unfollowedUsers} of ${nfmCount} users.`);
1022
+ console.log(`\n${colorize.Green('✔')} Total Unfollowed: ${unfollowedUsers} of ${nfmCount} users.`);
688
1023
  }
689
1024
  catch (error) {
690
1025
  console.error(`\nautomate_unfollow: ${error.message}`);